Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 36 additions & 4 deletions rewrite-java/src/main/java/org/openrewrite/java/RemoveImport.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,15 @@ public RemoveImport(String type, boolean force) {
Set<String> methodsAndFieldsUsed = new HashSet<>();
Set<String> otherMethodsAndFieldsInTypeUsed = new TreeSet<>();
Set<String> originalImports = new HashSet<>();
Set<String> ownerAndSupertypes = new HashSet<>();
for (J.Import cuImport : cu.getImports()) {
if (cuImport.getQualid().getType() != null) {
originalImports.add(((JavaType.FullyQualified) cuImport.getQualid().getType()).getFullyQualifiedName().replace("$", "."));
JavaType.FullyQualified qualidType = TypeUtils.asFullyQualified(cuImport.getQualid().getType());
if (qualidType != null) {
originalImports.add(qualidType.getFullyQualifiedName().replace("$", "."));
if (TypeUtils.fullyQualifiedNamesAreEqual(qualidType.getFullyQualifiedName(), type) &&
qualidType.getOwningClass() != null) {
collectSupertypeNames(qualidType.getOwningClass(), ownerAndSupertypes);
}
}
}

Expand All @@ -81,8 +87,16 @@ public RemoveImport(String type, boolean force) {
}
}

String importedName = type.substring(type.lastIndexOf('.') + 1);
for (JavaType.Method method : cu.getTypesInUse().getUsedMethods()) {
if (method.hasFlags(Flag.Static)) {
JavaType.FullyQualified methodDeclaringType = method.getDeclaringType();
if (methodDeclaringType != null &&
TypeUtils.fullyQualifiedNamesAreEqual(packageQualifiedName(methodDeclaringType, method.getName()), type)) {
methodsAndFieldsUsed.add(method.getName());
} else if (methodDeclaringType != null && method.getName().equals(importedName) &&
ownerAndSupertypes.contains(TypeUtils.toFullyQualifiedName(methodDeclaringType.getFullyQualifiedName()))) {
methodsAndFieldsUsed.add(method.getName());
} else if (method.hasFlags(Flag.Static)) {
String declaringType = method.getDeclaringType().getFullyQualifiedName();
if (TypeUtils.fullyQualifiedNamesAreEqual(declaringType, type)) {
methodsAndFieldsUsed.add(method.getName());
Expand Down Expand Up @@ -143,7 +157,8 @@ public RemoveImport(String type, boolean force) {
spaceForNextImport.set(import_.getPrefix());
return null;
}
} else if (!keepImport && TypeUtils.fullyQualifiedNamesAreEqual(typeName, type)) {
} else if (!keepImport && TypeUtils.fullyQualifiedNamesAreEqual(typeName, type) &&
!methodsAndFieldsUsed.contains(import_.getQualid().getSimpleName())) {
spaceForNextImport.set(import_.getPrefix());
return null;
} else if (!keepImport && import_.getPackageName().equals(owner) &&
Expand Down Expand Up @@ -184,6 +199,23 @@ public RemoveImport(String type, boolean force) {
return j;
}

private static String packageQualifiedName(JavaType.FullyQualified declaringType, String name) {
String packageName = declaringType.getPackageName();
return packageName.isEmpty() ? name : packageName + "." + name;
}

private static void collectSupertypeNames(JavaType.FullyQualified type, Set<String> names) {
if (!names.add(TypeUtils.toFullyQualifiedName(type.getFullyQualifiedName()))) {
return;
}
for (JavaType.FullyQualified anInterface : type.getInterfaces()) {
collectSupertypeNames(anInterface, names);
}
if (type.getSupertype() != null) {
collectSupertypeNames(type.getSupertype(), names);
}
}

private long countTrailingLinebreaks(Space space) {
return space.getLastWhitespace().chars().filter(s -> s == '\n').count();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.openrewrite.kotlin;

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openrewrite.DocumentExample;
import org.openrewrite.ExecutionContext;
Expand All @@ -24,6 +25,7 @@
import org.openrewrite.test.RewriteTest;
import org.openrewrite.test.TypeValidation;

import static org.openrewrite.java.Assertions.java;
import static org.openrewrite.kotlin.Assertions.kotlin;
import static org.openrewrite.test.RewriteTest.toRecipe;

Expand Down Expand Up @@ -268,4 +270,106 @@ class A
)
);
}

@Test
void keepWhenParentMembersAreUsed() {
rewriteRun(
spec -> spec.recipe(removeTypeImportRecipe("org.example.Child.Companion.one")),
kotlin(
"""
package org.example
interface Shared {
fun one() = "one"
}
open class Parent {
companion object : Shared
}
class Child : Parent() {
companion object : Shared {
fun two() = "two"
}
}
"""
),
kotlin(
"""
import org.example.Child.Companion.one
import org.example.Child.Companion.two

class A {
fun test() {
one()
two()
}
}
"""
)
);
}

@Test
void keepWhenUsingTopLevelFunctions() {
rewriteRun(
spec -> spec.recipe(removeTypeImportRecipe("org.example.one")),
kotlin(
"""
package org.example

fun one() = "one"
fun two() = "two"
"""
),
kotlin(
"""
package org.example2

import org.example.one
import org.example.two

class Aassss {
fun test() {
one()
two()
}
}
"""
)
);
}

@Disabled("We cannot use Java sources as dependencies in Kotlin sources yet")
@Test
void keepStarFoldWhenUsingStaticChildAndParentMembersFromJavaClasses() {
rewriteRun(
// This kind of setup is only possible with a Java <> Kotlin mix, as you cannot use star imports for companion object members
java(
"""
package org.example;
public class Parent {
public static void a() {}
public static void b() {}
}
public class Child extends Parent {
public static void x() {}
public static void y() {}
}
"""
),
kotlin(
"""
import org.example.Child.*
import org.example.Child.a

class A {
fun test() {
a()
b()
x()
y()
}
}
"""
)
);
}
}
Loading