Skip to content

Commit

Permalink
fix(ImportCleaner): resolve imports of parent types (#4353)
Browse files Browse the repository at this point in the history
  • Loading branch information
algomaster99 authored Dec 15, 2021
1 parent 4ccae4f commit dbb1841
Show file tree
Hide file tree
Showing 4 changed files with 366 additions and 4 deletions.
33 changes: 29 additions & 4 deletions src/main/java/spoon/reflect/visitor/ImportCleaner.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import spoon.support.Experimental;
import spoon.support.util.ModelList;
import spoon.support.visitor.ClassTypingContext;
import spoon.support.visitor.equals.EqualsVisitor;

import java.util.ArrayList;
import java.util.Collection;
Expand Down Expand Up @@ -176,15 +177,23 @@ void addImport(CtReference ref) {
// we would like to add an import, but we don't know to where
return;
}
if (ref instanceof CtFieldReference<?>
&& !isReferenceToFieldPresentInImports((CtFieldReference<?>) ref)) {
if (ref instanceof CtFieldReference<?> && !isReferencePresentInImports(ref)) {
return;
}
CtTypeReference<?> topLevelTypeRef = typeRef.getTopLevelType();
if (typeRefQNames.contains(topLevelTypeRef.getQualifiedName())) {
//it is reference to a type of this CompilationUnit. Do not add it
return;
}
if (ref instanceof CtTypeReference<?>
&& !isReferencePresentInImports(topLevelTypeRef)
&& topLevelTypeRef != ref
&& !isReferencePresentInImports(ref)) {
// check if a top level type has been imported
// if it has been, we don't need to add a separate import for its subtype
// last condition ensures that if only the subtype has been imported, we do not remove it
return;
}
CtPackageReference packageRef = topLevelTypeRef.getPackage();
if (packageRef == null) {
return;
Expand All @@ -210,10 +219,26 @@ void addImport(CtReference ref) {
}
}

private boolean isReferenceToFieldPresentInImports(CtFieldReference ref) {
private boolean isReferencePresentInImports(CtReference ref) {
return compilationUnit.getImports()
.stream()
.anyMatch(ctImport -> ctImport.getReference() != null && ctImport.getReference().equals(ref));
.anyMatch(ctImport -> ctImport.getReference() != null
&& isEqualAfterSkippingRole(ctImport.getReference(), ref, CtRole.TYPE_ARGUMENT));
}

/**
* Checks if element and other are equal if comparison for `role` value is skipped
*/
private boolean isEqualAfterSkippingRole(CtElement element, CtElement other, CtRole role) {
EqualsVisitor equalsVisitor = new EqualsVisitor();
boolean isEqual = equalsVisitor.checkEquals(element, other);
if (isEqual) {
return true;
}
if (role == equalsVisitor.getNotEqualRole()) {
return true;
}
return false;
}

void onCompilationUnitProcessed(CtCompilationUnit compilationUnit) {
Expand Down
12 changes: 12 additions & 0 deletions src/test/java/spoon/reflect/visitor/ImportCleanerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@

public class ImportCleanerTest {

@Test
void testDoesNotRemoveImportOfSubType() {
// contract: The import cleaner should not remove import of subtype if it is used by its simply qualified name
testImportCleanerDoesNotAlterImports("src/test/resources/importCleaner/DoNotRemoveSubType.java", "importCleaner.DoNotRemoveSubType");
}

@Test
void testDoesNotImportTypeWhoseParentTypeIsAlreadyImported() {
// contract: The import cleaner should not import the subtype if its parent has already been imported
testImportCleanerDoesNotAlterImports("src/test/resources/importCleaner/TypeImportButUseSubType.java", "importCleaner.TypeImportButUseSubType");
}

@Test
void testDoesNotRemoveImportForStaticFieldOfStaticClass() {
// contract: The import cleaner should not remove import of the static field
Expand Down
9 changes: 9 additions & 0 deletions src/test/resources/importCleaner/DoNotRemoveSubType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package importCleaner;

import java.util.Map.Entry;

public class DoNotRemoveSubType {
public void hey() {
Entry<String, String> f = null;
}
}
Loading

0 comments on commit dbb1841

Please sign in to comment.