Skip to content

Commit

Permalink
Fix incorrect handling of temporary variable enclosing element in RL …
Browse files Browse the repository at this point in the history
…inference; fixes #6473
  • Loading branch information
iamsanjaymalakar authored Mar 4, 2024
1 parent a49161a commit 7743e5d
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.checkerframework.checker.mustcall;

import com.sun.source.tree.ClassTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.Tree;
Expand Down Expand Up @@ -289,8 +288,10 @@ public void updateStoreWithTempVar(TransferResult<CFValue, CFStore> result, Node
if (path == null) {
enclosingElement = TreeUtils.elementFromUse(tree).getEnclosingElement();
} else {
ClassTree classTree = TreePathUtil.enclosingClass(path);
enclosingElement = TreeUtils.elementFromDeclaration(classTree);
// Issue 6473
// Adjusts handling of nearest enclosing element for temporary variables.
// This approach ensures the correct enclosing element (method or class) is determined.
enclosingElement = TreePathUtil.findNearestEnclosingElement(path);
}
if (enclosingElement == null) {
return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Demonstrates an issue in the Checker Framework with handling the nearest enclosing element for
* temporary variable declarations, leading to a crash during analysis.
*/
public abstract class CrashForTempVar<T extends Number> {

private final CrashForTempVar<T> _base;

protected CrashForTempVar(final CrashForTempVar<T> base) {
_base = base;
}

public T getValue() {
return _base.getValue();
}

protected CrashForTempVar<T> getBase() {
return _base;
}

protected abstract boolean evaluateLayer(final T baseValue, final T testValue);

public boolean evaluate(final T testValue) {
return evaluateLayer(getBase().getValue(), testValue);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1669,7 +1669,7 @@ protected boolean assumeAssertionsEnabledFor(AssertTree tree) {
protected VariableTree getAssertionsEnabledVariable() {
if (ea == null) {
String name = uniqueName("assertionsEnabled");
Element owner = findOwner();
Element owner = TreePathUtil.findNearestEnclosingElement(getCurrentPath());
ExpressionTree initializer = null;
ea =
treeBuilder.buildVariableDecl(
Expand All @@ -1679,21 +1679,6 @@ protected VariableTree getAssertionsEnabledVariable() {
return ea;
}

/**
* Find nearest owner element (Method or Class) which holds current tree.
*
* @return nearest owner element of current tree
*/
private Element findOwner() {
MethodTree enclosingMethod = TreePathUtil.enclosingMethod(getCurrentPath());
if (enclosingMethod != null) {
return TreeUtils.elementFromDeclaration(enclosingMethod);
} else {
ClassTree enclosingClass = TreePathUtil.enclosingClass(getCurrentPath());
return TreeUtils.elementFromDeclaration(enclosingClass);
}
}

/**
* Translates an assertion statement to the correct CFG nodes. The translation assumes that
* assertions are enabled.
Expand Down Expand Up @@ -2550,7 +2535,11 @@ private void buildSelector() {
// Create a synthetic variable to which the switch selector expression will be assigned
TypeMirror selectorExprType = TreeUtils.typeOf(selectorExprTree);
VariableTree selectorVarTree =
treeBuilder.buildVariableDecl(selectorExprType, uniqueName("switch"), findOwner(), null);
treeBuilder.buildVariableDecl(
selectorExprType,
uniqueName("switch"),
TreePathUtil.findNearestEnclosingElement(getCurrentPath()),
null);
handleArtificialTree(selectorVarTree);

VariableDeclarationNode selectorVarNode = new VariableDeclarationNode(selectorVarTree);
Expand Down Expand Up @@ -2586,7 +2575,10 @@ private void buildSwitchExpressionVar() {
TypeMirror switchExprType = TreeUtils.typeOf(switchTree);
switchExprVarTree =
treeBuilder.buildVariableDecl(
switchExprType, uniqueName("switchExpr"), findOwner(), null);
switchExprType,
uniqueName("switchExpr"),
TreePathUtil.findNearestEnclosingElement(getCurrentPath()),
null);
handleArtificialTree(switchExprVarTree);

VariableDeclarationNode switchExprVarNode = new VariableDeclarationNode(switchExprVarTree);
Expand Down Expand Up @@ -2737,7 +2729,11 @@ public Node visitConditionalExpression(ConditionalExpressionTree tree, Void p) {

// create a synthetic variable for the value of the conditional expression
VariableTree condExprVarTree =
treeBuilder.buildVariableDecl(exprType, uniqueName("condExpr"), findOwner(), null);
treeBuilder.buildVariableDecl(
exprType,
uniqueName("condExpr"),
TreePathUtil.findNearestEnclosingElement(getCurrentPath()),
null);
handleArtificialTree(condExprVarTree);
VariableDeclarationNode condExprVarNode = new VariableDeclarationNode(condExprVarTree);
condExprVarNode.setInSource(false);
Expand Down Expand Up @@ -4169,7 +4165,10 @@ public Node visitUnary(UnaryTree tree, Void p) {
TypeMirror exprType = TreeUtils.typeOf(exprTree);
VariableTree tempVarDecl =
treeBuilder.buildVariableDecl(
exprType, uniqueName("tempPostfix"), findOwner(), tree.getExpression());
exprType,
uniqueName("tempPostfix"),
TreePathUtil.findNearestEnclosingElement(getCurrentPath()),
tree.getExpression());
handleArtificialTree(tempVarDecl);
VariableDeclarationNode tempVarDeclNode = new VariableDeclarationNode(tempVarDecl);
tempVarDeclNode.setInSource(false);
Expand Down
1 change: 1 addition & 0 deletions docs/manual/contributors.tex
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
Ryan Oblak,
Sadaf Tajik,
Sagar Tewari,
Sanjay Malakar,
Sean C. Sullivan,
Sean McLaughlin,
Sebastian Schuberth,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -467,4 +467,25 @@ public static String leafToStringTruncated(@Nullable TreePath path, int length)
}
return TreeUtils.toStringTruncated(path.getLeaf(), length);
}

/**
* Retrieves the nearest enclosing method or class element for the specified path in the AST. This
* utility method prioritizes method elements over class elements. It returns the element of the
* closest method scope if available; otherwise, it defaults to the enclosing class scope.
*
* @param path the {@link TreePath} to analyze for the nearest enclosing scope.
* @return the {@link Element} of the nearest enclosing method or class, or {@code null} if no
* such enclosing element can be found.
*/
public static @Nullable Element findNearestEnclosingElement(TreePath path) {
MethodTree enclosingMethodTree = TreePathUtil.enclosingMethod(path);
if (enclosingMethodTree != null) {
return TreeUtils.elementFromDeclaration(enclosingMethodTree);
}
ClassTree enclosingClassTree = TreePathUtil.enclosingClass(path);
if (enclosingClassTree != null) {
return TreeUtils.elementFromDeclaration(enclosingClassTree);
}
return null;
}
}

0 comments on commit 7743e5d

Please sign in to comment.