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 
100     public boolean isVarSeen(VarSymbol s) {
101         return seenVars.contains(s);
102     }
103 }