Skip to content

Commit

Permalink
Create top level class VariableReferences
Browse files Browse the repository at this point in the history
  • Loading branch information
timtebeek committed Nov 2, 2024
1 parent 80cb672 commit e152bcf
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 121 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import java.time.Duration;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;

@Value
@EqualsAndHashCode(callSuper = false)
Expand Down Expand Up @@ -132,9 +131,9 @@ private Cursor getCursorToParentScope(Cursor cursor) {
return variable;
}

List<J> readReferences = References.findRhsReferences(parentScope.getValue(), variable.getName());
List<J> readReferences = VariableReferences.findRhsReferences(parentScope.getValue(), variable.getName());
if (readReferences.isEmpty()) {
List<Statement> assignmentReferences = References.findLhsReferences(parentScope.getValue(), variable.getName());
List<Statement> assignmentReferences = VariableReferences.findLhsReferences(parentScope.getValue(), variable.getName());
for (Statement ref : assignmentReferences) {
if (ref instanceof J.Assignment) {
doAfterVisit(new PruneAssignmentExpression((J.Assignment) ref));
Expand Down Expand Up @@ -245,122 +244,4 @@ public J visitAssignment(J.Assignment a, ExecutionContext ctx) {
}
}

private static class References {
private static boolean isIncrementKind(Cursor tree) {
return tree.getValue() instanceof J.Unary && ((J.Unary) tree.getValue()).getOperator().isModifying();
}

private static @Nullable Cursor dropParentWhile(Predicate<Object> valuePredicate, Cursor cursor) {
while (cursor != null && valuePredicate.test(cursor.getValue())) {
cursor = cursor.getParent();
}
return cursor;
}

private static @Nullable Cursor dropParentUntil(Predicate<Object> valuePredicate, Cursor cursor) {
while (cursor != null && !valuePredicate.test(cursor.getValue())) {
cursor = cursor.getParent();
}
return cursor;
}

private static boolean isRhsValue(Cursor tree) {
if (!(tree.getValue() instanceof J.Identifier)) {
return false;
}

Cursor parent = dropParentWhile(J.Parentheses.class::isInstance, tree.getParent());
assert parent != null;
if (parent.getValue() instanceof J.Assignment) {
if (dropParentUntil(J.ControlParentheses.class::isInstance, parent) != null) {
return true;
}
J.Assignment assignment = parent.getValue();
return assignment.getVariable() != tree.getValue();
}

if (parent.getValue() instanceof J.VariableDeclarations.NamedVariable) {
J.VariableDeclarations.NamedVariable namedVariable = parent.getValue();
return namedVariable.getName() != tree.getValue();
}

if (parent.getValue() instanceof J.AssignmentOperation) {
J.AssignmentOperation assignmentOperation = parent.getValue();
if (assignmentOperation.getVariable() == tree.getValue()) {
Tree grandParent = parent.getParentTreeCursor().getValue();
return (grandParent instanceof Expression || grandParent instanceof J.Return);
}
}

return !(isIncrementKind(parent) && parent.getParentTreeCursor().getValue() instanceof J.Block);
}

/**
* An identifier is considered a right-hand side ("rhs") read operation if it is not used as the left operand
* of an assignment, nor as the operand of a stand-alone increment.
*
* @param j The subtree to search.
* @param target A {@link J.Identifier} to check for usages.
* @return found {@link J} locations of "right-hand" read calls.
*/
private static List<J> findRhsReferences(J j, J.Identifier target) {
final List<J> refs = new ArrayList<>();
new JavaIsoVisitor<List<J>>() {
@Override
public J.Identifier visitIdentifier(J.Identifier identifier, List<J> ctx) {
if (identifier.getSimpleName().equals(target.getSimpleName()) && isRhsValue(getCursor())) {
ctx.add(identifier);
}
return super.visitIdentifier(identifier, ctx);
}
}.visit(j, refs);
return refs;
}

/**
* @param j The subtree to search.
* @param target A {@link J.Identifier} to check for usages.
* @return found {@link Statement} locations of "left-hand" assignment write calls.
*/
private static List<Statement> findLhsReferences(J j, J.Identifier target) {
JavaIsoVisitor<List<Statement>> visitor = new JavaIsoVisitor<List<Statement>>() {
@Override
public J.Assignment visitAssignment(J.Assignment assignment, List<Statement> ctx) {
if (assignment.getVariable() instanceof J.Identifier) {
J.Identifier i = (J.Identifier) assignment.getVariable();
if (i.getSimpleName().equals(target.getSimpleName())) {
ctx.add(assignment);
}
}
return super.visitAssignment(assignment, ctx);
}

@Override
public J.AssignmentOperation visitAssignmentOperation(J.AssignmentOperation assignOp, List<Statement> ctx) {
if (assignOp.getVariable() instanceof J.Identifier) {
J.Identifier i = (J.Identifier) assignOp.getVariable();
if (i.getSimpleName().equals(target.getSimpleName())) {
ctx.add(assignOp);
}
}
return super.visitAssignmentOperation(assignOp, ctx);
}

@Override
public J.Unary visitUnary(J.Unary unary, List<Statement> ctx) {
if (unary.getExpression() instanceof J.Identifier) {
J.Identifier i = (J.Identifier) unary.getExpression();
if (i.getSimpleName().equals(target.getSimpleName())) {
ctx.add(unary);
}
}
return super.visitUnary(unary, ctx);
}
};

List<Statement> refs = new ArrayList<>();
visitor.visit(j, refs);
return refs;
}
}
}
132 changes: 132 additions & 0 deletions src/main/java/org/openrewrite/staticanalysis/VariableReferences.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package org.openrewrite.staticanalysis;

import org.jspecify.annotations.Nullable;
import org.openrewrite.Cursor;
import org.openrewrite.Tree;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.tree.Expression;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.Statement;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

public class VariableReferences {
private static boolean isIncrementKind(Cursor tree) {
return tree.getValue() instanceof J.Unary && ((J.Unary) tree.getValue()).getOperator().isModifying();
}

private static @Nullable Cursor dropParentWhile(Predicate<Object> valuePredicate, Cursor cursor) {
while (cursor != null && valuePredicate.test(cursor.getValue())) {
cursor = cursor.getParent();
}
return cursor;
}

private static @Nullable Cursor dropParentUntil(Predicate<Object> valuePredicate, Cursor cursor) {
while (cursor != null && !valuePredicate.test(cursor.getValue())) {
cursor = cursor.getParent();
}
return cursor;
}

private static boolean isRhsValue(Cursor tree) {
if (!(tree.getValue() instanceof J.Identifier)) {
return false;
}

Cursor parent = dropParentWhile(J.Parentheses.class::isInstance, tree.getParent());
assert parent != null;
if (parent.getValue() instanceof J.Assignment) {
if (dropParentUntil(J.ControlParentheses.class::isInstance, parent) != null) {
return true;
}
J.Assignment assignment = parent.getValue();
return assignment.getVariable() != tree.getValue();
}

if (parent.getValue() instanceof J.VariableDeclarations.NamedVariable) {
J.VariableDeclarations.NamedVariable namedVariable = parent.getValue();
return namedVariable.getName() != tree.getValue();
}

if (parent.getValue() instanceof J.AssignmentOperation) {
J.AssignmentOperation assignmentOperation = parent.getValue();
if (assignmentOperation.getVariable() == tree.getValue()) {
Tree grandParent = parent.getParentTreeCursor().getValue();
return (grandParent instanceof Expression || grandParent instanceof J.Return);
}
}

return !(isIncrementKind(parent) && parent.getParentTreeCursor().getValue() instanceof J.Block);
}

/**
* An identifier is considered a right-hand side ("rhs") read operation if it is not used as the left operand
* of an assignment, nor as the operand of a stand-alone increment.
*
* @param j The subtree to search.
* @param target A {@link J.Identifier} to check for usages.
* @return found {@link J} locations of "right-hand" read calls.
*/
public static List<J> findRhsReferences(J j, J.Identifier target) {
final List<J> refs = new ArrayList<>();
new JavaIsoVisitor<List<J>>() {
@Override
public J.Identifier visitIdentifier(J.Identifier identifier, List<J> ctx) {
if (identifier.getSimpleName().equals(target.getSimpleName()) && isRhsValue(getCursor())) {
ctx.add(identifier);
}
return super.visitIdentifier(identifier, ctx);
}
}.visit(j, refs);
return refs;
}

/**
* @param j The subtree to search.
* @param target A {@link J.Identifier} to check for usages.
* @return found {@link Statement} locations of "left-hand" assignment write calls.
*/
public static List<Statement> findLhsReferences(J j, J.Identifier target) {
JavaIsoVisitor<List<Statement>> visitor = new JavaIsoVisitor<List<Statement>>() {
@Override
public J.Assignment visitAssignment(J.Assignment assignment, List<Statement> ctx) {
if (assignment.getVariable() instanceof J.Identifier) {
J.Identifier i = (J.Identifier) assignment.getVariable();
if (i.getSimpleName().equals(target.getSimpleName())) {
ctx.add(assignment);
}
}
return super.visitAssignment(assignment, ctx);
}

@Override
public J.AssignmentOperation visitAssignmentOperation(J.AssignmentOperation assignOp, List<Statement> ctx) {
if (assignOp.getVariable() instanceof J.Identifier) {
J.Identifier i = (J.Identifier) assignOp.getVariable();
if (i.getSimpleName().equals(target.getSimpleName())) {
ctx.add(assignOp);
}
}
return super.visitAssignmentOperation(assignOp, ctx);
}

@Override
public J.Unary visitUnary(J.Unary unary, List<Statement> ctx) {
if (unary.getExpression() instanceof J.Identifier) {
J.Identifier i = (J.Identifier) unary.getExpression();
if (i.getSimpleName().equals(target.getSimpleName())) {
ctx.add(unary);
}
}
return super.visitUnary(unary, ctx);
}
};

List<Statement> refs = new ArrayList<>();
visitor.visit(j, refs);
return refs;
}
}

0 comments on commit e152bcf

Please sign in to comment.