src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/dependencies/DependencyScanner.java

Print this page
rev 2819 : imported patch my-classpath-deps-00

*** 21,84 **** * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.tools.sjavac.comp.dependencies; ! import java.util.HashSet; import java.util.Set; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Symbol.ClassSymbol; import com.sun.tools.javac.code.Symbol.PackageSymbol; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.TypeTag; import com.sun.tools.javac.tree.JCTree.JCFieldAccess; import com.sun.tools.javac.tree.JCTree.JCIdent; import com.sun.tools.javac.tree.TreeScanner; class DependencyScanner extends TreeScanner { ! public final Set<Dependency> dependencies = new HashSet<>(); private boolean isValidDependency(Type t) { if (t == null || t.isPrimitiveOrVoid() || t.isErroneous()) return false; TypeTag tag = t.getTag(); return tag != TypeTag.PACKAGE && tag != TypeTag.METHOD && tag != TypeTag.ARRAY && tag != TypeTag.TYPEVAR; } @Override public void visitIdent(JCIdent tree) { if (isValidDependency(tree.type)) ! dependencies.add(new TypeAndSupertypesDependency(tree.type.tsym)); super.visitIdent(tree); } @Override public void visitSelect(JCFieldAccess tree) { if (tree.getIdentifier().contentEquals("*")) { Symbol sym = tree.selected instanceof JCIdent ? ((JCIdent) tree.selected).sym : ((JCFieldAccess) tree.selected).sym; if (sym instanceof ClassSymbol) { ! ClassSymbol clsSym = (ClassSymbol) sym; ! dependencies.add(new TypeAndSupertypesDependency(clsSym.type.tsym)); } else { ! dependencies.add(new PackageDependency((PackageSymbol) sym)); } ! } else if (tree.type != null && tree.type.hasTag(TypeTag.METHOD)) { // Method call? Depend on the result (even though we never access it elsewhere) Type retType = tree.type.getReturnType(); if (isValidDependency(retType)) ! dependencies.add(new TypeAndSupertypesDependency(retType.tsym)); } else if (isValidDependency(tree.type)) { ! dependencies.add(new TypeAndSupertypesDependency(tree.type.tsym)); } super.visitSelect(tree); } ! public Set<Dependency> getResult() { ! return dependencies; } } --- 21,185 ---- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.tools.sjavac.comp.dependencies; ! import java.util.Collections; ! import java.util.HashMap; import java.util.HashSet; + import java.util.Map; import java.util.Set; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Symbol.ClassSymbol; import com.sun.tools.javac.code.Symbol.PackageSymbol; + import com.sun.tools.javac.code.Symtab; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.TypeTag; + import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCFieldAccess; import com.sun.tools.javac.tree.JCTree.JCIdent; + import com.sun.tools.javac.tree.JCTree.JCImport; + import com.sun.tools.javac.tree.JCTree.JCPackageDecl; import com.sun.tools.javac.tree.TreeScanner; + import com.sun.tools.javac.util.Assert; + import com.sun.tools.javac.util.Context; + import com.sun.tools.sjavac.Util; class DependencyScanner extends TreeScanner { ! private final ClassSymbol OBJECT_SYM; ! private String currentClass = null; ! ! public final Map<String, Set<ClassSymbol>> dependencies = new HashMap<>(); ! public final Map<String, Set<PackageSymbol>> lazyImports = new HashMap<>(); ! ! // Keep track of imported classes, since they should be reported as dependency of any subsequent class decls. (This may change when moving to CompilationUnits). ! private final Set<ClassSymbol> typesImported = new HashSet<>(); ! private final Set<PackageSymbol> lazyImportedPkgs = new HashSet<>(); ! ! public DependencyScanner(Context context) { ! OBJECT_SYM = (ClassSymbol) Symtab.instance(context).objectType.tsym; ! } private boolean isValidDependency(Type t) { if (t == null || t.isPrimitiveOrVoid() || t.isErroneous()) return false; + if (!(t.tsym instanceof ClassSymbol)) + return false; TypeTag tag = t.getTag(); return tag != TypeTag.PACKAGE && tag != TypeTag.METHOD && tag != TypeTag.ARRAY && tag != TypeTag.TYPEVAR; } @Override + public void visitClassDef(JCClassDecl tree) { + // Skip anonymous classes for now. (Not sure if non-top level classes + // are interesting at this point) + if (tree.sym == null) + return; + + String prevClass = currentClass; + currentClass = tree.sym.flatname.toString(); + // Make sure the currentClass depends on the imported stuff. (This may go away when moving to CompilationUnits.) + typesImported.forEach(this::addDep); + lazyImports.put(currentClass, lazyImportedPkgs); + + // Make sure current class depends on Object if no extends expression is provided + if (tree.extending == null) + addDep(OBJECT_SYM); + else + addAllDeps(allSupertypes((ClassSymbol) tree.extending.type.tsym)); + super.visitClassDef(tree); + currentClass = prevClass; + } + + @Override + public void visitPackageDef(JCPackageDecl tree) { + // Ignore identifiers found in the package declaration. + //super.visitPackageDef(tree); + } + + @Override public void visitIdent(JCIdent tree) { if (isValidDependency(tree.type)) ! addDep((ClassSymbol) tree.type.tsym); super.visitIdent(tree); } @Override + public void visitImport(JCImport inport) { + TreeScanner importVisitor = new TreeScanner() { + @Override public void visitSelect(JCFieldAccess tree) { if (tree.getIdentifier().contentEquals("*")) { Symbol sym = tree.selected instanceof JCIdent ? ((JCIdent) tree.selected).sym : ((JCFieldAccess) tree.selected).sym; if (sym instanceof ClassSymbol) { ! typesImported.add((ClassSymbol) sym); ! } else if (sym instanceof PackageSymbol) { ! lazyImports.merge(currentClass, Collections.singleton((PackageSymbol) sym), Util::union); } else { ! Assert.error("Unknown import symbol: " + sym); } ! } else { ! // If this is a static import, the sym is null (why?) so ! // overapproximate by going up one level. ! if (inport.isStatic()) ! tree = ((JCFieldAccess) tree.selected); ! typesImported.add((ClassSymbol) tree.sym); ! } ! } ! }; ! inport.accept(importVisitor); ! ! // Avoid further visitSelect etc since we have no currentClass. ! // super.visitImport(tree); ! } ! ! @Override ! public void visitSelect(JCFieldAccess tree) { ! ! // This is not entirely safe. @MyAnno(SomeClass.class) public class C {} should depend on SomeClass.class ! if (currentClass == null) ! return; ! ! if (tree.type != null && tree.type.hasTag(TypeTag.METHOD)) { // Method call? Depend on the result (even though we never access it elsewhere) Type retType = tree.type.getReturnType(); if (isValidDependency(retType)) ! addDep((ClassSymbol) retType.tsym); } else if (isValidDependency(tree.type)) { ! ClassSymbol cs = (ClassSymbol) tree.type.tsym; ! addDep(cs); ! addAllDeps(allSupertypes(cs)); } super.visitSelect(tree); } ! private Set<ClassSymbol> allSupertypes(ClassSymbol cs) { ! if (cs == null) ! return Collections.emptySet(); ! Set<ClassSymbol> result = new HashSet<>(); ! result.add(cs); ! if (cs instanceof ClassSymbol) { ! result.addAll(allSupertypes((ClassSymbol) cs.getSuperclass().tsym)); ! for (Type it : cs.getInterfaces()) ! result.addAll(allSupertypes((ClassSymbol) it.tsym)); ! } ! return result; ! } ! ! private void addDep(ClassSymbol tsym) { ! if (currentClass == null) ! throw new RuntimeException("currentClass == null"); ! if (tsym == null) ! throw new RuntimeException("sym == null"); ! dependencies.merge(currentClass, Collections.singleton(tsym), Util::union); } + + private void addAllDeps(Set<ClassSymbol> tsyms) { + dependencies.merge(currentClass, tsyms, Util::union); + } + }