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
71 changes: 40 additions & 31 deletions src/checkers/inference/DefaultSlotManager.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
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;
import org.checkerframework.framework.type.AnnotatedTypeFactory;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.javacutil.AnnotationBuilder;
import org.checkerframework.javacutil.AnnotationUtils;
import org.checkerframework.javacutil.BugInCF;
import org.checkerframework.javacutil.TypeKindUtils;
import org.checkerframework.javacutil.TypesUtils;
import org.checkerframework.javacutil.*;
wmdietl marked this conversation as resolved.
Show resolved Hide resolved

import java.lang.annotation.Annotation;
import java.util.ArrayList;
Expand Down Expand Up @@ -347,25 +345,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 +403,43 @@ 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);
if (!defaultAnnotationsCache.containsKey(tree)) {
// If cache misses, we check if the top level class has changed.
ClassTree topLevelClass = InferenceMain.getInstance().getVisitor().getCurrentTopLevelClass();
zcai1 marked this conversation as resolved.
Show resolved Hide resolved

if (!defaultAnnotationsCache.containsKey(topLevelClass)) {
// If the top level has changed, we refresh our cache with the new scope.
defaultAnnotationsCache.clear();

Map<Tree, AnnotatedTypeMirror> defaultTypes = SlotDefaultTypeResolver.resolve(
topLevelClass,
realTypeFactory
);

// 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)
);
}
}
}

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
9 changes: 2 additions & 7 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 All @@ -26,11 +27,7 @@
import org.checkerframework.framework.util.AnnotationMirrorSet;
import org.checkerframework.framework.util.defaults.QualifierDefaults;
import org.checkerframework.framework.util.dependenttypes.DependentTypesHelper;
import org.checkerframework.javacutil.AnnotationBuilder;
import org.checkerframework.javacutil.BugInCF;
import org.checkerframework.javacutil.ElementUtils;
import org.checkerframework.javacutil.Pair;
import org.checkerframework.javacutil.TreeUtils;
import org.checkerframework.javacutil.*;
zcai1 marked this conversation as resolved.
Show resolved Hide resolved

import java.lang.annotation.Annotation;
import java.util.ArrayList;
Expand Down Expand Up @@ -536,7 +533,6 @@ public void addComputedTypeAnnotations(final Element element, final AnnotatedTyp
treeAnnotator.visit(declaration, type);
} else {
bytecodeTypeAnnotator.annotate(element, type);

}
}
}
Expand All @@ -550,7 +546,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
27 changes: 27 additions & 0 deletions src/checkers/inference/InferenceChecker.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,32 @@

import java.util.Properties;

import com.sun.source.tree.ClassTree;
import com.sun.source.util.TreePath;
import org.checkerframework.common.basetype.BaseTypeChecker;
import org.checkerframework.common.basetype.BaseTypeVisitor;

import javax.lang.model.element.TypeElement;

public class InferenceChecker extends BaseTypeChecker {

/**
* This field stores current top level class tree that's being type processed.
*
* 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.
*/
private ClassTree currentTopLevelClass;

@Override
public void initChecker() {
InferenceMain.getInstance().recordInferenceCheckerInstance(this);
// Needed for error messages and reporting.
super.initChecker();
// Overrides visitor created by initChecker
this.visitor = InferenceMain.getInstance().getVisitor();
this.currentTopLevelClass = null;
}

/**
Expand All @@ -32,4 +46,17 @@ public Properties getMessagesProperties() {
messages.putAll(getProperties(this.getClass(), MSGS_FILE, true));
return messages;
}

@Override
public void typeProcess(TypeElement element, TreePath treePath) {
// As the entry point for type processing, each time we will receive
// one fully-analyzed class directly under a compilation unit tree.
// Please check the documentation in AbstractTypeProcessor for more details.
this.currentTopLevelClass = (ClassTree) treePath.getLeaf();
super.typeProcess(element, treePath);
}

public ClassTree getCurrentTopLevelClass() {
return currentTopLevelClass;
}
}
5 changes: 5 additions & 0 deletions src/checkers/inference/InferenceVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import com.sun.source.tree.Tree;
import com.sun.source.tree.Tree.Kind;
import com.sun.source.tree.VariableTree;
import com.sun.source.tree.ClassTree;

import org.plumelib.util.ArraysPlume;

Expand Down Expand Up @@ -90,6 +91,10 @@ protected Factory createTypeFactory() {
return (Factory)((BaseInferrableChecker)checker).getTypeFactory();
}

public ClassTree getCurrentTopLevelClass() {
return ((InferenceChecker) checker).getCurrentTopLevelClass();
}

public void doesNotContain(AnnotatedTypeMirror ty, AnnotationMirror mod, String msgkey, Tree node) {
doesNotContain(ty, new AnnotationMirror[] {mod}, msgkey, node);
}
Expand Down
8 changes: 0 additions & 8 deletions src/checkers/inference/SlotManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -219,12 +219,4 @@ ArithmeticVariableSlot createArithmeticVariableSlot(
List<VariableSlot> getVariableSlots();

List<ConstantSlot> getConstantSlots();

/**
* Informs this manager that we are working on a new file, so
* it can preprocess and cache useful information.
*
* @param compilationUnit the current compilation tree
*/
void setRoot(CompilationUnitTree compilationUnit);
}
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