diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/RemoveUnusedImportsTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/RemoveUnusedImportsTest.java index 82052abfe4..be6ea2a463 100755 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/RemoveUnusedImportsTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/RemoveUnusedImportsTest.java @@ -132,6 +132,54 @@ public abstract class MyMapEntry implements Entry { ); } + @Test + void retainImportIfUsedInJavaDoc() { + rewriteRun( + java( + """ + import java.util.Date; + import java.util.List; + + /** + * referencing {@link Date} only in doc + */ + class Test { + List list; + } + """ + ) + ); + } + + @Test + void removeImportIfFullyQualifiedInJavaDoc() { + rewriteRun( + java( + """ + import java.util.Date; + import java.util.List; + + /** + * referencing {@link java.util.Date} only in doc + */ + class Test2 { + List list; + } + """, + """ + import java.util.List; + + /** + * referencing {@link java.util.Date} only in doc + */ + class Test2 { + List list; + } + """ + ) + ); + } + @Issue("https://github.com/openrewrite/rewrite/issues/1052") @Test void usedInJavadocWithThrows() { diff --git a/rewrite-java/src/main/java/org/openrewrite/java/internal/TypesInUse.java b/rewrite-java/src/main/java/org/openrewrite/java/internal/TypesInUse.java index 6dce7c0000..a507a4ad60 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/internal/TypesInUse.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/internal/TypesInUse.java @@ -24,8 +24,10 @@ import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.JavaSourceFile; import org.openrewrite.java.tree.JavaType; +import org.openrewrite.java.tree.Javadoc; import java.util.IdentityHashMap; +import java.util.Iterator; import java.util.Objects; import java.util.Set; @@ -100,12 +102,31 @@ public J.Lambda.Parameters visitLambdaParameters(J.Lambda.Parameters parameters, } else { usedMethods.add((JavaType.Method) javaType); } - } else if (!(cursor.getValue() instanceof J.ClassDeclaration) && !(cursor.getValue() instanceof J.Lambda)) { - // ignore type representing class declaration itself and inferred lambda types + } else if (!(cursor.getValue() instanceof J.ClassDeclaration) && + !(cursor.getValue() instanceof J.Lambda) && + !isFullyQualifiedJavaDocReference(cursor)) { types.add(javaType); } } return javaType; } + + private boolean isFullyQualifiedJavaDocReference(Cursor cursor) { + // Fully qualified Javadoc references are _using_ those types as much as they are just references; + // TypesInUse entries determines what imports are retained, and for fully qualified these can be dropped + if (cursor.getValue() instanceof J.FieldAccess) { + Iterator path = cursor.getPath(); + while (path.hasNext()) { + Object o = path.next(); + if (o instanceof Javadoc.Reference) { + return true; + } + if (o instanceof J.Block) { + return false; + } + } + } + return false; + } } }