use of org.checkerframework.common.aliasing.qual.Unique in project checker-framework by typetools.
the class AliasingTransfer method visitAssignment.
/**
* Case 1: For every assignment, the LHS is refined if the RHS has type {@literal @}Unique and is
* a method invocation or a new class instance.
*/
@Override
public TransferResult<CFValue, CFStore> visitAssignment(AssignmentNode n, TransferInput<CFValue, CFStore> in) {
Node rhs = n.getExpression();
Tree treeRhs = rhs.getTree();
AnnotatedTypeMirror rhsType = factory.getAnnotatedType(treeRhs);
if (rhsType.hasAnnotation(Unique.class) && (rhs instanceof MethodInvocationNode || rhs instanceof ObjectCreationNode)) {
// Do normal refinement.
return super.visitAssignment(n, in);
}
// Widen the type of the rhs if the RHS's declared type wasn't @Unique.
JavaExpression rhsExpr = JavaExpression.fromNode(rhs);
in.getRegularStore().clearValue(rhsExpr);
return new RegularTransferResult<>(null, in.getRegularStore());
}
use of org.checkerframework.common.aliasing.qual.Unique in project checker-framework by typetools.
the class AliasingVisitor method canBeLeaked.
/**
* Returns true if {@code exp} has type {@code @Unique} and is not a method invocation nor a new
* class expression. It checks whether the tree expression is unique by either checking for an
* explicit annotation or checking whether the class of the tree expression {@code exp} has type
* {@code @Unique}
*
* @param exp the Tree to check
* @return true if {@code exp} has type {@code @Unique} and is not a method invocation nor a new
* class expression
*/
private boolean canBeLeaked(Tree exp) {
AnnotatedTypeMirror type = atypeFactory.getAnnotatedType(exp);
boolean isMethodInvocation = exp.getKind() == Tree.Kind.METHOD_INVOCATION;
boolean isNewClass = exp.getKind() == Tree.Kind.NEW_CLASS;
boolean isUniqueType = isUniqueClass(type) || type.hasExplicitAnnotation(Unique.class);
return isUniqueType && !isMethodInvocation && !isNewClass;
}
use of org.checkerframework.common.aliasing.qual.Unique in project checker-framework by typetools.
the class AliasingVisitor method visitVariable.
@Override
public Void visitVariable(VariableTree node, Void p) {
// Component types are not allowed to have the @Unique annotation.
AnnotatedTypeMirror varType = atypeFactory.getAnnotatedType(node);
VariableElement elt = TreeUtils.elementFromDeclaration(node);
if (elt.getKind().isField() && varType.hasExplicitAnnotation(Unique.class)) {
checker.reportError(node, "unique.location.forbidden");
} else if (node.getType().getKind() == Tree.Kind.ARRAY_TYPE) {
AnnotatedArrayType arrayType = (AnnotatedArrayType) varType;
if (arrayType.getComponentType().hasAnnotation(Unique.class)) {
checker.reportError(node, "unique.location.forbidden");
}
} else if (node.getType().getKind() == Tree.Kind.PARAMETERIZED_TYPE) {
AnnotatedDeclaredType declaredType = (AnnotatedDeclaredType) varType;
for (AnnotatedTypeMirror atm : declaredType.getTypeArguments()) {
if (atm.hasAnnotation(Unique.class)) {
checker.reportError(node, "unique.location.forbidden");
}
}
}
return super.visitVariable(node, p);
}
use of org.checkerframework.common.aliasing.qual.Unique in project checker-framework by typetools.
the class AliasingVisitor method visitMethodInvocation.
/**
* Checks that if a method call is being invoked inside a constructor with result type
* {@literal @}Unique, it must not leak the "this" reference. There are 3 ways to make sure that
* this is not happening:
*
* <ol>
* <li>{@code this} is not an argument of the method call.
* <li>{@code this} is an argument of the method call, but the respective parameter is annotated
* as {@literal @}NonLeaked.
* <li>{@code this} is an argument of the method call, but the respective parameter is annotated
* as {@literal @}LeakedToResult AND the result of the method call is not being stored (the
* method call is a statement).
* </ol>
*
* The private method {@code isUniqueCheck} handles cases 2 and 3.
*/
@Override
public Void visitMethodInvocation(MethodInvocationTree node, Void p) {
// @Unique. We also want to avoid visiting the <init> method.
if (isInUniqueConstructor()) {
if (TreeUtils.isSuperConstructorCall(node)) {
// Check if a call to super() might create an alias: that
// happens when the parent's respective constructor is not @Unique.
AnnotatedTypeMirror superResult = atypeFactory.getAnnotatedType(node);
if (!superResult.hasAnnotation(Unique.class)) {
checker.reportError(node, "unique.leaked");
}
} else {
// TODO: Currently the type of "this" doesn't always return the type of the constructor
// result, therefore we need this "else" block. Once constructors are implemented correctly
// we could remove that code below, since the type of "this" in a @Unique constructor will
// be @Unique.
Tree parent = getCurrentPath().getParentPath().getLeaf();
boolean parentIsStatement = parent.getKind() == Tree.Kind.EXPRESSION_STATEMENT;
ExecutableElement methodElement = TreeUtils.elementFromUse(node);
List<? extends VariableElement> params = methodElement.getParameters();
List<? extends ExpressionTree> args = node.getArguments();
assert (args.size() == params.size()) : "Number of arguments in" + " the method call " + node + " is different from the " + "number of parameters for the method declaration: " + methodElement.getSimpleName();
for (int i = 0; i < args.size(); i++) {
// For every argument we check if it is a reference to "this".
if (TreeUtils.isExplicitThisDereference(args.get(i))) {
// If it is a reference to "this", there is still hope that
// it is not being leaked (2. and 3. from the javadoc).
VariableElement param = params.get(i);
boolean hasNonLeaked = atypeFactory.getAnnotatedType(param).hasAnnotation(NonLeaked.class);
boolean hasLeakedToResult = atypeFactory.getAnnotatedType(param).hasAnnotation(LeakedToResult.class);
isUniqueCheck(node, parentIsStatement, hasNonLeaked, hasLeakedToResult);
} else {
// Not possible to leak reference here (case 1. from the javadoc).
}
}
// Now, doing the same as above for the receiver parameter
AnnotatedExecutableType annotatedType = atypeFactory.getAnnotatedType(methodElement);
AnnotatedDeclaredType receiverType = annotatedType.getReceiverType();
if (receiverType != null) {
boolean hasNonLeaked = receiverType.hasAnnotation(NonLeaked.class);
boolean hasLeakedToResult = receiverType.hasAnnotation(LeakedToResult.class);
isUniqueCheck(node, parentIsStatement, hasNonLeaked, hasLeakedToResult);
}
}
}
return super.visitMethodInvocation(node, p);
}
Aggregations