diff --git a/core/src/main/java/com/google/googlejavaformat/java/RemoveUnusedImports.java b/core/src/main/java/com/google/googlejavaformat/java/RemoveUnusedImports.java index 8c3cae319..a47a73a7a 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/RemoveUnusedImports.java +++ b/core/src/main/java/com/google/googlejavaformat/java/RemoveUnusedImports.java @@ -273,6 +273,8 @@ private static RangeMap buildReplacements( Set usedNames, Multimap> usedInJavadoc) { RangeMap replacements = TreeRangeMap.create(); + int size = unit.getImports().size(); + JCTree lastImport = size > 0 ? unit.getImports().get(size - 1) : null; for (JCTree importTree : unit.getImports()) { String simpleName = getSimpleName(importTree); if (!isUnused(unit, usedNames, usedInJavadoc, importTree, simpleName)) { @@ -286,6 +288,12 @@ private static RangeMap buildReplacements( && contents.subSequence(endPosition, endPosition + sep.length()).toString().equals(sep)) { endPosition += sep.length(); } + if (size == 1 || importTree != lastImport) { + while (endPosition + sep.length() <= contents.length() + && contents.regionMatches(endPosition, sep, 0, sep.length())) { + endPosition += sep.length(); + } + } replacements.put(Range.closedOpen(importTree.getStartPosition(), endPosition), ""); } return replacements; @@ -306,10 +314,13 @@ private static boolean isUnused( if (qualifier.equals("java.lang")) { return true; } + if(usedNames.contains(simpleName)){ + return false; + } if (unit.getPackageName() != null && unit.getPackageName().toString().equals(qualifier)) { return true; } - if (qualifiedIdentifier.getIdentifier().contentEquals("*")) { + if (qualifiedIdentifier.getIdentifier().contentEquals("*") && !((JCImport) importTree).isStatic()) { return false; } diff --git a/core/src/test/java/com/google/googlejavaformat/java/RemoveUnusedImportsTest.java b/core/src/test/java/com/google/googlejavaformat/java/RemoveUnusedImportsTest.java index 675bc8884..47d7b7871 100644 --- a/core/src/test/java/com/google/googlejavaformat/java/RemoveUnusedImportsTest.java +++ b/core/src/test/java/com/google/googlejavaformat/java/RemoveUnusedImportsTest.java @@ -28,257 +28,509 @@ /** {@link RemoveUnusedImports}Test */ @RunWith(Parameterized.class) public class RemoveUnusedImportsTest { - @Parameters(name = "{index}: {0}") - public static Collection parameters() { - String[][][] inputsOutputs = { - { - { - "import java.util.List;", - "import java.util.ArrayList;", - "", - "class Test {", - " /** could be an {@link ArrayList} */", - " List xs;", - "}", - }, - { - "import java.util.List;", - "import java.util.ArrayList;", - "", - "class Test {", - " /** could be an {@link ArrayList} */", - " List xs;", - "}", - }, - }, - { - { - "import java.util.ArrayList;", // - "import java.util.Collection;", - "/** {@link ArrayList#add} {@link Collection#remove(Object)} */", - "class Test {}", - }, - { - "import java.util.ArrayList;", // - "import java.util.Collection;", - "/** {@link ArrayList#add} {@link Collection#remove(Object)} */", - "class Test {}", - }, - }, - { - { - "import a.A;", - "import a.B;", - "import a.C;", - "class Test {", - " /** a", - " * {@link A} */", - " void f() {}", - "}", - }, - { - "import a.A;", // - "class Test {", - " /** a", - " * {@link A} */", - " void f() {}", - "}", - }, - }, - { - { - "import a.A;import a.B;", // - "import a.C; // hello", - "class Test {", - " B b;", - "}", - }, - { - "import a.B;", // - "// hello", - "class Test {", - " B b;", - "}", - }, - }, - { - { - "import a.A;", - "import b.B;", - "import c.C;", - "import d.D;", - "import e.E;", - "import f.F;", - "import g.G;", - "import h.H;", - "/**", - " * {@link A} {@linkplain B} {@value D#FOO}", - " *", - " * @exception E", - " * @throws F", - " * @see C", - " * @see H#foo", - " * @see ", - " */", - "class Test {", - "}", - }, - { - "import a.A;", - "import b.B;", - "import c.C;", - "import d.D;", - "import e.E;", - "import f.F;", - "import h.H;", - "/**", - " * {@link A} {@linkplain B} {@value D#FOO}", - " *", - " * @exception E", - " * @throws F", - " * @see C", - " * @see H#foo", - " * @see ", - " */", - "class Test {", - "}", - }, - }, - { - { - "import java.util.Map;", - "/** {@link Map.Entry#containsKey(Object)} } */", - "class Test {}", - }, - { - "import java.util.Map;", - "/** {@link Map.Entry#containsKey(Object)} } */", - "class Test {}", - }, - }, - { - { - "/** {@link #containsKey(Object)} } */", // - "class Test {}", - }, - { - "/** {@link #containsKey(Object)} } */", // - "class Test {}", - }, - }, - { - { - "import java.util.*;", // - "class Test {", - " List xs;", - "}", - }, - { - "import java.util.*;", // - "class Test {", - " List xs;", - "}", - }, - }, - { - { - "package com.foo;", - "import static com.foo.Outer.A;", - "import com.foo.*;", - "import com.foo.B;", - "import com.bar.C;", - "class Test {", - " A a;", - " B b;", - " C c;", - "}", - }, - { - "package com.foo;", - "import static com.foo.Outer.A;", - "import com.bar.C;", - "class Test {", - " A a;", - " B b;", - " C c;", - "}", + @Parameters(name = "{index}: {0}") + public static Collection parameters() { + String[][][] inputsOutputs = { + { + { + """ + import java.util.List; + import java.util.ArrayList; + + class Test { + /** could be an {@link ArrayList} */ + List xs; + } + """ + }, + { + """ + import java.util.List; + import java.util.ArrayList; + + class Test { + /** could be an {@link ArrayList} */ + List xs; + } + """ + } + }, + { + { + """ + import java.util.ArrayList; + import java.util.Collection; + /** {@link ArrayList#add} {@link Collection#remove(Object)} */ + class Test {} + """ + }, + { + """ + import java.util.ArrayList; + import java.util.Collection; + /** {@link ArrayList#add} {@link Collection#remove(Object)} */ + class Test {} + """ + } + }, + { + { + """ + import a.A; + import a.B; + import a.C; + class Test { + /** a + * {@link A} */ + void f() {} + } + """ + }, + { + """ + import a.A; + class Test { + /** a + * {@link A} */ + void f() {} + } + """ + } + }, + { + { + """ + import a.A;import a.B; + import a.C; // hello + class Test { + B b; + } + """ + }, + { + """ + import a.B; + // hello + class Test { + B b; + } + """ + } + }, + { + { + """ + import a.A; + import b.B; + import c.C; + import d.D; + import e.E; + import f.F; + import g.G; + import h.H; + /** + * {@link A} {@linkplain B} {@value D#FOO} + * + * @exception E + * @throws F + * @see C + * @see H#foo + * @see + */ + class Test { + } + """ + }, + { + """ + import a.A; + import b.B; + import c.C; + import d.D; + import e.E; + import f.F; + import h.H; + /** + * {@link A} {@linkplain B} {@value D#FOO} + * + * @exception E + * @throws F + * @see C + * @see H#foo + * @see + */ + class Test { + } + """ + } + }, + { + { + """ + import java.util.Map; + /** {@link Map.Entry#containsKey(Object)} } */ + class Test {} + """ + }, + { + """ + import java.util.Map; + /** {@link Map.Entry#containsKey(Object)} } */ + class Test {} + """ + } + }, + { + { + """ + /** {@link #containsKey(Object)} } */ + class Test {} + """ + }, + { + """ + /** {@link #containsKey(Object)} } */ + class Test {} + """ + } + }, + { + { + """ + import java.util.*; + class Test { + List xs; + } + """ + }, + { + """ + import java.util.*; + class Test { + List xs; + } + """ + } + }, + { + { + """ + package com.foo; + import static com.foo.Outer.A; + import com.foo.*; + import com.foo.B; + import com.bar.C; + class Test { + A a; + B b; + C c; + } + """ + }, + { + """ + package com.foo; + import static com.foo.Outer.A; + import com.foo.B; + import com.bar.C; + class Test { + A a; + B b; + C c; + } + """ + } + }, + { + { + """ + import java.util.Map; + import java.util.Map.Entry; + /** {@link #foo(Map.Entry[])} */ + public class Test {} + """ + }, + { + """ + import java.util.Map; + /** {@link #foo(Map.Entry[])} */ + public class Test {} + """ + } + }, + { + { + """ + import java.util.List; + import java.util.Collection; + /** {@link java.util.List#containsAll(Collection)} */ + public class Test {} + """ + }, + { + """ + import java.util.Collection; + /** {@link java.util.List#containsAll(Collection)} */ + public class Test {} + """ + } + }, + { + { + """ + import java.lang.Foo; + interface Test { private static void foo() {} } + """ + }, + { + """ + interface Test { private static void foo() {} } + """ + } + }, + { + { + """ + package test.pkg; + + import static test.pkg.Constants.FOO; + import static test.pkg.Constants.BAR; + + import java.util.List; + import java.util.ArrayList; + + public class Test { + public static final String VALUE = FOO; + } + """ + }, + { + """ + package test.pkg; + + import static test.pkg.Constants.FOO; + + public class Test { + public static final String VALUE = FOO; + } + """ + } + }, + { + { + """ + import java.util.List; + import java.util.Collections; + + class Test { + void foo() { + List list = Collections.emptyList(); + } + } + """ + }, + { + """ + import java.util.List; + import java.util.Collections; + + class Test { + void foo() { + List list = Collections.emptyList(); + } + } + """ + } + }, + { + { + """ + import java.util.List; + import java.util.ArrayList; + import java.util.Collections; + + class Test { + List list = new ArrayList<>(); + } + """ + }, + { + """ + import java.util.List; + import java.util.ArrayList; + + class Test { + List list = new ArrayList<>(); + } + """ + } + }, + { + { + """ + import static java.util.Collections.*; + import static java.util.Collections.emptyList; + + class Test { + void foo() { + emptyList(); + } + } + """ + }, + { + """ + import static java.util.Collections.emptyList; + + class Test { + void foo() { + emptyList(); + } + } + """ + } + }, + { + { + """ + import java.util.List; + import java.util.function.Function; + + class Test { + Function, String> f; + } + """ + }, + { + """ + import java.util.List; + import java.util.function.Function; + + class Test { + Function, String> f; + } + """ + } + }, + { + { + """ + import a.Outer.Inner; + import a.Outer; + + class Test { + Inner i; + } + """ + }, + { + """ + import a.Outer.Inner; + + class Test { + Inner i; + } + """ + } + }, + { + { + """ + import java.util.HashMap; + + class Test { + java.util.Map map = new java.util.HashMap<>(); + } + """ + }, + { + """ + class Test { + java.util.Map map = new java.util.HashMap<>(); + } + """ + } + }, + { + { + """ + import java.util.Map; + + class Test { + Map.Entry entry; + } + """ + }, + { + """ + import java.util.Map; + + class Test { + Map.Entry entry; + } + """ + } + }, + { + { + """ + import static java.lang.Math.*; + import static java.lang.Math.PI; + + class Test { + double r = PI; + } + """ + }, + { + """ + import static java.lang.Math.PI; + + class Test { + double r = PI; + } + """ + } + }, + { + { + """ + import java.util.ArrayList; + + // This is a comment mentioning ArrayList + class Test {} + """ + }, + { + """ + // This is a comment mentioning ArrayList + class Test {} + """ + } + } + }; + + ImmutableList.Builder builder = ImmutableList.builder(); + for (String[][] inputAndOutput : inputsOutputs) { + assertThat(inputAndOutput).hasLength(2); + builder.add(new String[]{ + Joiner.on('\n').join(inputAndOutput[0]) + '\n', + Joiner.on('\n').join(inputAndOutput[1]) + '\n', + }); } - }, - { - { - "import java.util.Map;", // - "import java.util.Map.Entry;", - "/** {@link #foo(Map.Entry[])} */", - "public class Test {}", - }, - { - "import java.util.Map;", // - "/** {@link #foo(Map.Entry[])} */", - "public class Test {}", - }, - }, - { - { - "import java.util.List;", - "import java.util.Collection;", - "/** {@link java.util.List#containsAll(Collection)} */", - "public class Test {}", - }, - { - "import java.util.Collection;", - "/** {@link java.util.List#containsAll(Collection)} */", - "public class Test {}", - }, - }, - { - { - "package p;", - "import java.lang.Foo;", - "import java.lang.Foo.Bar;", - "import p.Baz;", - "import p.Baz.Bork;", - "public class Test implements Foo, Bar, Baz, Bork {}", - }, - { - "package p;", - "import java.lang.Foo.Bar;", - "import p.Baz.Bork;", - "public class Test implements Foo, Bar, Baz, Bork {}", - }, - }, - { - { - "import java.lang.Foo;", // - "interface Test { private static void foo() {} }", - }, - { - "interface Test { private static void foo() {} }", - }, - }, - }; - ImmutableList.Builder builder = ImmutableList.builder(); - for (String[][] inputAndOutput : inputsOutputs) { - assertThat(inputAndOutput).hasLength(2); - String[] input = inputAndOutput[0]; - String[] output = inputAndOutput[1]; - String[] parameters = { - Joiner.on('\n').join(input) + '\n', Joiner.on('\n').join(output) + '\n', - }; - builder.add(parameters); + return builder.build(); } - return builder.build(); - } - private final String input; - private final String expected; + private final String input; + private final String expected; - public RemoveUnusedImportsTest(String input, String expected) { - this.input = input; - this.expected = expected; - } + public RemoveUnusedImportsTest(String input, String expected) { + this.input = input; + this.expected = expected; + } - @Test - public void removeUnused() throws FormatterException { - assertThat(removeUnusedImports(input)).isEqualTo(expected); - } -} + @Test + public void removeUnused() throws FormatterException { + assertThat(removeUnusedImports(input)).isEqualTo(expected); + } +} \ No newline at end of file