1 /*
 2  * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
 3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 4  *
 5  * This code is free software; you can redistribute it and/or modify it
 6  * under the terms of the GNU General Public License version 2 only, as
 7  * published by the Free Software Foundation.  Oracle designates this
 8  * particular file as subject to the "Classpath" exception as provided
 9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package com.sun.tools.javac.comp;
27 
28 import com.sun.tools.javac.code.Symbol;
29 import com.sun.tools.javac.code.Symbol.VarSymbol;
30 import com.sun.tools.javac.tree.JCTree;
31 import com.sun.tools.javac.tree.TreeScanner;
32 import com.sun.tools.javac.util.List;
33 
34 import java.util.HashSet;
35 import java.util.LinkedHashSet;
36 import java.util.SequencedSet;
37 import java.util.Set;
38 
39 import static com.sun.tools.javac.code.Kinds.Kind.MTH;
40 import static com.sun.tools.javac.code.Kinds.Kind.VAR;
41 
42 /**
43  * A visitor which collects the set of local variables "captured" by a given tree.
44  */
45 public class CaptureScanner extends TreeScanner {
46 
47     /**
48      * The tree under analysis.
49      */
50     private final JCTree tree;
51 
52     /**
53      * The set of local variable declarations encountered in the tree under analysis.
54      */
55     private final Set<Symbol.VarSymbol> seenVars = new HashSet<>();
56 
57     /**
58      * The set of captured local variables accessed from within the tree under analysis.
59      */
60     private final SequencedSet<VarSymbol> fvs = new LinkedHashSet<>();
61 
62     public CaptureScanner(JCTree ownerTree) {
63         this.tree = ownerTree;
64     }
65 
66     @Override
67     public void visitIdent(JCTree.JCIdent tree) {
68         Symbol sym = tree.sym;
69         if (sym.kind == VAR && sym.owner.kind == MTH) {
70             Symbol.VarSymbol vsym = (Symbol.VarSymbol) sym;
71             if (vsym.getConstValue() == null && !seenVars.contains(vsym)) {
72                 addFreeVar(vsym);
73             }
74         }
75     }
76 
77     /**
78      * Add free variable to fvs list unless it is already there.
79      */
80     protected void addFreeVar(Symbol.VarSymbol v) {
81         fvs.add(v);
82     }
83 
84     @Override
85     public void visitVarDef(JCTree.JCVariableDecl tree) {
86         if (tree.sym.owner.kind == MTH) {
87             seenVars.add(tree.sym);
88         }
89         super.visitVarDef(tree);
90     }
91 
92     /**
93      * Obtains the list of captured local variables in the tree under analysis.
94      */
95     public List<Symbol.VarSymbol> analyzeCaptures() {
96         scan(tree);
97         return List.from(fvs);
98     }
99 }