Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid reading type info from trees that are not being processed #385

Merged
merged 13 commits into from
Mar 1, 2022
62 changes: 36 additions & 26 deletions src/checkers/inference/DefaultSlotManager.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -202,6 +205,25 @@ public int compare(Class<? extends Annotation> o1, Class<? extends Annotation> 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<Tree, AnnotatedTypeMirror> defaultTypes = SlotDefaultTypeResolver.resolve(
classTree,
InferenceMain.getInstance().getRealTypeFactory()
);

// find default types in the current hierarchy and save them to the cache
for (Map.Entry<Tree, AnnotatedTypeMirror> 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
Expand Down Expand Up @@ -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<Tree, AnnotatedTypeMirror> defaultTypes = SlotDefaultTypeResolver.resolve(
compilationUnit,
realTypeFactory
);

for (Map.Entry<Tree, AnnotatedTypeMirror> 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;
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 1 addition & 2 deletions src/checkers/inference/InferenceAnnotatedTypeFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -536,7 +537,6 @@ public void addComputedTypeAnnotations(final Element element, final AnnotatedTyp
treeAnnotator.visit(declaration, type);
} else {
bytecodeTypeAnnotator.annotate(element, type);

}
}
}
Expand All @@ -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);
}

Expand Down
11 changes: 0 additions & 11 deletions src/checkers/inference/InferenceChecker.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package checkers.inference;

import java.util.Properties;

import org.checkerframework.common.basetype.BaseTypeChecker;
import org.checkerframework.common.basetype.BaseTypeVisitor;

Expand All @@ -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;
}
}
13 changes: 12 additions & 1 deletion src/checkers/inference/InferenceVisitor.java
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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<Checker extends InferenceChecker,
Factory extends BaseAnnotatedTypeFactory>
extends BaseTypeVisitor<Factory> {
Expand Down Expand Up @@ -90,6 +92,15 @@ protected Factory createTypeFactory() {
return (Factory)((BaseInferrableChecker)checker).getTypeFactory();
}

@Override
public void visit(TreePath path) {
Copy link
Author

@zcai1 zcai1 Feb 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Documentation from its super class:

Entry point for a type processor: the TreePath leaf is a top-level type tree within root.

And this is why I choose to call slotManager.setTopLevelClass from here.

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);
}
Expand Down
12 changes: 8 additions & 4 deletions src/checkers/inference/SlotManager.java
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -221,10 +222,13 @@ ArithmeticVariableSlot createArithmeticVariableSlot(
List<ConstantSlot> 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);
}
8 changes: 5 additions & 3 deletions src/checkers/inference/util/SlotDefaultTypeResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -38,11 +37,11 @@
public class SlotDefaultTypeResolver {

public static Map<Tree, AnnotatedTypeMirror> resolve(
CompilationUnitTree root,
ClassTree classTree,
BaseAnnotatedTypeFactory realTypeFactory
) {
DefaultTypeFinder finder = new DefaultTypeFinder(realTypeFactory);
finder.scan(root, null);
finder.scan(classTree, null);

return finder.defaultTypes;
}
Expand Down Expand Up @@ -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));
Expand Down