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 }