package checkers.linear; import java.util.Set; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.Element; import com.sun.source.tree.*; import checkers.basetype.BaseTypeChecker; import checkers.flow.Flow; import checkers.linear.quals.*; import checkers.types.AnnotatedTypeFactory; import checkers.types.AnnotatedTypeMirror; import checkers.types.BasicAnnotatedTypeFactory; import checkers.util.AnnotationUtils; import checkers.util.TreeUtils; /** * Adds {@link Unusable} qualifier to a type if it represents: * * <ol> * <li value="1">Class declaration tree/element. Such a construct usually * requires the root qualifier.</li> * * <li value="2">{@code Linear} reference once it is "used up"</li> * </ol> * */ public class LinearAnnotatedTypeFactory extends BasicAnnotatedTypeFactory<LinearChecker> { public LinearAnnotatedTypeFactory(LinearChecker checker, CompilationUnitTree root) { super(checker, root); } /** * Case 1: type of class declaration */ @Override public void annotateImplicit(Element elt, AnnotatedTypeMirror type) { if (!type.isAnnotated() && elt.getKind().isClass()) { type.addAnnotation(Unusable.class); } super.annotateImplicit(elt, type); } @Override public Flow createFlow(LinearChecker checker, CompilationUnitTree tree, Set<AnnotationMirror> flowQuals) { return new LinearFlow(checker, tree, flowQuals, this); } /** * Performs flow-sensitive analysis to mark reference types {@code Linear} * as {@code Unusable} once they are used up. * * A {code Linear} type is "used up" once the reference is mentioned, as * an {@link IdentifierTree}. * */ private static class LinearFlow extends Flow { private final AnnotationMirror LINEAR, UNUSABLE; public LinearFlow(BaseTypeChecker checker, CompilationUnitTree root, Set<AnnotationMirror> annotations, AnnotatedTypeFactory factory) { super(checker, root, annotations, factory); AnnotationUtils annoFactory = AnnotationUtils.getInstance(checker.getProcessingEnvironment()); LINEAR = annoFactory.fromClass(Linear.class); UNUSABLE = annoFactory.fromClass(Unusable.class); } /** * Case 2: add {@code Unusable} to node type, if it is {@code Linear}. */ public Void visitIdentifier(IdentifierTree node, Void p) { super.visitIdentifier(node, p); markAsUnusableIfLinear(node); return null; } /** * If the node is of type {@code Linear}, then transit its type * into an {@code Unusable} type. * * The method should be called on every every instance of a tree * that causes the reference to be "used up". */ private void markAsUnusableIfLinear(ExpressionTree node) { if (!LinearVisitor.isLocalVarOrParam(node)) return; Element elem = TreeUtils.elementFromUse(node); assert elem != null; if (vars.contains(elem)) { int idx = vars.indexOf(elem); if (annos.get(LINEAR, idx)) { annos.set(UNUSABLE, idx); annos.clear(LINEAR, idx); } } } } }