diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f08d3aad5e6..d50cb1998d0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,36 +27,3 @@ jobs: ossrh_token: ${{ secrets.OSSRH_TOKEN }} ossrh_signing_key: ${{ secrets.OSSRH_SIGNING_KEY }} ossrh_signing_password: ${{ secrets.OSSRH_SIGNING_PASSWORD }} -# test-downstream: -# needs: build -# strategy: -# fail-fast: false -# matrix: -# repository: [ rewrite-java-security , rewrite-spring, rewrite-migrate-java ] -# runs-on: ubuntu-latest -# steps: -# - name: Checkout -# uses: actions/checkout@v3 -# with: -# path: rewrite -# fetch-depth: 0 -# - name: Checkout ${{ matrix.repository }} repo -# uses: actions/checkout@v3 -# with: -# repository: openrewrite/${{ matrix.repository }} -# path: ${{ matrix.repository }} -# fetch-depth: 0 -# - name: Setup Java -# uses: actions/setup-java@v3.11.0 -# with: -# distribution: temurin -# java-version: 17 -# - name: Build -# uses: gradle/gradle-build-action@v2 -# with: -# arguments: --console=plain --info --stacktrace --warning-mode=all --no-daemon --include-build ../rewrite build -# build-root-directory: ${{ matrix.repository }} -# env: -# GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} -# GRADLE_ENTERPRISE_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USERNAME }} -# GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }} diff --git a/build.gradle.kts b/build.gradle.kts index eddf8702a4e..330dc566c64 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,23 +1,12 @@ plugins { id("org.openrewrite.build.root") version("latest.release") id("org.openrewrite.build.java-base") version("latest.release") - id("org.openrewrite.rewrite") version("latest.release") } repositories { mavenCentral() } -dependencies { - rewrite(project(":rewrite-core")) -} - -rewrite { - failOnDryRunResults = true - activeRecipe("org.openrewrite.self.Rewrite") -} - - allprojects { group = "org.openrewrite" description = "Eliminate tech-debt. Automatically." diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/search/FindDeprecatedFieldsTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/search/FindDeprecatedFieldsTest.java index 0545ab80ac8..c65a9ea7aca 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/search/FindDeprecatedFieldsTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/search/FindDeprecatedFieldsTest.java @@ -41,7 +41,7 @@ public class D { @Test void ignoreDeprecationsInDeprecatedMethod() { rewriteRun( - spec -> spec.recipe(new FindDeprecatedFields("org.old.types..*", true)), + spec -> spec.recipe(new FindDeprecatedFields("org.old.types..*", null, true)), java( """ import org.old.types.D; @@ -59,7 +59,7 @@ void test(int n) { @Test void ignoreDeprecationsInDeprecatedClass() { rewriteRun( - spec -> spec.recipe(new FindDeprecatedFields("org.old.types..*", true)), + spec -> spec.recipe(new FindDeprecatedFields("org.old.types..*", null, true)), java( """ import org.old.types.D; @@ -79,7 +79,7 @@ void test(int n) { @Test void findDeprecations() { rewriteRun( - spec -> spec.recipe(new FindDeprecatedFields("org.old.types..*", false)), + spec -> spec.recipe(new FindDeprecatedFields("org.old.types..*", null, false)), java( """ import org.old.types.D; diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/search/FindFieldsOfTypeTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/search/FindFieldsOfTypeTest.java index ff484eb36c2..2ad348d9b5f 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/search/FindFieldsOfTypeTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/search/FindFieldsOfTypeTest.java @@ -16,7 +16,8 @@ package org.openrewrite.java.search; import org.junit.jupiter.api.Test; -import org.openrewrite.DocumentExample; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.openrewrite.Issue; import org.openrewrite.test.RewriteTest; @@ -28,7 +29,7 @@ class FindFieldsOfTypeTest implements RewriteTest { @Test void findFieldNotVariable() { rewriteRun( - spec -> spec.recipe(new FindFieldsOfType("java.io.File")), + spec -> spec.recipe(new FindFieldsOfType("java.io.File", null)), java( """ import java.io.*; @@ -42,24 +43,26 @@ public static void main(String[] args) { ); } - @DocumentExample - @Test - void findPrivateNonInheritedField() { + @ParameterizedTest + @ValueSource(strings = {"java.util.List", "java.util.*", "java.util..*"}) + void findPrivateNonInheritedField(String type) { rewriteRun( - spec -> spec.recipe(new FindFieldsOfType("java.util.List")), + spec -> spec.recipe(new FindFieldsOfType(type, null)), java( """ - import java.util.*; + import java.security.SecureRandom; + import java.util.List; public class A { private List list; - private Set set; + private SecureRandom rand; } """, """ - import java.util.*; + import java.security.SecureRandom; + import java.util.List; public class A { /*~~>*/private List list; - private Set set; + private SecureRandom rand; } """ ) @@ -69,7 +72,7 @@ public class A { @Test void findArrayOfType() { rewriteRun( - spec -> spec.recipe(new FindFieldsOfType("java.lang.String")), + spec -> spec.recipe(new FindFieldsOfType("java.lang.String", null)), java( """ import java.util.*; @@ -83,7 +86,7 @@ public class A { /*~~>*/private String[] s; } """ - ) + ) ); } @@ -91,7 +94,7 @@ public class A { @Test void skipsMultiCatches() { rewriteRun( - spec -> spec.recipe(new FindFieldsOfType("java.io.File")), + spec -> spec.recipe(new FindFieldsOfType("java.io.File", null)), java( """ import java.io.*; @@ -116,5 +119,4 @@ public void test() { ) ); } - } diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/search/FindFieldsTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/search/FindFieldsTest.java index 46b28bd77b1..9889442ca50 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/search/FindFieldsTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/search/FindFieldsTest.java @@ -26,7 +26,26 @@ class FindFieldsTest implements RewriteTest { @Override public void defaults(RecipeSpec spec) { - spec.recipe(new FindFields("java.nio.charset.StandardCharsets", "UTF_8")); + spec.recipe(new FindFields("java.nio.charset.StandardCharsets", null,"UTF_8")); + } + + @Test + void fieldMatch() { + rewriteRun( + spec -> spec.recipe(new FindFields("java.nio..*", true, "*")), + java( + """ + class Test { + Object o = java.nio.charset.StandardCharsets.UTF_8; + } + """, + """ + class Test { + Object o = /*~~>*/java.nio.charset.StandardCharsets.UTF_8; + } + """ + ) + ); } @DocumentExample diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/search/FindImplementationsTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/search/FindImplementationsTest.java index 5a108d1e8c9..429af1c3f01 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/search/FindImplementationsTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/search/FindImplementationsTest.java @@ -27,7 +27,7 @@ class FindImplementationsTest implements RewriteTest { @Test void found() { rewriteRun( - spec -> spec.recipe(new FindImplementations("java.lang.Runnable")), + spec -> spec.recipe(new FindImplementations("java.lang.Runnable", null)), java( """ class Test implements Runnable { @@ -50,7 +50,7 @@ public void run() { @Test void notFound() { rewriteRun( - spec -> spec.recipe(new FindImplementations("java.lang.Runnable")), + spec -> spec.recipe(new FindImplementations("java.lang.Runnable", null)), java( """ class Test { @@ -62,10 +62,11 @@ public void run() { ); } + @SuppressWarnings("NullableProblems") @Test void genericType() { rewriteRun( - spec -> spec.recipe(new FindImplementations("java.lang.Comparable")), + spec -> spec.recipe(new FindImplementations("java.lang.Comparable", null)), java( """ class Test implements Comparable { @@ -87,10 +88,11 @@ public int compareTo(String o) { ); } + @SuppressWarnings("NullableProblems") @Test void genericType2() { rewriteRun( - spec -> spec.recipe(new FindImplementations("java.lang.Comparable")), + spec -> spec.recipe(new FindImplementations("java.lang.Comparable", null)), java( """ class Test implements Comparable { @@ -112,10 +114,11 @@ public int compareTo(String o) { ); } + @SuppressWarnings("NullableProblems") @Test void unmatchedGenericType() { rewriteRun( - spec -> spec.recipe(new FindImplementations("java.lang.Comparable")), + spec -> spec.recipe(new FindImplementations("java.lang.Comparable", null)), java( """ class Test implements Comparable { @@ -132,7 +135,7 @@ public int compareTo(String o) { @Test void transitiveImplementsExtends() { rewriteRun( - spec -> spec.recipe(new FindImplementations("org.x.A")), + spec -> spec.recipe(new FindImplementations("org.x.A", null)), java( """ package org.x; @@ -189,7 +192,7 @@ public void bar() { @Test void transitiveExtendsImplements() { rewriteRun( - spec -> spec.recipe(new FindImplementations("org.x.A")), + spec -> spec.recipe(new FindImplementations("org.x.A", null)), java( """ package org.x; diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/search/FindImportsTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/search/FindImportsTest.java index 53ff05fc206..8bcb6657ada 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/search/FindImportsTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/search/FindImportsTest.java @@ -28,7 +28,7 @@ class FindImportsTest implements RewriteTest { @Override public void defaults(RecipeSpec spec) { - spec.recipe(new FindImports("java.util..*")); + spec.recipe(new FindImports("java.util..*", null)); } @Test @@ -79,7 +79,7 @@ class Test { @Test void starImportMatchesExact() { rewriteRun( - spec -> spec.recipe(new FindImports("java.util.List")), + spec -> spec.recipe(new FindImports("java.util.List", null)), java( """ import java.util.*; diff --git a/rewrite-java/src/main/antlr/TemplateParameterLexer.tokens b/rewrite-java/src/main/antlr/TemplateParameterLexer.tokens index c24e72bc9b4..aad1837fbc6 100644 --- a/rewrite-java/src/main/antlr/TemplateParameterLexer.tokens +++ b/rewrite-java/src/main/antlr/TemplateParameterLexer.tokens @@ -1,17 +1,14 @@ LPAREN=1 RPAREN=2 -LBRACK=3 -RBRACK=4 -DOT=5 -COMMA=6 -SPACE=7 -FullyQualifiedName=8 -Number=9 -Identifier=10 +DOT=3 +COLON=4 +COMMA=5 +FullyQualifiedName=6 +Number=7 +Identifier=8 +S=9 '('=1 ')'=2 -'['=3 -']'=4 -'.'=5 -','=6 -' '=7 +'.'=3 +':'=4 +','=5 diff --git a/rewrite-java/src/main/java/org/openrewrite/java/MethodMatcher.java b/rewrite-java/src/main/java/org/openrewrite/java/MethodMatcher.java index 67e469b6630..2df748b65f3 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/MethodMatcher.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/MethodMatcher.java @@ -62,18 +62,21 @@ */ @SuppressWarnings("NotNullFieldNotInitialized") public class MethodMatcher { - private static final JavaType.ShallowClass OBJECT_CLASS = JavaType.ShallowClass.build("java.lang.Object"); private static final String ASPECTJ_DOT_PATTERN = StringUtils.aspectjNameToPattern("."); private static final String ASPECTJ_DOTDOT_PATTERN = StringUtils.aspectjNameToPattern(".."); @Getter private Pattern targetTypePattern; + @Getter private Pattern methodNamePattern; + @Getter private Pattern argumentPattern; + @Nullable private String targetType; + @Nullable private String methodName; @@ -115,11 +118,11 @@ public Void visitMethodPattern(MethodSignatureParser.MethodPatternContext ctx) { } private static boolean isPlainIdentifier(MethodSignatureParser.TargetTypePatternContext context) { - return context.BANG() == null - && context.AND() == null - && context.OR() == null - && context.classNameOrInterface().DOTDOT().isEmpty() - && context.classNameOrInterface().WILDCARD().isEmpty(); + return context.BANG() == null && + context.AND() == null && + context.OR() == null && + context.classNameOrInterface().DOTDOT().isEmpty() && + context.classNameOrInterface().WILDCARD().isEmpty(); } private static boolean isPlainIdentifier(MethodSignatureParser.SimpleNamePatternContext context) { @@ -149,16 +152,16 @@ private boolean matchesTargetTypeName(String fullyQualifiedTypeName) { boolean matchesTargetType(@Nullable JavaType.FullyQualified type) { return TypeUtils.isOfTypeWithName( - type, - matchOverrides, - this::matchesTargetTypeName - ); + type, + matchOverrides, + this::matchesTargetTypeName + ); } @SuppressWarnings("BooleanMethodIsAlwaysInverted") private boolean matchesMethodName(String methodName) { - return this.methodName != null && this.methodName.equals(methodName) - || this.methodName == null && methodNamePattern.matcher(methodName).matches(); + return this.methodName != null && this.methodName.equals(methodName) || + this.methodName == null && methodNamePattern.matcher(methodName).matches(); } private boolean matchesParameterTypes(List parameterTypes) { @@ -206,7 +209,7 @@ public boolean matches(J.MethodDeclaration method, J.ClassDeclaration enclosing) // aspectJUtils does not support matching classes separated by packages. // [^.]* is the product of a fully wild card match for a method. `* foo()` boolean matchesTargetType = (targetType == null && "[^.]*".equals(targetTypePattern.pattern())) - || matchesTargetType(enclosing.getType()); + || matchesTargetType(enclosing.getType()); if (!matchesTargetType) { return false; } @@ -265,8 +268,8 @@ private boolean matchesAllowingUnknownTypes(J.MethodInvocation method) { } if (method.getSelect() != null - && method.getSelect() instanceof J.Identifier - && !matchesSelectBySimpleNameAlone(((J.Identifier) method.getSelect()))) { + && method.getSelect() instanceof J.Identifier + && !matchesSelectBySimpleNameAlone(((J.Identifier) method.getSelect()))) { return false; } @@ -281,11 +284,11 @@ private boolean matchesSelectBySimpleNameAlone(J.Identifier select) { if (targetType != null) { return targetType.equals(select.getSimpleName()) || targetType.endsWith('.' + select.getSimpleName()); } - return targetTypePattern.matcher(select.getSimpleName()).matches() - || Pattern.compile(targetTypePattern.pattern() - .replaceAll(".*" + Pattern.quote(ASPECTJ_DOT_PATTERN), "") - .replaceAll(".*" + Pattern.quote(ASPECTJ_DOTDOT_PATTERN), "")) - .matcher(select.getSimpleName()).matches(); + return targetTypePattern.matcher(select.getSimpleName()).matches() || + Pattern.compile(targetTypePattern.pattern() + .replaceAll(".*" + Pattern.quote(ASPECTJ_DOT_PATTERN), "") + .replaceAll(".*" + Pattern.quote(ASPECTJ_DOTDOT_PATTERN), "")) + .matcher(select.getSimpleName()).matches(); } private String argumentsFromExpressionTypes(J.MethodInvocation method) { @@ -314,8 +317,8 @@ public boolean isFullyQualifiedClassReference(J.FieldAccess fieldAccess) { hopefullyFullyQualifiedMethod = targetType + "." + methodNamePattern.pattern(); } else { hopefullyFullyQualifiedMethod = targetTypePattern.pattern() - .replace(ASPECTJ_DOT_PATTERN, ".") - + "." + methodNamePattern.pattern(); + .replace(ASPECTJ_DOT_PATTERN, ".") + + "." + methodNamePattern.pattern(); } return fieldAccess.isFullyQualifiedClassReference(hopefullyFullyQualifiedMethod); } @@ -327,7 +330,7 @@ private static String typePattern(JavaType type) { return ((JavaType.Primitive) type).getClassName(); } return ((JavaType.Primitive) type).getKeyword(); - } else if(type instanceof JavaType.Unknown) { + } else if (type instanceof JavaType.Unknown) { return "*"; } else if (type instanceof JavaType.FullyQualified) { return ((JavaType.FullyQualified) type).getFullyQualifiedName(); @@ -353,7 +356,7 @@ public static String methodPattern(JavaType.Method method) { } return typePattern(method.getDeclaringType()) + " " + - method.getName() + "(" + parameters + ")"; + method.getName() + "(" + parameters + ")"; } } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/TypeMatcher.java b/rewrite-java/src/main/java/org/openrewrite/java/TypeMatcher.java index 9e450dd136d..c7dceeaa988 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/TypeMatcher.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/TypeMatcher.java @@ -18,6 +18,7 @@ import lombok.Getter; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; +import org.openrewrite.internal.StringUtils; import org.openrewrite.internal.lang.Nullable; import org.openrewrite.java.internal.grammar.MethodSignatureLexer; import org.openrewrite.java.internal.grammar.MethodSignatureParser; @@ -28,41 +29,28 @@ import java.util.regex.Pattern; +import static org.openrewrite.java.tree.TypeUtils.fullyQualifiedNamesAreEqual; + @SuppressWarnings("NotNullFieldNotInitialized") @Getter public class TypeMatcher { + private static final String ASPECTJ_DOT_PATTERN = StringUtils.aspectjNameToPattern("."); + + @SuppressWarnings("NotNullFieldNotInitialized") + @Getter private Pattern targetTypePattern; + @Nullable + private String targetType; + private final String signature; /** - * Whether to match overridden forms of the method on subclasses of {@link #targetTypePattern}. + * Whether to match on subclasses of {@link #targetTypePattern}. */ + @Getter private final boolean matchInherited; - public TypeMatcher(String signature, boolean matchInherited) { - this.signature = signature; - this.matchInherited = matchInherited; - MethodSignatureParser parser = new MethodSignatureParser(new CommonTokenStream(new MethodSignatureLexer( - CharStreams.fromString(signature + " *(..)")))); - - new MethodSignatureParserBaseVisitor() { - @Override - public Void visitMethodPattern(MethodSignatureParser.MethodPatternContext ctx) { - targetTypePattern = Pattern.compile(new TypeVisitor().visitTargetTypePattern(ctx.targetTypePattern())); - return null; - } - }.visit(parser.methodPattern()); - } - - public TypeMatcher(String signature) { - this(signature, false); - } - - public boolean matches(@Nullable JavaType type) { - return matchesTargetType(TypeUtils.asFullyQualified(type)); - } - public boolean matches(@Nullable TypeTree tt) { return tt != null && matches(tt.getType()); } @@ -73,29 +61,52 @@ public boolean matchesPackage(String packageName) { "." + signature.substring(signature.lastIndexOf('.') + 1))).matches(); } - boolean matchesTargetType(@Nullable JavaType.FullyQualified type) { - if (type == null) { - return false; - } - - if (targetTypePattern.matcher(type.getFullyQualifiedName()).matches()) { - return true; - } else if (!"java.lang.Object".equals(type.getFullyQualifiedName()) && matchesTargetType(type.getSupertype() == null ? JavaType.ShallowClass.build("java.lang.Object") : type.getSupertype())) { - return true; - } + public TypeMatcher(String fieldType) { + this(fieldType, false); + } - if (matchInherited) { - if (matchesTargetType(type.getSupertype())) { - return true; - } + public TypeMatcher(String fieldType, boolean matchInherited) { + this.signature = fieldType; + this.matchInherited = matchInherited; - for (JavaType.FullyQualified anInterface : type.getInterfaces()) { - if (matchesTargetType(anInterface)) { - return true; + if (StringUtils.isBlank(fieldType)) { + targetTypePattern = Pattern.compile(".*"); + } else { + MethodSignatureParser parser = new MethodSignatureParser(new CommonTokenStream(new MethodSignatureLexer( + CharStreams.fromString(fieldType)))); + + new MethodSignatureParserBaseVisitor() { + @Override + public Void visitTargetTypePattern(MethodSignatureParser.TargetTypePatternContext ctx) { + String pattern = new TypeVisitor().visitTargetTypePattern(ctx); + targetTypePattern = Pattern.compile(new TypeVisitor().visitTargetTypePattern(ctx)); + targetType = isPlainIdentifier(ctx) + ? pattern.replace(ASPECTJ_DOT_PATTERN, ".").replace("\\", "") + : null; + return null; } - } + }.visitTargetTypePattern(parser.targetTypePattern()); } + } + + public boolean matches(@Nullable JavaType type) { + return TypeUtils.isOfTypeWithName( + TypeUtils.asFullyQualified(type), + matchInherited, + this::matchesTargetTypeName + ); + } + + private boolean matchesTargetTypeName(String fullyQualifiedTypeName) { + return this.targetType != null && fullyQualifiedNamesAreEqual(this.targetType, fullyQualifiedTypeName) || + this.targetType == null && this.targetTypePattern.matcher(fullyQualifiedTypeName).matches(); + } - return false; + private static boolean isPlainIdentifier(MethodSignatureParser.TargetTypePatternContext context) { + return context.BANG() == null && + context.AND() == null && + context.OR() == null && + context.classNameOrInterface().DOTDOT().isEmpty() && + context.classNameOrInterface().WILDCARD().isEmpty(); } } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/search/FindDeprecatedClasses.java b/rewrite-java/src/main/java/org/openrewrite/java/search/FindDeprecatedClasses.java index d9508006e18..e5d9668a27d 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/search/FindDeprecatedClasses.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/search/FindDeprecatedClasses.java @@ -64,7 +64,8 @@ public String getDescription() { @Override public TreeVisitor getVisitor() { - TypeMatcher typeMatcher = typePattern == null ? null : new TypeMatcher(typePattern); + TypeMatcher typeMatcher = typePattern == null ? null : new TypeMatcher(typePattern, + Boolean.TRUE.equals(matchInherited)); return Preconditions.check(new JavaIsoVisitor() { @Override diff --git a/rewrite-java/src/main/java/org/openrewrite/java/search/FindDeprecatedFields.java b/rewrite-java/src/main/java/org/openrewrite/java/search/FindDeprecatedFields.java index 6a4ebe74e65..6e26583abe6 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/search/FindDeprecatedFields.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/search/FindDeprecatedFields.java @@ -42,6 +42,12 @@ public class FindDeprecatedFields extends Recipe { @Nullable String typePattern; + @Option(displayName = "Match inherited", + description = "When enabled, find types that inherit from a deprecated type.", + required = false) + @Nullable + Boolean matchInherited; + @Option(displayName = "Ignore deprecated scopes", description = "When a deprecated method is used in a deprecated method or class, ignore it.", required = false) @@ -60,7 +66,8 @@ public String getDescription() { @Override public TreeVisitor getVisitor() { - TypeMatcher typeMatcher = typePattern == null ? null : new TypeMatcher(typePattern); + TypeMatcher typeMatcher = typePattern == null ? null : new TypeMatcher(typePattern, + Boolean.TRUE.equals(matchInherited)); return Preconditions.check(new JavaIsoVisitor() { @Override diff --git a/rewrite-java/src/main/java/org/openrewrite/java/search/FindDeprecatedUses.java b/rewrite-java/src/main/java/org/openrewrite/java/search/FindDeprecatedUses.java index d9ea02c366a..bddd1ae5759 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/search/FindDeprecatedUses.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/search/FindDeprecatedUses.java @@ -51,7 +51,7 @@ public List getRecipeList() { return Arrays.asList( new FindDeprecatedMethods((typePattern == null || typePattern.isEmpty() ? null : typePattern + " *(..)"), ignoreDeprecatedScopes), new FindDeprecatedClasses(typePattern, matchInherited, ignoreDeprecatedScopes), - new FindDeprecatedFields(typePattern, ignoreDeprecatedScopes) + new FindDeprecatedFields(typePattern, matchInherited, ignoreDeprecatedScopes) ); } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/search/FindFields.java b/rewrite-java/src/main/java/org/openrewrite/java/search/FindFields.java index 60b7be4c5e3..30f190d800f 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/search/FindFields.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/search/FindFields.java @@ -18,11 +18,13 @@ import lombok.EqualsAndHashCode; import lombok.Value; import org.openrewrite.*; +import org.openrewrite.internal.StringUtils; +import org.openrewrite.internal.lang.Nullable; import org.openrewrite.java.JavaIsoVisitor; import org.openrewrite.java.JavaVisitor; +import org.openrewrite.java.TypeMatcher; import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.JavaType; -import org.openrewrite.java.tree.TypeUtils; import org.openrewrite.marker.SearchResult; import java.util.HashSet; @@ -36,6 +38,12 @@ public class FindFields extends Recipe { example = "com.fasterxml.jackson.core.json.JsonWriteFeature") String fullyQualifiedTypeName; + @Option(displayName = "Match inherited", + description = "When enabled, find types that inherit from a deprecated type.", + required = false) + @Nullable + Boolean matchInherited; + @Option(displayName = "Field name", description = "The name of a field on the type.", example = "QUOTE_FIELD_NAMES") @@ -57,8 +65,8 @@ public TreeVisitor getVisitor() { @Override public J.FieldAccess visitFieldAccess(J.FieldAccess fieldAccess, ExecutionContext executionContext) { JavaType.Variable varType = fieldAccess.getName().getFieldType(); - if (varType != null && TypeUtils.isOfClassType(varType.getOwner(), fullyQualifiedTypeName) && - varType.getName().equals(fieldName)) { + if (varType != null && new TypeMatcher(fullyQualifiedTypeName, Boolean.TRUE.equals(matchInherited)).matches(varType.getOwner()) && + StringUtils.matchesGlob(varType.getName(), fieldName)) { return SearchResult.found(fieldAccess); } return super.visitFieldAccess(fieldAccess, executionContext); @@ -68,8 +76,8 @@ public J.FieldAccess visitFieldAccess(J.FieldAccess fieldAccess, ExecutionContex public J.Identifier visitIdentifier(J.Identifier identifier, ExecutionContext executionContext) { J.Identifier i = super.visitIdentifier(identifier, executionContext); JavaType.Variable varType = identifier.getFieldType(); - if (varType != null && TypeUtils.isOfClassType(varType.getOwner(), fullyQualifiedTypeName) && - varType.getName().equals(fieldName)) { + if (varType != null && new TypeMatcher(fullyQualifiedTypeName, Boolean.TRUE.equals(matchInherited)).matches(varType.getOwner()) && + StringUtils.matchesGlob(varType.getName(), fieldName)) { i = SearchResult.found(i); } return i; @@ -79,8 +87,8 @@ public J.Identifier visitIdentifier(J.Identifier identifier, ExecutionContext ex public J.MemberReference visitMemberReference(J.MemberReference memberRef, ExecutionContext ctx) { J.MemberReference m = super.visitMemberReference(memberRef, ctx); JavaType.Variable varType = memberRef.getVariableType(); - if (varType != null && TypeUtils.isOfClassType(varType.getOwner(), fullyQualifiedTypeName) && - varType.getName().equals(fieldName)) { + if (varType != null && new TypeMatcher(fullyQualifiedTypeName, Boolean.TRUE.equals(matchInherited)).matches(varType.getOwner()) && + StringUtils.matchesGlob(varType.getName(), fieldName)) { m = m.withReference(SearchResult.found(m.getReference())); } return m; @@ -94,8 +102,8 @@ public static Set find(J j, String fullyQualifiedTypeName, String fieldName) public J.FieldAccess visitFieldAccess(J.FieldAccess fieldAccess, Set vs) { J.FieldAccess f = super.visitFieldAccess(fieldAccess, vs); JavaType.Variable varType = fieldAccess.getName().getFieldType(); - if (varType != null && TypeUtils.isOfClassType(varType.getOwner(), fullyQualifiedTypeName) && - varType.getName().equals(fieldName)) { + if (varType != null && new TypeMatcher(fullyQualifiedTypeName, true).matches(varType.getOwner()) && + StringUtils.matchesGlob(varType.getName(), fieldName)) { vs.add(f); } return f; @@ -105,8 +113,8 @@ public J.FieldAccess visitFieldAccess(J.FieldAccess fieldAccess, Set vs) { public J.Identifier visitIdentifier(J.Identifier identifier, Set vs) { J.Identifier i = super.visitIdentifier(identifier, vs); JavaType.Variable varType = identifier.getFieldType(); - if (varType != null && TypeUtils.isOfClassType(varType.getOwner(), fullyQualifiedTypeName) && - varType.getName().equals(fieldName)) { + if (varType != null && new TypeMatcher(fullyQualifiedTypeName, true).matches(varType.getOwner()) && + StringUtils.matchesGlob(varType.getName(), fieldName)) { vs.add(i); } return i; @@ -116,8 +124,8 @@ public J.Identifier visitIdentifier(J.Identifier identifier, Set vs) { public J.MemberReference visitMemberReference(J.MemberReference memberRef, Set vs) { J.MemberReference m = super.visitMemberReference(memberRef, vs); JavaType.Variable varType = memberRef.getVariableType(); - if (varType != null && TypeUtils.isOfClassType(varType.getOwner(), fullyQualifiedTypeName) && - varType.getName().equals(fieldName)) { + if (varType != null && new TypeMatcher(fullyQualifiedTypeName, true).matches(varType.getOwner()) && + StringUtils.matchesGlob(varType.getName(), fieldName)) { vs.add(m); } return m; diff --git a/rewrite-java/src/main/java/org/openrewrite/java/search/FindFieldsOfType.java b/rewrite-java/src/main/java/org/openrewrite/java/search/FindFieldsOfType.java index e0461dba4ed..2ea870aed34 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/search/FindFieldsOfType.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/search/FindFieldsOfType.java @@ -20,6 +20,7 @@ import org.openrewrite.*; import org.openrewrite.internal.lang.Nullable; import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.TypeMatcher; import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.JavaType; import org.openrewrite.marker.SearchResult; @@ -40,6 +41,12 @@ public class FindFieldsOfType extends Recipe { example = "org.slf4j.api.Logger") String fullyQualifiedTypeName; + @Option(displayName = "Match inherited", + description = "When enabled, find types that inherit from a deprecated type.", + required = false) + @Nullable + Boolean matchInherited; + @Override public String getDisplayName() { return "Find fields of type"; @@ -59,8 +66,9 @@ public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations m return multiVariable; } if (multiVariable.getTypeExpression() != null && - hasElementType(multiVariable.getTypeExpression().getType(), fullyQualifiedTypeName) && - isField(getCursor())) { + hasElementType(multiVariable.getTypeExpression().getType(), fullyQualifiedTypeName, + Boolean.TRUE.equals(matchInherited)) && + isField(getCursor())) { return SearchResult.found(multiVariable); } return multiVariable; @@ -76,7 +84,7 @@ public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations m return multiVariable; } if (multiVariable.getTypeExpression() != null && - hasElementType(multiVariable.getTypeExpression().getType(), fullyQualifiedTypeName) && + hasElementType(multiVariable.getTypeExpression().getType(), fullyQualifiedTypeName, true) && isField(getCursor())) { vs.add(multiVariable); } @@ -103,20 +111,20 @@ private static boolean isField(Cursor cursor) { return true; } - private static boolean hasElementType(@Nullable JavaType type, String fullyQualifiedName) { + private static boolean hasElementType(@Nullable JavaType type, String fullyQualifiedName, + boolean matchOverrides) { if (type instanceof JavaType.Array) { - return hasElementType(((JavaType.Array) type).getElemType(), fullyQualifiedName); + return hasElementType(((JavaType.Array) type).getElemType(), fullyQualifiedName, matchOverrides); } else if (type instanceof JavaType.FullyQualified) { - return fullyQualifiedName.equals(((JavaType.FullyQualified) type).getFullyQualifiedName()); + return new TypeMatcher(fullyQualifiedName, matchOverrides).matches(type); } else if (type instanceof JavaType.GenericTypeVariable) { JavaType.GenericTypeVariable generic = (JavaType.GenericTypeVariable) type; for (JavaType bound : generic.getBounds()) { - if (hasElementType(bound, fullyQualifiedName)) { + if (hasElementType(bound, fullyQualifiedName, matchOverrides)) { return true; } } } return false; } - } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/search/FindImplementations.java b/rewrite-java/src/main/java/org/openrewrite/java/search/FindImplementations.java index 2de50764442..32bf3e92bcb 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/search/FindImplementations.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/search/FindImplementations.java @@ -21,6 +21,7 @@ import org.openrewrite.Option; import org.openrewrite.Recipe; import org.openrewrite.TreeVisitor; +import org.openrewrite.internal.lang.Nullable; import org.openrewrite.java.JavaIsoVisitor; import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.TypeUtils; @@ -34,6 +35,12 @@ public class FindImplementations extends Recipe { example = "org.openrewrite.Recipe") String interfaceFullyQualifiedName; + @Option(displayName = "Match on inherited types", + description = "When enabled, find methods that are overrides of the method pattern.", + required = false) + @Nullable + Boolean matchInherited; + @Override public String getDisplayName() { return "Find class declarations implementing an interface"; diff --git a/rewrite-java/src/main/java/org/openrewrite/java/search/FindImports.java b/rewrite-java/src/main/java/org/openrewrite/java/search/FindImports.java index 3a4183ca700..e431ec43464 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/search/FindImports.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/search/FindImports.java @@ -21,6 +21,7 @@ import org.openrewrite.Option; import org.openrewrite.Recipe; import org.openrewrite.TreeVisitor; +import org.openrewrite.internal.lang.Nullable; import org.openrewrite.java.JavaIsoVisitor; import org.openrewrite.java.TypeMatcher; import org.openrewrite.java.tree.J; @@ -35,6 +36,12 @@ public class FindImports extends Recipe { required = false) String typePattern; + @Option(displayName = "Match inherited", + description = "When enabled, find types that inherit from a deprecated type.", + required = false) + @Nullable + Boolean matchInherited; + @Override public String getDisplayName() { return "Find source files with imports"; @@ -48,7 +55,7 @@ public String getDescription() { @Override public TreeVisitor getVisitor() { - TypeMatcher typeMatcher = new TypeMatcher(typePattern); + TypeMatcher typeMatcher = new TypeMatcher(typePattern, Boolean.TRUE.equals(matchInherited)); return new JavaIsoVisitor() { @Override public J.Import visitImport(J.Import anImport, ExecutionContext executionContext) { diff --git a/rewrite-java/src/main/java/org/openrewrite/java/search/UsesField.java b/rewrite-java/src/main/java/org/openrewrite/java/search/UsesField.java index 23cba757cb2..9cc53dad760 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/search/UsesField.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/search/UsesField.java @@ -17,12 +17,13 @@ import lombok.RequiredArgsConstructor; import org.openrewrite.Tree; +import org.openrewrite.internal.StringUtils; import org.openrewrite.internal.lang.Nullable; import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.TypeMatcher; import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.JavaSourceFile; import org.openrewrite.java.tree.JavaType; -import org.openrewrite.java.tree.TypeUtils; import org.openrewrite.marker.SearchResult; import static java.util.Objects.requireNonNull; @@ -37,7 +38,8 @@ public J visit(@Nullable Tree tree, P p) { if (tree instanceof JavaSourceFile) { JavaSourceFile cu = (JavaSourceFile) requireNonNull(tree); for (JavaType.Variable variable : cu.getTypesInUse().getVariables()) { - if (variable.getName().equals(field) && TypeUtils.isOfClassType(variable.getOwner(), owner)) { + if (StringUtils.matchesGlob(variable.getName(), field) && + new TypeMatcher(owner, true).matches(variable.getOwner())) { return SearchResult.found(cu); } }