forked from openrewrite/rewrite
-
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.
New
ShortenFullyQualifiedTypeReferences
recipe
Allows to replace fully qualified type references with simple names and a corresponding import, provided that it doesn't result in any conflict. Fixes: openrewrite#3094
- Loading branch information
1 parent
0d3312d
commit 9b11d3f
Showing
2 changed files
with
269 additions
and
0 deletions.
There are no files selected for viewing
164 changes: 164 additions & 0 deletions
164
...t/src/test/java/org/openrewrite/java/cleanup/ShortenFullyQualifiedTypeReferencesTest.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,164 @@ | ||
/* | ||
* Copyright 2023 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.java.cleanup; | ||
|
||
import org.junit.jupiter.api.Test; | ||
import org.openrewrite.test.RecipeSpec; | ||
import org.openrewrite.test.RewriteTest; | ||
|
||
import static org.openrewrite.java.Assertions.java; | ||
|
||
public class ShortenFullyQualifiedTypeReferencesTest implements RewriteTest { | ||
@Override | ||
public void defaults(RecipeSpec spec) { | ||
spec.recipe(new ShortenFullyQualifiedTypeReferences()); | ||
} | ||
|
||
@Test | ||
void redundantImport() { | ||
rewriteRun( | ||
java( | ||
""" | ||
import java.util.List; | ||
class T { | ||
java.util.List<String> list; | ||
} | ||
""", | ||
""" | ||
import java.util.List; | ||
class T { | ||
List<String> list; | ||
} | ||
""" | ||
) | ||
); | ||
} | ||
|
||
@Test | ||
void withinStaticFieldAccess() { | ||
rewriteRun( | ||
java( | ||
""" | ||
class T { | ||
int dotall = java.util.regex.Pattern.DOTALL; | ||
} | ||
""", | ||
""" | ||
import java.util.regex.Pattern; | ||
class T { | ||
int dotall = Pattern.DOTALL; | ||
} | ||
""" | ||
) | ||
); | ||
} | ||
|
||
@Test | ||
void inGenericTypeParameter() { | ||
rewriteRun( | ||
java( | ||
""" | ||
import java.util.List; | ||
class T { | ||
List<java.util.List<String>> list; | ||
} | ||
""", | ||
""" | ||
import java.util.List; | ||
class T { | ||
List<List<String>> list; | ||
} | ||
""" | ||
) | ||
); | ||
} | ||
|
||
@Test | ||
void noImport() { | ||
rewriteRun( | ||
java( | ||
""" | ||
class T { | ||
java.util.List<String> list; | ||
} | ||
""", | ||
""" | ||
import java.util.List; | ||
class T { | ||
List<String> list; | ||
} | ||
""" | ||
) | ||
); | ||
} | ||
|
||
@Test | ||
void multipleConflictingTypesWithoutImport() { | ||
rewriteRun( | ||
java( | ||
""" | ||
class T { | ||
java.util.List<String> list; | ||
java.awt.List list2; | ||
} | ||
""", | ||
""" | ||
import java.util.List; | ||
class T { | ||
List<String> list; | ||
java.awt.List list2; | ||
} | ||
""" | ||
) | ||
); | ||
} | ||
|
||
@Test | ||
void conflictWithLocalType() { | ||
rewriteRun( | ||
java( | ||
""" | ||
class T { | ||
java.util.List<String> list; | ||
class List { | ||
} | ||
} | ||
""" | ||
) | ||
); | ||
} | ||
|
||
@Test | ||
void conflictExistingImport() { | ||
rewriteRun( | ||
java( | ||
""" | ||
import java.awt.List; | ||
class T { | ||
java.util.List<String> list; | ||
} | ||
""" | ||
) | ||
); | ||
} | ||
} |
105 changes: 105 additions & 0 deletions
105
...-java/src/main/java/org/openrewrite/java/cleanup/ShortenFullyQualifiedTypeReferences.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,105 @@ | ||
/* | ||
* Copyright 2023 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.java.cleanup; | ||
|
||
import org.openrewrite.ExecutionContext; | ||
import org.openrewrite.Recipe; | ||
import org.openrewrite.SourceFile; | ||
import org.openrewrite.TreeVisitor; | ||
import org.openrewrite.internal.lang.Nullable; | ||
import org.openrewrite.java.JavaIsoVisitor; | ||
import org.openrewrite.java.JavaVisitor; | ||
import org.openrewrite.java.tree.J; | ||
import org.openrewrite.java.tree.JavaType; | ||
|
||
import java.time.Duration; | ||
import java.util.HashMap; | ||
import java.util.HashSet; | ||
import java.util.Map; | ||
import java.util.Set; | ||
|
||
import static org.openrewrite.java.tree.TypeUtils.isWellFormedType; | ||
|
||
public class ShortenFullyQualifiedTypeReferences extends Recipe { | ||
|
||
@Override | ||
public String getDisplayName() { | ||
return "Add imports for fully qualified references to types"; | ||
} | ||
|
||
@Override | ||
public String getDescription() { | ||
return "Any fully qualified references to Java types will be replaced with corresponding simple " | ||
+ "names and import statements, provided that it doesn't result in " | ||
+ "any conflicts with other imports or types declared in the local compilation unit."; | ||
} | ||
|
||
@Override | ||
public @Nullable Duration getEstimatedEffortPerOccurrence() { | ||
return Duration.ofMinutes(2); | ||
} | ||
|
||
@Override | ||
protected TreeVisitor<?, ExecutionContext> getVisitor() { | ||
return new JavaVisitor<ExecutionContext>() { | ||
final Set<String> localTypes = new HashSet<>(); | ||
final Map<String, JavaType> importedTypes = new HashMap<>(); | ||
final Map<String, JavaType> staticallyImportedMembers = new HashMap<>(); | ||
|
||
@Override | ||
public @Nullable J visitSourceFile(SourceFile sourceFile, ExecutionContext ctx) { | ||
if (sourceFile instanceof J.CompilationUnit) { | ||
J.CompilationUnit cu = (J.CompilationUnit) sourceFile; | ||
JavaIsoVisitor<Set<String>> typeCollector = new JavaIsoVisitor<Set<String>>() { | ||
@Override | ||
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, Set<String> types) { | ||
types.add(classDecl.getSimpleName()); | ||
return super.visitClassDeclaration(classDecl, types); | ||
} | ||
}; | ||
typeCollector.visit(cu, localTypes); | ||
} | ||
return super.visitSourceFile(sourceFile, ctx); | ||
} | ||
|
||
@Override | ||
public J visitImport(J.Import impoort, ExecutionContext ctx) { | ||
if (impoort.isStatic() && isWellFormedType(impoort.getQualid().getType())) { | ||
staticallyImportedMembers.put(impoort.getQualid().getSimpleName(), impoort.getQualid().getType()); | ||
} else if (!impoort.isStatic() && isWellFormedType(impoort.getQualid().getType())) { | ||
importedTypes.put(impoort.getQualid().getSimpleName(), impoort.getQualid().getType()); | ||
} | ||
return impoort; | ||
} | ||
|
||
@Override | ||
public J visitFieldAccess(J.FieldAccess fieldAccess, ExecutionContext ctx) { | ||
JavaType type = fieldAccess.getType(); | ||
if (type instanceof JavaType.Class) { | ||
String simpleName = fieldAccess.getSimpleName(); | ||
if (type.equals(importedTypes.get(simpleName))) { | ||
return fieldAccess.getName().withPrefix(fieldAccess.getPrefix()); | ||
} else if (!importedTypes.containsKey(simpleName) && !localTypes.contains(simpleName)) { | ||
maybeAddImport(((JavaType.FullyQualified) type).getFullyQualifiedName()); | ||
importedTypes.put(simpleName, type); | ||
return fieldAccess.getName().withPrefix(fieldAccess.getPrefix()); | ||
} | ||
} | ||
return super.visitFieldAccess(fieldAccess, ctx); | ||
} | ||
}; | ||
} | ||
} |