package org.checkerframework.checker.linear;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import org.checkerframework.checker.linear.qual.Linear;
import org.checkerframework.checker.linear.qual.Unusable;
import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory;
import org.checkerframework.common.basetype.BaseTypeChecker;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.javacutil.AnnotationUtils;
/**
* Adds {@link Unusable} qualifier to a type if it represents:
*
* <ol>
* <li value="1">Class declaration tree/element. Such a construct usually requires the top
* qualifier.
* <li value="2">{@code Linear} reference once it is "used up"
* </ol>
*/
public class LinearAnnotatedTypeFactory extends BaseAnnotatedTypeFactory {
private final AnnotationMirror LINEAR, UNUSABLE;
public LinearAnnotatedTypeFactory(BaseTypeChecker checker) {
super(checker);
LINEAR = AnnotationUtils.fromClass(elements, Linear.class);
UNUSABLE = AnnotationUtils.fromClass(elements, Unusable.class);
this.postInit();
}
/** Case 1: type of class declaration */
@Override
public void addComputedTypeAnnotations(Element elt, AnnotatedTypeMirror type) {
if (!type.isAnnotatedInHierarchy(LINEAR) && elt.getKind().isClass()) {
type.addAnnotation(UNUSABLE);
}
super.addComputedTypeAnnotations(elt, type);
}
// TODO: Re-enable flow with the new org.checkerframework.dataflow framework.
/**
* Performs flow-sensitive analysis to mark reference types {@code Linear} as {@code Unusable}
* once they are used up.
*
* <p>A {code Linear} type is "used up" once the reference is mentioned, as an {@link
* IdentifierTree}.
*/
/*
private class LinearFlow extends DefaultFlow<DefaultFlowState> {
public LinearFlow(BaseTypeChecker checker, CompilationUnitTree root,
Set<AnnotationMirror> annotations, AnnotatedTypeFactory factory) {
super(checker, root, annotations, factory);
}
/**
* Case 2: add {@code Unusable} to node type, if it is {@code Linear}.
*
@Override
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 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 (this.flowState.vars.contains(elem)) {
int idx = this.flowState.vars.indexOf(elem);
if (this.flowState.annos.get(LINEAR, idx)) {
this.flowState.annos.set(UNUSABLE, idx);
this.flowState.annos.clear(LINEAR, idx);
}
}
}
}
*/
}