Skip to content
Open
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,54 @@ public abstract class MyMapEntry<K, V> implements Entry<K, V> {
);
}

@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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
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.Objects;
Expand Down Expand Up @@ -100,12 +101,20 @@ 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 also determines what imports are retained, and for fully qualified these can be dropped
return cursor.getValue() instanceof J.FieldAccess &&
cursor.getPathAsStream().anyMatch(o -> o instanceof Javadoc.Reference);
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this code is a bit performance critical, I think we may want to optimize this, so that we also have other parent types, which break the cursor walking. Can we perhaps also break on J.Block?

Also, what if we have a reference to a nested type, like Outer.Inner? It seems like the Outer import would still be required.

Copy link
Member

Choose a reason for hiding this comment

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

Good point, thanks! Added a first loop for the J.Block; haven't yet explored the Outer.Inner, but worst case there we would not remove a stray import, which I'd consider to be fairly niche and perhaps not worth handling separately here.

}
}
}
Loading