diff --git a/src/checkers/inference/DefaultSlotManager.java b/src/checkers/inference/DefaultSlotManager.java index a18e4a37..8083741b 100644 --- a/src/checkers/inference/DefaultSlotManager.java +++ b/src/checkers/inference/DefaultSlotManager.java @@ -1,8 +1,10 @@ package checkers.inference; import checkers.inference.util.SlotDefaultTypeResolver; +import com.sun.source.tree.ClassTree; import com.sun.source.tree.CompilationUnitTree; import com.sun.source.tree.Tree; +import com.sun.source.util.TreePath; import com.sun.tools.javac.code.Symbol; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; @@ -11,6 +13,7 @@ import org.checkerframework.javacutil.AnnotationBuilder; import org.checkerframework.javacutil.AnnotationUtils; import org.checkerframework.javacutil.BugInCF; +import org.checkerframework.javacutil.TreeUtils; import org.checkerframework.javacutil.TypeKindUtils; import org.checkerframework.javacutil.TypesUtils; @@ -202,6 +205,25 @@ public int compare(Class o1, Class o return set; } + @Override + public void setTopLevelClass(ClassTree classTree) { + // If the top level has changed, we refresh our cache with the new scope. + defaultAnnotationsCache.clear(); + + Map defaultTypes = SlotDefaultTypeResolver.resolve( + classTree, + InferenceMain.getInstance().getRealTypeFactory() + ); + + // find default types in the current hierarchy and save them to the cache + for (Map.Entry entry : defaultTypes.entrySet()) { + defaultAnnotationsCache.put( + entry.getKey(), + entry.getValue().getAnnotationInHierarchy(this.realTop) + ); + } + } + /** * Returns the next unique variable id. These id's are monotonically increasing. * @return the next variable id to be used in VariableCreation @@ -347,25 +369,6 @@ public int getNumberOfSlots() { return nextId - 1; } - @Override - public void setRoot(CompilationUnitTree compilationUnit) { - this.defaultAnnotationsCache.clear(); - - BaseAnnotatedTypeFactory realTypeFactory = InferenceMain.getInstance().getRealTypeFactory(); - Map defaultTypes = SlotDefaultTypeResolver.resolve( - compilationUnit, - realTypeFactory - ); - - for (Map.Entry entry : defaultTypes.entrySet()) { - // find default types in the current hierarchy and save them to the cache - this.defaultAnnotationsCache.put( - entry.getKey(), - entry.getValue().getAnnotationInHierarchy(this.realTop) - ); - } - } - @Override public SourceVariableSlot createSourceVariableSlot(AnnotationLocation location, TypeMirror type) { AnnotationMirror defaultAnnotation = null; @@ -424,13 +427,20 @@ public SourceVariableSlot createSourceVariableSlot(AnnotationLocation location, throw new BugInCF("Unable to find default annotation for location " + location); } - AnnotationMirror realAnnotation = null; - if (tree != null) { - realAnnotation = this.defaultAnnotationsCache.get(tree); - if (realAnnotation == null) { - // If its default type can't be found in the cache, we can - // fallback to the simplest method. - realAnnotation = realTypeFactory.getAnnotatedType(tree).getAnnotationInHierarchy(this.realTop); + AnnotationMirror realAnnotation = defaultAnnotationsCache.get(tree); + if (tree != null && realAnnotation == null) { + // If its default type can't be found in the cache, we can + // fallback to the simplest method. + // TODO: If the tree is not under the current top-level tree + // that's being processed, the type factory may crash due + // to lack of information. We may want to investigate if + // this issue ever happens. + if (TreeUtils.isTypeTree(tree)) { + realAnnotation = realTypeFactory.getAnnotatedTypeFromTypeTree(tree) + .getAnnotationInHierarchy(this.realTop); + } else { + realAnnotation = realTypeFactory.getAnnotatedType(tree) + .getAnnotationInHierarchy(this.realTop); } } return realAnnotation; diff --git a/src/checkers/inference/InferenceAnnotatedTypeFactory.java b/src/checkers/inference/InferenceAnnotatedTypeFactory.java index ce401e92..3d62157e 100644 --- a/src/checkers/inference/InferenceAnnotatedTypeFactory.java +++ b/src/checkers/inference/InferenceAnnotatedTypeFactory.java @@ -2,6 +2,7 @@ import checkers.inference.model.ConstantSlot; import checkers.inference.model.Slot; +import com.sun.source.util.TreePath; import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; import org.checkerframework.framework.flow.CFAbstractAnalysis; import org.checkerframework.framework.flow.CFAnalysis; @@ -536,7 +537,6 @@ public void addComputedTypeAnnotations(final Element element, final AnnotatedTyp treeAnnotator.visit(declaration, type); } else { bytecodeTypeAnnotator.annotate(element, type); - } } } @@ -550,7 +550,6 @@ public void setRoot(final CompilationUnitTree root) { compilationUnitsHandled += 1; this.realTypeFactory.setRoot( root ); this.variableAnnotator.clearTreeInfo(); - this.slotManager.setRoot(root); super.setRoot(root); } diff --git a/src/checkers/inference/InferenceChecker.java b/src/checkers/inference/InferenceChecker.java index 3c71add3..b5bb5641 100644 --- a/src/checkers/inference/InferenceChecker.java +++ b/src/checkers/inference/InferenceChecker.java @@ -1,7 +1,5 @@ package checkers.inference; -import java.util.Properties; - import org.checkerframework.common.basetype.BaseTypeChecker; import org.checkerframework.common.basetype.BaseTypeVisitor; @@ -23,13 +21,4 @@ public void initChecker() { protected BaseTypeVisitor createSourceVisitor() { return null; } - - @Override - public Properties getMessagesProperties() { - // Add the messages.properties file defined in the same location as - // InferenceChecker - Properties messages = super.getMessagesProperties(); - messages.putAll(getProperties(this.getClass(), MSGS_FILE, true)); - return messages; - } } diff --git a/src/checkers/inference/InferenceVisitor.java b/src/checkers/inference/InferenceVisitor.java index 07218b0f..df07527f 100644 --- a/src/checkers/inference/InferenceVisitor.java +++ b/src/checkers/inference/InferenceVisitor.java @@ -1,5 +1,7 @@ package checkers.inference; +import com.sun.source.tree.ClassTree; +import com.sun.source.util.TreePath; import org.checkerframework.checker.compilermsgs.qual.CompilerMessageKey; import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; import org.checkerframework.common.basetype.BaseTypeVisitor; @@ -61,7 +63,7 @@ * That is, the methods from BaseTypeVisiotr should be migrated here and InferenceVisitor * should replace it in the Visitor hierarchy. */ -// TODO(Zhiping): new logics from BaseTypeVisiotr should be migrated here +// TODO(Zhiping): new logics from BaseTypeVisitor should be migrated here public class InferenceVisitor extends BaseTypeVisitor { @@ -90,6 +92,15 @@ protected Factory createTypeFactory() { return (Factory)((BaseInferrableChecker)checker).getTypeFactory(); } + @Override + public void visit(TreePath path) { + if (infer) { + final SlotManager slotManager = InferenceMain.getInstance().getSlotManager(); + slotManager.setTopLevelClass((ClassTree) path.getLeaf()); + } + super.visit(path); + } + public void doesNotContain(AnnotatedTypeMirror ty, AnnotationMirror mod, String msgkey, Tree node) { doesNotContain(ty, new AnnotationMirror[] {mod}, msgkey, node); } diff --git a/src/checkers/inference/SlotManager.java b/src/checkers/inference/SlotManager.java index 37cea000..4f8b6da7 100644 --- a/src/checkers/inference/SlotManager.java +++ b/src/checkers/inference/SlotManager.java @@ -1,6 +1,7 @@ package checkers.inference; import checkers.inference.model.LubVariableSlot; +import com.sun.source.tree.ClassTree; import com.sun.source.tree.CompilationUnitTree; import org.checkerframework.framework.type.AnnotatedTypeMirror; @@ -221,10 +222,13 @@ ArithmeticVariableSlot createArithmeticVariableSlot( List getConstantSlots(); /** - * Informs this manager that we are working on a new file, so - * it can preprocess and cache useful information. + * This method informs slot manager of the current top level class tree that's being type processed. + * Slot manager can then preprocess this information by clearing caches, resolving slot default + * types, etc. * - * @param compilationUnit the current compilation tree + * Note that trees that are not within this tree may be missing some information + * (in the JCTree implementation), and this is because they are either not fully + * initialized or being garbage-recycled. */ - void setRoot(CompilationUnitTree compilationUnit); + void setTopLevelClass(ClassTree classTree); } diff --git a/src/checkers/inference/util/SlotDefaultTypeResolver.java b/src/checkers/inference/util/SlotDefaultTypeResolver.java index cc3367c2..2f081931 100644 --- a/src/checkers/inference/util/SlotDefaultTypeResolver.java +++ b/src/checkers/inference/util/SlotDefaultTypeResolver.java @@ -3,7 +3,6 @@ import com.sun.source.tree.AnnotatedTypeTree; import com.sun.source.tree.ArrayTypeTree; import com.sun.source.tree.ClassTree; -import com.sun.source.tree.CompilationUnitTree; import com.sun.source.tree.ParameterizedTypeTree; import com.sun.source.tree.PrimitiveTypeTree; import com.sun.source.tree.Tree; @@ -38,11 +37,11 @@ public class SlotDefaultTypeResolver { public static Map resolve( - CompilationUnitTree root, + ClassTree classTree, BaseAnnotatedTypeFactory realTypeFactory ) { DefaultTypeFinder finder = new DefaultTypeFinder(realTypeFactory); - finder.scan(root, null); + finder.scan(classTree, null); return finder.defaultTypes; } @@ -89,6 +88,9 @@ private AnnotatedTypeMirror getDefaultTypeFor(Tree tree) { @Override public Void visitClass(ClassTree tree, Void unused) { + // stores the default type of the class tree + getDefaultTypeFor(tree); + Tree ext = tree.getExtendsClause(); if (ext != null) { defaultTypes.put(ext, realTypeFactory.getTypeOfExtendsImplements(ext));