forked from openrewrite/rewrite-static-analysis
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add recipe
ReplaceClassIsInstanceWithInstanceof
for SonarQube RSPEC…
…-6202 (openrewrite#381) * add: recipe for RSPEC-S1170, adding "static" to "public final" constants and fields * add: recipe and unit test for RSPEC-S6202 * update: add recipe to list * fix: correct the name of the recipe * update: for more cases in unit test * update: correct copyright messages * refactor: format code * Update src/test/java/org/openrewrite/staticanalysis/ReplaceClassIsInstanceWithInstanceofTest.java Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update src/test/java/org/openrewrite/staticanalysis/ReplaceClassIsInstanceWithInstanceofTest.java Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update src/test/java/org/openrewrite/staticanalysis/ReplaceClassIsInstanceWithInstanceofTest.java Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update src/main/java/org/openrewrite/staticanalysis/ReplaceClassIsInstanceWithInstanceof.java Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update src/main/java/org/openrewrite/staticanalysis/ReplaceClassIsInstanceWithInstanceof.java Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update src/main/java/org/openrewrite/staticanalysis/ReplaceClassIsInstanceWithInstanceof.java Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update src/main/java/org/openrewrite/staticanalysis/AddStaticModifierToPublicFinalConstantsAndFields.java Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update src/main/java/org/openrewrite/staticanalysis/AddStaticModifierToPublicFinalConstantsAndFields.java Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Test additional cases pointed out in review * Format tests * Slight polish to ReplaceClassIsInstanceWithInstanceof * Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * update: Recipe for RSPEC-S1170 is removed because it needs further consideration, so we will do it in another PR * Minor polish --------- Co-authored-by: Sheng Yu <[email protected]> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Tim te Beek <[email protected]> Co-authored-by: Tim te Beek <[email protected]>
- Loading branch information
1 parent
be381dc
commit 286d4ee
Showing
3 changed files
with
203 additions
and
0 deletions.
There are no files selected for viewing
86 changes: 86 additions & 0 deletions
86
src/main/java/org/openrewrite/staticanalysis/ReplaceClassIsInstanceWithInstanceof.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
/* | ||
* Copyright 2024 the original author or authors. | ||
* <p> | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* <p> | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* <p> | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.openrewrite.staticanalysis; | ||
|
||
import org.jspecify.annotations.Nullable; | ||
import org.openrewrite.ExecutionContext; | ||
import org.openrewrite.Recipe; | ||
import org.openrewrite.java.JavaTemplate; | ||
import org.openrewrite.java.JavaVisitor; | ||
import org.openrewrite.java.MethodMatcher; | ||
import org.openrewrite.java.tree.Expression; | ||
import org.openrewrite.java.tree.J; | ||
import org.openrewrite.java.tree.J.FieldAccess; | ||
import org.openrewrite.java.tree.J.Identifier; | ||
import org.openrewrite.java.tree.J.MethodInvocation; | ||
import org.openrewrite.java.tree.JavaType; | ||
|
||
import java.util.Collections; | ||
import java.util.Set; | ||
|
||
public class ReplaceClassIsInstanceWithInstanceof extends Recipe { | ||
|
||
@Override | ||
public String getDisplayName() { | ||
return "Replace `A.class.isInstance(a)` with `a instanceof A`"; | ||
} | ||
|
||
@Override | ||
public String getDescription() { | ||
return "There should be no `A.class.isInstance(a)`, it should be replaced by `a instanceof A`."; | ||
} | ||
|
||
@Override | ||
public Set<String> getTags() { | ||
return Collections.singleton("RSPEC-S6202"); | ||
} | ||
|
||
@Override | ||
public JavaVisitor<ExecutionContext> getVisitor() { | ||
// use JavaVisitor instead of JavaIsoVisitor because we changed the type of LST | ||
return new JavaVisitor<ExecutionContext>() { | ||
|
||
private final MethodMatcher matcher = new MethodMatcher("java.lang.Class isInstance(java.lang.Object)"); | ||
|
||
@Override | ||
public J visitMethodInvocation(MethodInvocation method, ExecutionContext ctx) { | ||
// make sure we find the right method and the left part is something like "SomeClass.class" | ||
if (matcher.matches(method) && isObjectClass(method.getSelect())) { | ||
// for code like "A.class.isInstance(a)", select is "String.class", name is "isInstance", argument is "a" | ||
Identifier objectExpression = (Identifier) method.getArguments().get(0); | ||
FieldAccess fieldAccessPart = (FieldAccess) method.getSelect(); | ||
String className = ((JavaType.Class) fieldAccessPart.getTarget().getType()).getClassName(); | ||
// upcast to type J, so J.MethodInvocation can be replaced by J.InstanceOf | ||
J.InstanceOf instanceOf = JavaTemplate.apply("#{any(org.openrewrite.java.tree.Expression)} instanceof #{}", | ||
getCursor(), method.getCoordinates().replace(), objectExpression, className); | ||
return maybeAutoFormat(method, instanceOf, ctx); | ||
} | ||
return super.visitMethodInvocation(method, ctx); | ||
} | ||
|
||
private boolean isObjectClass(@Nullable Expression expression) { | ||
if (expression instanceof J.FieldAccess) { | ||
J.FieldAccess fieldAccess = (J.FieldAccess) expression; | ||
if (fieldAccess.getTarget() instanceof Identifier) { | ||
Identifier identifier = (Identifier) fieldAccess.getTarget(); | ||
return identifier.getType() instanceof JavaType.Class; | ||
} | ||
} | ||
return false; | ||
} | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
116 changes: 116 additions & 0 deletions
116
src/test/java/org/openrewrite/staticanalysis/ReplaceClassIsInstanceWithInstanceofTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
/* | ||
* Copyright 2024 the original author or authors. | ||
* <p> | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* <p> | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* <p> | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.openrewrite.staticanalysis; | ||
|
||
import org.junit.jupiter.api.Test; | ||
import org.openrewrite.DocumentExample; | ||
import org.openrewrite.test.RecipeSpec; | ||
import org.openrewrite.test.RewriteTest; | ||
|
||
import static org.openrewrite.java.Assertions.java; | ||
import static org.openrewrite.java.Assertions.javaVersion; | ||
|
||
@SuppressWarnings({"RedundantClassCall", "ConstantValue", "UnusedAssignment"}) | ||
class ReplaceClassIsInstanceWithInstanceofTest implements RewriteTest { | ||
|
||
@Override | ||
public void defaults(RecipeSpec spec) { | ||
spec.recipe(new ReplaceClassIsInstanceWithInstanceof()); | ||
} | ||
|
||
@Test | ||
@DocumentExample | ||
void changeInstanceOf() { | ||
rewriteRun( | ||
//language=java | ||
java( | ||
""" | ||
class A { | ||
void foo() { | ||
String s = ""; | ||
boolean result = String.class.isInstance(s); | ||
result = Integer.class.isInstance(s); | ||
} | ||
} | ||
""", | ||
""" | ||
class A { | ||
void foo() { | ||
String s = ""; | ||
boolean result = s instanceof String; | ||
result = s instanceof Integer; | ||
} | ||
} | ||
""" | ||
) | ||
); | ||
} | ||
|
||
@Test | ||
void doNotChangeWhenAlreadyInstanceOf() { | ||
rewriteRun( | ||
//language=java | ||
java( | ||
""" | ||
class A { | ||
boolean foo() { | ||
String s = ""; | ||
return s instanceof String; | ||
} | ||
} | ||
""" | ||
) | ||
); | ||
} | ||
|
||
@Test | ||
void doNotChangeWhenVariable() { | ||
rewriteRun( | ||
//language=java | ||
java( | ||
""" | ||
class A { | ||
void foo(Class<?> clazz) { | ||
String s = ""; | ||
boolean result = clazz.isInstance(s); | ||
} | ||
} | ||
""" | ||
) | ||
); | ||
} | ||
|
||
@Test | ||
void doNotChangeInstanceOfWithVariable() { | ||
rewriteRun( | ||
//language=java | ||
java( | ||
""" | ||
class A { | ||
String foo(Object obj) { | ||
if (obj instanceof String s) { | ||
return s; | ||
} | ||
return null; | ||
} | ||
} | ||
""", | ||
spec -> spec.markers(javaVersion(17)) | ||
) | ||
); | ||
} | ||
|
||
} |