blob: 0b84a0a2186169f53fbcbb84a1a57f75fed9fcec [file] [log] [blame]
package org.checkerframework.common.aliasing;
import com.sun.source.tree.NewArrayTree;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Set;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.util.Elements;
import org.checkerframework.common.aliasing.qual.LeakedToResult;
import org.checkerframework.common.aliasing.qual.MaybeAliased;
import org.checkerframework.common.aliasing.qual.MaybeLeaked;
import org.checkerframework.common.aliasing.qual.NonLeaked;
import org.checkerframework.common.aliasing.qual.Unique;
import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory;
import org.checkerframework.common.basetype.BaseTypeChecker;
import org.checkerframework.framework.flow.CFAbstractAnalysis;
import org.checkerframework.framework.flow.CFStore;
import org.checkerframework.framework.flow.CFTransfer;
import org.checkerframework.framework.flow.CFValue;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.type.NoElementQualifierHierarchy;
import org.checkerframework.framework.type.QualifierHierarchy;
import org.checkerframework.framework.type.treeannotator.ListTreeAnnotator;
import org.checkerframework.framework.type.treeannotator.TreeAnnotator;
import org.checkerframework.javacutil.AnnotationBuilder;
/** Annotated type factory for the Aliasing Checker. */
public class AliasingAnnotatedTypeFactory extends BaseAnnotatedTypeFactory {
/** Aliasing annotations. */
/** The @{@link MaybeAliased} annotation. */
protected final AnnotationMirror MAYBE_ALIASED =
AnnotationBuilder.fromClass(elements, MaybeAliased.class);
/** The @{@link NonLeaked} annotation. */
protected final AnnotationMirror NON_LEAKED =
AnnotationBuilder.fromClass(elements, NonLeaked.class);
/** The @{@link Unique} annotation. */
protected final AnnotationMirror UNIQUE = AnnotationBuilder.fromClass(elements, Unique.class);
/** The @{@link MaybeLeaked} annotation. */
protected final AnnotationMirror MAYBE_LEAKED =
AnnotationBuilder.fromClass(elements, MaybeLeaked.class);
/** Create the type factory. */
public AliasingAnnotatedTypeFactory(BaseTypeChecker checker) {
super(checker);
if (this.getClass() == AliasingAnnotatedTypeFactory.class) {
this.postInit();
}
}
// @NonLeaked and @LeakedToResult are type qualifiers because of a checker framework limitation
// (Issue 383). Once the stub parser gets updated to read non-type-qualifiers annotations on stub
// files, this annotation won't be a type qualifier anymore.
@Override
protected Set<Class<? extends Annotation>> createSupportedTypeQualifiers() {
return getBundledTypeQualifiers(MaybeLeaked.class);
}
@Override
public CFTransfer createFlowTransferFunction(
CFAbstractAnalysis<CFValue, CFStore, CFTransfer> analysis) {
CFTransfer ret = new AliasingTransfer(analysis);
return ret;
}
protected class AliasingTreeAnnotator extends TreeAnnotator {
public AliasingTreeAnnotator(AliasingAnnotatedTypeFactory atypeFactory) {
super(atypeFactory);
}
@Override
public Void visitNewArray(NewArrayTree node, AnnotatedTypeMirror type) {
type.replaceAnnotation(UNIQUE);
return super.visitNewArray(node, type);
}
}
@Override
protected ListTreeAnnotator createTreeAnnotator() {
return new ListTreeAnnotator(new AliasingTreeAnnotator(this), super.createTreeAnnotator());
}
@Override
protected QualifierHierarchy createQualifierHierarchy() {
return new AliasingQualifierHierarchy(this.getSupportedTypeQualifiers(), elements);
}
/** AliasingQualifierHierarchy. */
protected class AliasingQualifierHierarchy extends NoElementQualifierHierarchy {
/**
* Create AliasingQualifierHierarchy.
*
* @param qualifierClasses classes of annotations that are the qualifiers
* @param elements element utils
*/
protected AliasingQualifierHierarchy(
Collection<Class<? extends Annotation>> qualifierClasses, Elements elements) {
super(qualifierClasses, elements);
}
/**
* Returns true is {@code anno} is annotation in the Leaked hierarchy.
*
* @param anno an annotation
* @return true is {@code anno} is annotation in the Leaked hierarchy
*/
private boolean isLeakedQualifier(AnnotationMirror anno) {
return areSameByClass(anno, MaybeLeaked.class)
|| areSameByClass(anno, NonLeaked.class)
|| areSameByClass(anno, LeakedToResult.class);
}
@Override
public boolean isSubtype(AnnotationMirror subAnno, AnnotationMirror superAnno) {
if (isLeakedQualifier(superAnno) && isLeakedQualifier(subAnno)) {
// @LeakedToResult and @NonLeaked were supposed to be non-type-qualifiers annotations.
// Currently the stub parser does not support non-type-qualifier annotations on receiver
// parameters (Issue 383), therefore these annotations are implemented as type qualifiers
// but the warnings related to the hierarchy are ignored.
return true;
}
return super.isSubtype(subAnno, superAnno);
}
}
}