use of org.checkerframework.dataflow.expression.LocalVariable in project checker-framework by typetools.
the class CFAbstractTransfer method addFinalLocalValues.
/**
* Adds information about effectively final variables (from outer scopes)
*
* @param store the store to add to
* @param enclosingElement the enclosing element of the code we are analyzing
*/
private void addFinalLocalValues(S store, Element enclosingElement) {
// add information about effectively final variables (from outer scopes)
for (Map.Entry<Element, V> e : analysis.atypeFactory.getFinalLocalValues().entrySet()) {
Element elem = e.getKey();
// TODO: There is a design flaw where the values of final local values leaks
// into other methods of the same class. For example, in
// class a { void b() {...} void c() {...} }
// final local values from b() would be visible in the store for c(),
// even though they should only be visible in b() and in classes
// defined inside the method body of b().
// This is partly because GenericAnnotatedTypeFactory.performFlowAnalysis does not call itself
// recursively to analyze inner classes, but instead pops classes off of a queue, and the
// information about known final local values is stored by GenericAnnotatedTypeFactory.analyze
// in GenericAnnotatedTypeFactory.flowResult, which is visible to all classes in the queue
// regardless of their level of recursion.
// We work around this here by ensuring that we only add a final local value to a method's
// store if that method is enclosed by the method where the local variables were declared.
// Find the enclosing method of the element
Element enclosingMethodOfVariableDeclaration = elem.getEnclosingElement();
if (enclosingMethodOfVariableDeclaration != null) {
// Now find all the enclosing methods of the code we are analyzing. If any one of
// them matches the above, then the final local variable value applies.
Element enclosingMethodOfCurrentMethod = enclosingElement;
while (enclosingMethodOfCurrentMethod != null) {
if (enclosingMethodOfVariableDeclaration.equals(enclosingMethodOfCurrentMethod)) {
LocalVariable l = new LocalVariable(elem);
store.insertValue(l, e.getValue());
break;
}
enclosingMethodOfCurrentMethod = enclosingMethodOfCurrentMethod.getEnclosingElement();
}
}
}
}
use of org.checkerframework.dataflow.expression.LocalVariable in project checker-framework by typetools.
the class CFAbstractStore method clearValue.
/**
* Remove any knowledge about the expression {@code expr} (correctly deciding where to remove the
* information depending on the type of the expression {@code expr}).
*/
public void clearValue(JavaExpression expr) {
if (expr.containsUnknown()) {
// Expressions containing unknown expressions are not stored.
return;
}
if (expr instanceof LocalVariable) {
LocalVariable localVar = (LocalVariable) expr;
localVariableValues.remove(localVar);
} else if (expr instanceof FieldAccess) {
FieldAccess fieldAcc = (FieldAccess) expr;
fieldValues.remove(fieldAcc);
} else if (expr instanceof MethodCall) {
MethodCall method = (MethodCall) expr;
methodValues.remove(method);
} else if (expr instanceof ArrayAccess) {
ArrayAccess a = (ArrayAccess) expr;
arrayValues.remove(a);
} else if (expr instanceof ClassName) {
ClassName c = (ClassName) expr;
classValues.remove(c);
} else {
// thisValue ...
// No other types of expressions are stored.
}
}
use of org.checkerframework.dataflow.expression.LocalVariable in project checker-framework by typetools.
the class DependentTypesHelper method delocalize.
/**
* Viewpoint-adapt all dependent type annotations to the method declaration, {@code
* methodDeclTree}. This method changes occurrences of formal parameter names to the "#2" syntax,
* and it removes expressions that contain other local variables.
*
* <p>If a Java expression in {@code atm} references local variables (other than formal
* parameters), the expression is removed from the annotation. This could result in dependent type
* annotations with empty lists of expressions. If this is a problem, a subclass can override
* {@link #buildAnnotation(AnnotationMirror, Map)} to do something besides creating an annotation
* with a empty list.
*
* @param atm type to viewpoint-adapt; is side-effected by this method
* @param methodDeclTree the method declaration to which the annotations are viewpoint-adapted
*/
public void delocalize(AnnotatedTypeMirror atm, MethodTree methodDeclTree) {
if (!hasDependentType(atm)) {
return;
}
TreePath pathToMethodDecl = factory.getPath(methodDeclTree);
ExecutableElement methodElement = TreeUtils.elementFromDeclaration(methodDeclTree);
List<FormalParameter> parameters = JavaExpression.getFormalParameters(methodElement);
List<JavaExpression> paramsAsLocals = JavaExpression.getParametersAsLocalVariables(methodElement);
StringToJavaExpression stringToJavaExpr = expression -> {
JavaExpression javaExpr;
try {
javaExpr = StringToJavaExpression.atPath(expression, pathToMethodDecl, factory.getChecker());
} catch (JavaExpressionParseException ex) {
return null;
}
JavaExpressionConverter jec = new JavaExpressionConverter() {
@Override
protected JavaExpression visitLocalVariable(LocalVariable localVarExpr, Void unused) {
int index = paramsAsLocals.indexOf(localVarExpr);
if (index == -1) {
throw new FoundLocalException();
}
return parameters.get(index);
}
};
try {
return jec.convert(javaExpr);
} catch (FoundLocalException ex) {
return null;
}
};
if (debugStringToJavaExpression) {
System.out.printf("delocalize(%s, %s) created %s%n", atm, TreeUtils.toStringTruncated(methodDeclTree, 65), stringToJavaExpr);
}
convertAnnotatedTypeMirror(stringToJavaExpr, atm);
}
use of org.checkerframework.dataflow.expression.LocalVariable in project checker-framework by typetools.
the class MustCallConsistencyAnalyzer method isValidCreatesMustCallForExpression.
/**
* Checks the validity of the given expression from an invoked method's {@link
* org.checkerframework.checker.mustcall.qual.CreatesMustCallFor} annotation. Helper method for
* {@link #checkCreatesMustCallForInvocation(Set, MethodInvocationNode)}.
*
* <p>An expression is valid if one of the following conditions is true: 1) the expression is an
* owning pointer, 2) the expression already has a tracked Obligation (i.e. there is already a
* resource alias in some Obligation's resource alias set that refers to the expression), or 3)
* the method in which the invocation occurs also has an @CreatesMustCallFor annotation, with the
* same expression.
*
* @param obligations the currently-tracked Obligations; this value is side-effected if there is
* an Obligation in it which tracks {@code expression} as one of its resource aliases
* @param expression an element of a method's @CreatesMustCallFor annotation
* @param path the path to the invocation of the method from whose @CreateMustCallFor annotation
* {@code expression} came
* @return true iff the expression is valid, as defined above
*/
private boolean isValidCreatesMustCallForExpression(Set<Obligation> obligations, JavaExpression expression, TreePath path) {
if (expression instanceof FieldAccess) {
Element elt = ((FieldAccess) expression).getField();
if (!checker.hasOption(MustCallChecker.NO_LIGHTWEIGHT_OWNERSHIP) && typeFactory.getDeclAnnotation(elt, Owning.class) != null) {
// The expression is an Owning field. This satisfies case 1.
return true;
}
} else if (expression instanceof LocalVariable) {
Element elt = ((LocalVariable) expression).getElement();
if (!checker.hasOption(MustCallChecker.NO_LIGHTWEIGHT_OWNERSHIP) && typeFactory.getDeclAnnotation(elt, Owning.class) != null) {
// This satisfies case 1.
return true;
} else {
Obligation toRemove = null;
Obligation toAdd = null;
for (Obligation obligation : obligations) {
ResourceAlias alias = obligation.getResourceAlias(expression);
if (alias != null) {
// This satisfies case 2 above. Remove all its aliases, then return below.
if (toRemove != null) {
throw new TypeSystemError("tried to remove multiple sets containing a reset expression at once");
}
toRemove = obligation;
toAdd = new Obligation(ImmutableSet.of(alias));
}
}
if (toRemove != null) {
obligations.remove(toRemove);
obligations.add(toAdd);
// This satisfies case 2.
return true;
}
}
}
// TODO: Getting this every time is inefficient if a method has many @CreatesMustCallFor
// annotations, but that should be rare.
MethodTree enclosingMethodTree = TreePathUtil.enclosingMethod(path);
if (enclosingMethodTree == null) {
return false;
}
ExecutableElement enclosingMethodElt = TreeUtils.elementFromDeclaration(enclosingMethodTree);
MustCallAnnotatedTypeFactory mcAtf = typeFactory.getTypeFactoryOfSubchecker(MustCallChecker.class);
List<String> enclosingCmcfValues = ResourceLeakVisitor.getCreatesMustCallForValues(enclosingMethodElt, mcAtf, typeFactory);
if (enclosingCmcfValues.isEmpty()) {
return false;
}
for (String enclosingCmcfValue : enclosingCmcfValues) {
JavaExpression enclosingTarget;
try {
enclosingTarget = StringToJavaExpression.atMethodBody(enclosingCmcfValue, enclosingMethodTree, checker);
} catch (JavaExpressionParseException e) {
// Do not issue an error here, because it would be a duplicate.
// The error will be issued by the Transfer class of the checker,
// via the CreatesMustCallForElementSupplier interface.
enclosingTarget = null;
}
if (areSame(expression, enclosingTarget)) {
// This satisfies case 3.
return true;
}
}
return false;
}
use of org.checkerframework.dataflow.expression.LocalVariable in project checker-framework by typetools.
the class UpperBoundVisitor method checkEffectivelyFinalAndParsable.
/**
* Reports an error if the Java expression named by s is not effectively final when parsed at the
* declaration of the given class.
*
* @param s a Java expression
* @param classTree the expression is parsed with respect to this class
* @param whereToReportError the tree at which to possibly report an error
*/
private void checkEffectivelyFinalAndParsable(String s, ClassTree classTree, Tree whereToReportError) {
JavaExpression je;
try {
je = StringToJavaExpression.atTypeDecl(s, TreeUtils.elementFromDeclaration(classTree), checker);
} catch (JavaExpressionParseException e) {
checker.report(whereToReportError, e.getDiagMessage());
return;
}
Element element = null;
if (je instanceof LocalVariable) {
element = ((LocalVariable) je).getElement();
} else if (je instanceof FieldAccess) {
element = ((FieldAccess) je).getField();
} else if (je instanceof ThisReference || je instanceof ValueLiteral) {
return;
}
if (element == null || !ElementUtils.isEffectivelyFinal(element)) {
checker.reportError(whereToReportError, NOT_FINAL, je);
}
}
Aggregations