package org.checkerframework.common.aliasing; import com.sun.source.tree.NewArrayTree; import com.sun.source.tree.NewClassTree; import java.lang.annotation.Annotation; import java.util.Map; import java.util.Set; import javax.lang.model.element.AnnotationMirror; 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.QualifierHierarchy; import org.checkerframework.framework.type.treeannotator.ImplicitsTreeAnnotator; import org.checkerframework.framework.type.treeannotator.ListTreeAnnotator; import org.checkerframework.framework.type.treeannotator.PropagationTreeAnnotator; import org.checkerframework.framework.type.treeannotator.TreeAnnotator; import org.checkerframework.framework.util.MultiGraphQualifierHierarchy; import org.checkerframework.framework.util.MultiGraphQualifierHierarchy.MultiGraphFactory; import org.checkerframework.javacutil.AnnotationUtils; public class AliasingAnnotatedTypeFactory extends BaseAnnotatedTypeFactory { private final AnnotationMirror MAYBE_ALIASED, NON_LEAKED, UNIQUE, MAYBE_LEAKED; public AliasingAnnotatedTypeFactory(BaseTypeChecker checker) { super(checker); MAYBE_ALIASED = AnnotationUtils.fromClass(elements, MaybeAliased.class); NON_LEAKED = AnnotationUtils.fromClass(elements, NonLeaked.class); UNIQUE = AnnotationUtils.fromClass(elements, Unique.class); MAYBE_LEAKED = AnnotationUtils.fromClass(elements, MaybeLeaked.class); if (this.getClass().equals(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-qualifers annotations on stub files, this annotation won't be a // type qualifier anymore. @Override protected Set<Class<? extends Annotation>> createSupportedTypeQualifiers() { return getBundledTypeQualifiersWithoutPolyAll(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 visitNewClass(NewClassTree node, AnnotatedTypeMirror p) { // Copied hack below from SPARTA: // This is a horrible hack around the implementation of constructor // results (CF treats annotations on constructor results in stub // files as if it were a default and therefore ignores it.) // This hack ignores any annotation written in the following location: // new @A SomeClass(); AnnotatedTypeMirror defaulted = atypeFactory.constructorFromUse(node).first.getReturnType(); Set<AnnotationMirror> defaultedSet = defaulted.getAnnotations(); p.replaceAnnotations(defaultedSet); return null; } @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), new PropagationTreeAnnotator(this), new ImplicitsTreeAnnotator(this)); } @Override protected MultiGraphQualifierHierarchy.MultiGraphFactory createQualifierHierarchyFactory() { return new MultiGraphQualifierHierarchy.MultiGraphFactory(this); } @Override public QualifierHierarchy createQualifierHierarchy(MultiGraphFactory factory) { return new AliasingQualifierHierarchy(factory); } protected class AliasingQualifierHierarchy extends MultiGraphQualifierHierarchy { protected AliasingQualifierHierarchy(MultiGraphFactory f) { super(f); } @Override protected Set<AnnotationMirror> findBottoms( Map<AnnotationMirror, Set<AnnotationMirror>> supertypes) { Set<AnnotationMirror> newbottoms = AnnotationUtils.createAnnotationSet(); newbottoms.add(UNIQUE); newbottoms.add(MAYBE_LEAKED); return newbottoms; } @Override protected Set<AnnotationMirror> findTops( Map<AnnotationMirror, Set<AnnotationMirror>> supertypes) { Set<AnnotationMirror> newtops = AnnotationUtils.createAnnotationSet(); newtops.add(MAYBE_ALIASED); newtops.add(NON_LEAKED); return newtops; } private boolean isLeakedQualifier(AnnotationMirror anno) { return AnnotationUtils.areSameByClass(anno, MaybeLeaked.class) || AnnotationUtils.areSameByClass(anno, NonLeaked.class) || AnnotationUtils.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); } } }