Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.checker.signature.qual.ClassGetName;
import org.checkerframework.dataflow.cfg.visualize.CFGVisualizer;
import org.checkerframework.framework.qual.AnnotatedFor;
import org.checkerframework.framework.qual.SubtypeOf;
import org.checkerframework.framework.source.SourceChecker;
import org.checkerframework.framework.type.AnnotatedTypeFactory;
Expand All @@ -13,6 +14,7 @@
import org.checkerframework.javacutil.AbstractTypeProcessor;
import org.checkerframework.javacutil.AnnotationProvider;
import org.checkerframework.javacutil.BugInCF;
import org.checkerframework.javacutil.ElementUtils;
import org.checkerframework.javacutil.TypeSystemError;
import org.checkerframework.javacutil.UserError;
import org.plumelib.util.CollectionsPlume;
Expand All @@ -22,10 +24,13 @@
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.Set;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.PackageElement;

/**
* An abstract {@link SourceChecker} that provides a simple {@link
Expand Down Expand Up @@ -69,6 +74,13 @@
*/
public abstract class BaseTypeChecker extends SourceChecker {

/**
* A mapping from an element to whether it is in an {@code @AnnotatedFor} scope for this checker
* or an upstream checker.
*/
private final IdentityHashMap<Element, Boolean> elementAnnotatedForThisCheckerOrUpstreamCache =
new IdentityHashMap<>();

/** An array containing just {@code BaseTypeChecker.class}. */
protected static Class<?>[] baseTypeCheckerClassArray = new Class<?>[] {BaseTypeChecker.class};

Expand Down Expand Up @@ -315,26 +327,39 @@ public BaseTypeChecker getUltimateParentChecker() {
}
}

/**
* The implementation of this method resides in AnnotatedTypeFactory (atf), see {@link
* AnnotatedTypeFactory#isElementAnnotatedForThisCheckerOrUpstreamChecker(Element)} We want to
* implement it here to avoid duplication and call
* atypeFactory.getChecker().isElementAnnotatedForThisCheckerOrUpstreamChecker(elt) in
* QualifierDefaults, but implement it here causes type-system error. The reason is the
* implementation requires an atf to call {@link AnnotatedTypeFactory#getDeclAnnotation(Element,
* Class)}to get the relavent {@code @AnnotatedFor} annotation on the element. However, the
* method is called during the initialization of the atf when applying qualifier defaults. At
* that time, the atf and the visitor are not fully initialized, so calling getTypeFactory()
* will result in a type-system error. The initialization logic is as follows: 1. Create the
* checker. 2. Create the visitor, and the visitor's constructor initializes the atf. 3. During
* postInit() of the atf, the qualifier defaults are applied, which need to call
* isElementAnnotatedForThisCheckerOrUpstreamChecker().
*
* @param elt the source code element to check, or null
* @return true if the element is annotated for this checker or an upstream checker
*/
@Override
protected boolean isElementAnnotatedForThisCheckerOrUpstreamChecker(Element elt) {
return getTypeFactory().isElementAnnotatedForThisCheckerOrUpstreamChecker(elt);
public boolean isElementAnnotatedForThisCheckerOrUpstreamChecker(@Nullable Element elt) {
if (elt == null) {
throw new BugInCF(
"Call of BaseTypeChecker.isElementAnnotatedForThisCheckerOrUpstreamChecker with null");
}

if (elementAnnotatedForThisCheckerOrUpstreamCache.containsKey(elt)) {
return elementAnnotatedForThisCheckerOrUpstreamCache.get(elt);
}

AnnotatedTypeFactory atypeFactory = getTypeFactory();
AnnotationMirror annotatedFor = atypeFactory.getDeclAnnotation(elt, AnnotatedFor.class);
boolean elementAnnotatedForThisChecker =
annotatedFor != null
&& atypeFactory.doesAnnotatedForApplyToThisChecker(annotatedFor);

if (!elementAnnotatedForThisChecker) {
Element parent;
if (elt.getKind() == ElementKind.PACKAGE) {
parent =
ElementUtils.parentPackage(
(PackageElement) elt, atypeFactory.getElementUtils());
} else {
parent = elt.getEnclosingElement();
}

if (parent != null && isElementAnnotatedForThisCheckerOrUpstreamChecker(parent)) {
elementAnnotatedForThisChecker = true;
}
}

elementAnnotatedForThisCheckerOrUpstreamCache.put(elt, elementAnnotatedForThisChecker);
return elementAnnotatedForThisChecker;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ public AnnotationProvider getAnnotationProvider() {
}

@Override
protected boolean isElementAnnotatedForThisCheckerOrUpstreamChecker(Element elt) {
public boolean isElementAnnotatedForThisCheckerOrUpstreamChecker(Element elt) {
throw new BugInCF("Unexpected call to determine whether this checker is annotated");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ public AnnotationProvider getAnnotationProvider() {
}

@Override
protected boolean isElementAnnotatedForThisCheckerOrUpstreamChecker(Element elt) {
public boolean isElementAnnotatedForThisCheckerOrUpstreamChecker(Element elt) {
throw new BugInCF("Unexpected call to determine whether this checker is annotated");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ private void init(ProcessingEnvironment env, @Nullable @BinaryName String checke
new SourceChecker() {

@Override
protected boolean isElementAnnotatedForThisCheckerOrUpstreamChecker(
public boolean isElementAnnotatedForThisCheckerOrUpstreamChecker(
Element elt) {
throw new BugInCF(
"Unexpected call to determine whether this checker is annotated");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ protected final Set<Class<? extends SourceChecker>> getImmediateSubcheckerClasse
* org.checkerframework.checker.initialization.InitializationChecker#getUpstreamCheckerNames()}.
*/
@Override
protected boolean isElementAnnotatedForThisCheckerOrUpstreamChecker(Element elt) {
public boolean isElementAnnotatedForThisCheckerOrUpstreamChecker(Element elt) {
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2999,7 +2999,7 @@ protected boolean messageKeyMatches(
* @param elt the source code element to check, or null
* @return true if the element is annotated for this checker or an upstream checker
*/
protected abstract boolean isElementAnnotatedForThisCheckerOrUpstreamChecker(Element elt);
public abstract boolean isElementAnnotatedForThisCheckerOrUpstreamChecker(Element elt);

/**
* Returns a modifiable set of lower-case strings that are prefixes for SuppressWarnings
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -536,9 +536,6 @@ void checkRep(String aliasName) {
/** Mapping from a Tree to its TreePath. Shared between all instances. */
private final TreePathCacher treePathCache;

/** A mapping of Element &rarr; Whether or not that element is AnnotatedFor this type system. */
private final IdentityHashMap<Element, Boolean> elementAnnotatedFors = new IdentityHashMap<>();

/** Whether to ignore type arguments from raw types. */
public final boolean ignoreRawTypeArguments;

Expand Down Expand Up @@ -4100,6 +4097,18 @@ protected void parseAnnotationFiles() {
ajavaTypes.parseAjavaFiles();
}

/**
* Returns true if this type factory is currently parsing stub files or ajava files. While this
* is true, annotation-file-backed lookup may observe partially loaded annotation-file data.
*
* @return true if stub files or ajava files are currently being parsed
*/
public boolean isParsingAnnotationFiles() {
return stubTypes.isParsing()
|| ajavaTypes.isParsing()
|| (currentFileAjavaTypes != null && currentFileAjavaTypes.isParsing());
}

/**
* Returns all of the declaration annotations whose name equals the passed annotation class (or
* is an alias for it) including annotations:
Expand Down Expand Up @@ -6051,49 +6060,6 @@ public boolean doesAnnotatedForApplyToThisChecker(AnnotationMirror annotatedForA
return false;
}

/**
* Return true if the element has an {@code @AnnotatedFor} annotation, for this checker or an
* upstream checker that called this one.
*
* @param elt the source code element to check, or null
* @return true if the element is annotated for this checker or an upstream checker
*/
public boolean isElementAnnotatedForThisCheckerOrUpstreamChecker(@Nullable Element elt) {
boolean elementAnnotatedForThisChecker = false;

if (elt == null) {
throw new BugInCF(
"Call of AnnotatedTypeFactory.isElementAnnotatedForThisCheckerOrUpstreamChecker with null");
}

if (elementAnnotatedFors.containsKey(elt)) {
return elementAnnotatedFors.get(elt);
}

AnnotationMirror annotatedFor = getDeclAnnotation(elt, AnnotatedFor.class);

if (annotatedFor != null) {
elementAnnotatedForThisChecker = doesAnnotatedForApplyToThisChecker(annotatedFor);
}

if (!elementAnnotatedForThisChecker) {
Element parent;
if (elt.getKind() == ElementKind.PACKAGE) {
parent = ElementUtils.parentPackage((PackageElement) elt, elements);
} else {
parent = elt.getEnclosingElement();
}

if (parent != null && isElementAnnotatedForThisCheckerOrUpstreamChecker(parent)) {
elementAnnotatedForThisChecker = true;
}
}

elementAnnotatedFors.put(elt, elementAnnotatedForThisChecker);

return elementAnnotatedForThisChecker;
}

/**
* Get the {@code expression} field/element of the given contract annotation.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -748,6 +748,10 @@ public boolean applyConservativeDefaults(Element annotationScope) {
return false;
}

if (atypeFactory.isParsingAnnotationFiles()) {
return false;
}

// TODO: I would expect this:
// atypeFactory.isFromByteCode(annotationScope)) {
// to work instead of the
Expand All @@ -761,8 +765,9 @@ public boolean applyConservativeDefaults(Element annotationScope) {
&& !isFromStubFile;
if (isBytecode) {
return useConservativeDefaultsBytecode
&& !atypeFactory.isElementAnnotatedForThisCheckerOrUpstreamChecker(
annotationScope);
&& !atypeFactory
.getChecker()
.isElementAnnotatedForThisCheckerOrUpstreamChecker(annotationScope);
} else if (isFromStubFile) {
// TODO: Types in stub files not annotated for a particular checker should be
// treated as unchecked bytecode. For now, all types in stub files are treated as
Expand All @@ -771,7 +776,9 @@ public boolean applyConservativeDefaults(Element annotationScope) {
// be treated like unchecked code except for methods in the scope of an @AnnotatedFor.
return false;
} else if (useConservativeDefaultsSource) {
return !atypeFactory.isElementAnnotatedForThisCheckerOrUpstreamChecker(annotationScope);
return !atypeFactory
.getChecker()
.isElementAnnotatedForThisCheckerOrUpstreamChecker(annotationScope);
}
return false;
}
Expand Down
Loading