Skip to content

Commit

Permalink
fix: Avoid import duplication on unresolved imports (#3730)
Browse files Browse the repository at this point in the history
  • Loading branch information
slarse authored Dec 16, 2020
1 parent 8f86cf9 commit c525fe3
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 1 deletion.
20 changes: 19 additions & 1 deletion src/main/java/spoon/reflect/visitor/ImportCleaner.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import spoon.support.visitor.ClassTypingContext;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
Expand Down Expand Up @@ -198,7 +199,7 @@ void onCompilationUnitProcessed(CtCompilationUnit compilationUnit) {
ModelList<CtImport> existingImports = compilationUnit.getImports();
Set<CtImport> computedImports = new HashSet<>(this.computedImports.values());
topfor: for (CtImport oldImport : new ArrayList<>(existingImports)) {
if (!computedImports.remove(oldImport)) {
if (!removeImport(oldImport, computedImports)) {

// case: import is required in Javadoc
for (CtType type: compilationUnit.getDeclaredTypes()) {
Expand Down Expand Up @@ -253,8 +254,25 @@ void onCompilationUnitProcessed(CtCompilationUnit compilationUnit) {
existingImports.set(existingImports.stream().sorted(importComparator).collect(Collectors.toList()));
}
}

/**
* Remove an import from the given collection based on equality or textual equality.
*/
private boolean removeImport(CtImport toRemove, Collection<CtImport> imports) {
String toRemoveStr = toRemove.toString();
Iterator<CtImport> it = imports.iterator();
while (it.hasNext()) {
CtImport imp = it.next();
if (toRemove.equals(imp) || toRemoveStr.equals(imp.toString())) {
it.remove();
return true;
}
}
return false;
}
}


/**
* @return fast unique identification of reference. It is not the same like printing of import, because it needs to handle access path.
*/
Expand Down
43 changes: 43 additions & 0 deletions src/test/java/spoon/reflect/visitor/ImportCleanerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package spoon.reflect.visitor;

import org.junit.Test;
import spoon.Launcher;
import spoon.reflect.CtModel;
import spoon.reflect.declaration.CtCompilationUnit;
import spoon.reflect.declaration.CtImport;
import spoon.reflect.declaration.CtType;

import java.util.List;
import java.util.stream.Collectors;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;

public class ImportCleanerTest {

@Test
public void testDoesNotDuplicateUnresolvedImports() {
// contract: The import cleaner should not duplicate unresolved imports

// arrange
Launcher launcher = new Launcher();
launcher.addInputResource("./src/test/resources/unresolved/UnresolvedImport.java");
CtModel model = launcher.buildModel();
CtType<?> type = model.getAllTypes().stream().findFirst().get();
CtCompilationUnit cu = type.getFactory().CompilationUnit().getOrCreate(type);
List<String> importsBefore = getTextualImports(cu);

// act
new ImportCleaner().process(cu);

// assert
List<String> importsAfter = getTextualImports(cu);
assertThat(importsAfter, equalTo(importsBefore));
}

private static List<String> getTextualImports(CtCompilationUnit cu) {
return cu.getImports().stream()
.map(CtImport::toString)
.collect(Collectors.toList());
}
}
8 changes: 8 additions & 0 deletions src/test/resources/unresolved/UnresolvedImport.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// this import will be unresolved as the package does not exist
import non.existing.pkg.SomeClass;

public class UnresolvedImport {
public static void main(String[] args) {
SomeClass instance = new SomeClass();
}
}

0 comments on commit c525fe3

Please sign in to comment.