Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -289,11 +289,11 @@ public boolean isEmpty() {
return replacements.isEmpty() && variablesToDelete.isEmpty();
}

public J.InstanceOf processInstanceOf(J.InstanceOf instanceOf, Cursor cursor) {
public J.InstanceOf processInstanceOf(J.InstanceOf instanceOf, Cursor cursor, Set<String> usedNames) {
if (!contextScopes.containsKey(instanceOf)) {
return instanceOf;
}
String name = patternVariableName(instanceOf, cursor);
String name = patternVariableName(instanceOf, cursor, usedNames);
TypedTree typeCastTypeTree = computeTypeTreeFromTypeCasts(instanceOf);
TypedTree currentTypeTree = (TypedTree) instanceOf.getClazz();

Expand Down Expand Up @@ -341,7 +341,7 @@ private TypeTree computeTypeTreeFromTypeCasts(J.InstanceOf instanceOf) {
return typeCastTypeTree;
}

private String patternVariableName(J.InstanceOf instanceOf, Cursor cursor) {
private String patternVariableName(J.InstanceOf instanceOf, Cursor cursor, Set<String> usedNames) {
VariableNameStrategy strategy;
JavaType type = ((TypeTree) instanceOf.getClazz()).getType();
if (root instanceof J.If) {
Expand All @@ -358,6 +358,13 @@ private String patternVariableName(J.InstanceOf instanceOf, Cursor cursor) {
if (root instanceof J.If) {
J.If enclosingIf = cursor.firstEnclosing(J.If.class);
String nameInIfScope = VariableNameUtils.generateVariableName(baseName, new Cursor(cursor, enclosingIf), INCREMENT_NUMBER);

// Also check against other pattern variables being introduced in the same expression
while (usedNames.contains(nameInIfScope)) {
String numStr = nameInIfScope.substring(baseName.length());
nameInIfScope = baseName + (numStr.isEmpty() ? 1 : Integer.parseInt(numStr) + 1);
}

String nameInCursorScope = VariableNameUtils.generateVariableName(baseName, cursor, INCREMENT_NUMBER);
return nameInIfScope.compareTo(nameInCursorScope) >= 0 ? nameInIfScope : nameInCursorScope;
}
Expand Down Expand Up @@ -407,13 +414,22 @@ public J visitBinary(J.Binary binary, Integer p) {
// The left side changed, so the right side should see any introduced variable names
Cursor widenedCursor = updateCursor(b);

// Collect names from the left side if it's an instanceof with a pattern
Set<String> usedNames = new HashSet<>();
if (b.getLeft() instanceof J.InstanceOf) {
J.InstanceOf leftInstanceOf = (J.InstanceOf) b.getLeft();
if (leftInstanceOf.getPattern() != null) {
usedNames.add(((J.Identifier) leftInstanceOf.getPattern()).getSimpleName());
}
}

Expression newRight;
if (binary.getRight() instanceof J.InstanceOf) {
newRight = replacements.processInstanceOf((J.InstanceOf) binary.getRight(), widenedCursor);
newRight = replacements.processInstanceOf((J.InstanceOf) binary.getRight(), widenedCursor, usedNames);
} else if (binary.getRight() instanceof J.Parentheses &&
((J.Parentheses<?>) binary.getRight()).getTree() instanceof J.InstanceOf) {
@SuppressWarnings("unchecked") J.Parentheses<J.InstanceOf> originalRight = (J.Parentheses<J.InstanceOf>) binary.getRight();
newRight = originalRight.withTree(replacements.processInstanceOf(originalRight.getTree(), widenedCursor));
newRight = originalRight.withTree(replacements.processInstanceOf(originalRight.getTree(), widenedCursor, usedNames));
} else {
newRight = (Expression) visitNonNull(binary.getRight(), p, widenedCursor);
}
Expand All @@ -426,7 +442,7 @@ public J visitBinary(J.Binary binary, Integer p) {
@Override
public J.InstanceOf visitInstanceOf(J.InstanceOf instanceOf, Integer p) {
instanceOf = (J.InstanceOf) super.visitInstanceOf(instanceOf, p);
return replacements.processInstanceOf(instanceOf, getCursor());
return replacements.processInstanceOf(instanceOf, getCursor(), new HashSet<>());
}

@Override
Expand Down
116 changes: 86 additions & 30 deletions src/main/resources/META-INF/rewrite/examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ examples:
- description: ''
parameters:
- 'null'
- 'null'
sources:
- before: |
public class PersonBuilder {
Expand Down Expand Up @@ -360,44 +361,44 @@ examples:
- description: ''
sources:
- before: |
import java.io.FileReader;
import java.io.IOException;

class A {
void foo() throws IllegalAccessException {
void foo() throws IOException {
try {
throw new IllegalAccessException();
} catch (Exception e) {
throw e; // `e` is removed below
new FileReader("").read();
} catch (IOException e) {
throw e;
}
}
}
after: |
import java.io.FileReader;
import java.io.IOException;

class A {
void foo() throws IllegalAccessException {
throw new IllegalAccessException();
void foo() throws IOException {
new FileReader("").read();
}
}
language: java
- description: ''
sources:
- before: |
import java.io.FileReader;
import java.io.IOException;

class A {
void foo() throws IOException {
void foo() throws IllegalAccessException {
try {
new FileReader("").read();
} catch (IOException e) {
throw e;
throw new IllegalAccessException();
} catch (Exception e) {
throw e; // `e` is removed below
}
}
}
after: |
import java.io.FileReader;
import java.io.IOException;

class A {
void foo() throws IOException {
new FileReader("").read();
void foo() throws IllegalAccessException {
throw new IllegalAccessException();
}
}
language: java
Expand Down Expand Up @@ -1212,6 +1213,61 @@ examples:
language: java
---
type: specs.openrewrite.org/v1beta/example
recipeName: org.openrewrite.staticanalysis.InstanceOfPatternMatch
examples:
- description: ''
sources:
- before: |
class LeftNode {
int bar() {
return 0;
}
}
class RightNode {
int bar() {
return 1;
}
}

class Foo {
void bar(Object o1, Object o2) {
if (o1 instanceof LeftNode && o2 instanceof RightNode) {
((LeftNode)o1).bar();
((RightNode)o2).bar();
}
else if (o1 instanceof RightNode && o2 instanceof LeftNode) {
((RightNode)o1).bar();
((LeftNode)o2).bar();
}
}
}
after: |
class LeftNode {
int bar() {
return 0;
}
}
class RightNode {
int bar() {
return 1;
}
}

class Foo {
void bar(Object o1, Object o2) {
if (o1 instanceof LeftNode node2 && o2 instanceof RightNode node3) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Surprising to see node2 and node3 before node and node1.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that slightly annoyed me as well, but figured since we're already a few levels deep into edge cases (classes with the same suffix, used in binaries, with an else of overlapping instanceof expressions) I didn't want to explore how to switch those around and risk potentially breaking other logic that had assumed a particular processing order. From a brief look into it it's not as easy as moving down a super.visit call unfortunately.

node2.bar();
node3.bar();
}
else if (o1 instanceof RightNode node && o2 instanceof LeftNode node1) {
node.bar();
node1.bar();
}
}
}
language: java
---
type: specs.openrewrite.org/v1beta/example
recipeName: org.openrewrite.staticanalysis.IsEmptyCallOnCollections
examples:
- description: ''
Expand Down Expand Up @@ -3039,18 +3095,6 @@ examples:
type: specs.openrewrite.org/v1beta/example
recipeName: org.openrewrite.staticanalysis.SimplifyBooleanExpression
examples:
- description: ''
sources:
- before: |
fun getSymbol() : String? {
return null
}
language: kotlin
- before: |
val isPositive = getSymbol().equals("+") == true
after: |
val isPositive = getSymbol().equals("+")
language: kotlin
- description: ''
sources:
- before: |
Expand All @@ -3070,6 +3114,18 @@ examples:
}
}
language: java
- description: ''
sources:
- before: |
fun getSymbol() : String? {
return null
}
language: kotlin
- before: |
val isPositive = getSymbol().equals("+") == true
after: |
val isPositive = getSymbol().equals("+")
language: kotlin
---
type: specs.openrewrite.org/v1beta/example
recipeName: org.openrewrite.staticanalysis.SimplifyBooleanExpressionWithDeMorgan
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.openrewrite.DocumentExample;
import org.openrewrite.Issue;
import org.openrewrite.test.RecipeSpec;
import org.openrewrite.test.RewriteTest;
Expand All @@ -33,6 +34,66 @@ public void defaults(RecipeSpec spec) {
.allSources(sourceSpec -> version(sourceSpec, 17));
}

@DocumentExample
@Issue("https://github.com/openrewrite/rewrite-static-analysis/issues/619")
@Test
void variableNamingConflictWithMultipleInstanceOf() {
rewriteRun(
//language=java
java(
"""
class LeftNode {
int bar() {
return 0;
}
}
class RightNode {
int bar() {
return 1;
}
}

class Foo {
void bar(Object o1, Object o2) {
if (o1 instanceof LeftNode && o2 instanceof RightNode) {
((LeftNode)o1).bar();
((RightNode)o2).bar();
}
else if (o1 instanceof RightNode && o2 instanceof LeftNode) {
((RightNode)o1).bar();
((LeftNode)o2).bar();
}
}
}
""",
"""
class LeftNode {
int bar() {
return 0;
}
}
class RightNode {
int bar() {
return 1;
}
}

class Foo {
void bar(Object o1, Object o2) {
if (o1 instanceof LeftNode node2 && o2 instanceof RightNode node3) {
node2.bar();
node3.bar();
}
else if (o1 instanceof RightNode node && o2 instanceof LeftNode node1) {
node.bar();
node1.bar();
}
}
}
"""
)
);
}

@Nested
class If {
Expand Down