Skip to content

Commit 810ff72

Browse files
author
Vincent Potucek
committed
Promote RemoveWildCardImports to linter
1 parent 1e8b84e commit 810ff72

File tree

9 files changed

+173
-11
lines changed

9 files changed

+173
-11
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
1717
* Bump default `google-java-format` version to latest `1.24.0` -> `1.28.0`. ([#2345](https://github.com/diffplug/spotless/pull/2345))
1818
* Bump default `ktlint` version to latest `1.5.0` -> `1.7.1`. ([#2555](https://github.com/diffplug/spotless/pull/2555))
1919
* Bump default `jackson` version to latest `2.19.2` -> `2.20.0`. ([#2606](https://github.com/diffplug/spotless/pull/2606))
20+
* Promote `RemoveWildCardImports` to linter ([#2611](https://github.com/diffplug/spotless/pull/2611))
2021

2122
## [3.3.1] - 2025-07-21
2223
### Fixed

lib/src/main/java/com/diffplug/spotless/Lint.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022-2024 DiffPlug
2+
* Copyright 2022-2025 DiffPlug
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -91,7 +91,7 @@ public ShortcutException(Lint... lints) {
9191
private final List<Lint> lints;
9292

9393
ShortcutException(Collection<Lint> lints) {
94-
super(lints.iterator().next().detail);
94+
super(lints.iterator().next().toString());
9595
this.lints = List.copyOf(lints);
9696
}
9797

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright 2016-2025 DiffPlug
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.diffplug.spotless.generic;
17+
18+
import static com.diffplug.spotless.Lint.atLine;
19+
20+
import java.io.File;
21+
import java.io.Serializable;
22+
import java.util.ArrayList;
23+
import java.util.List;
24+
import java.util.Objects;
25+
import java.util.regex.Pattern;
26+
27+
import com.diffplug.spotless.FormatterFunc;
28+
import com.diffplug.spotless.FormatterStep;
29+
import com.diffplug.spotless.Lint;
30+
31+
public final class LintRegexStep {
32+
// prevent direct instantiation
33+
private LintRegexStep() {}
34+
35+
public static FormatterStep lint(String name, String regex, String error) {
36+
Objects.requireNonNull(name, "name");
37+
Objects.requireNonNull(regex, "regex");
38+
Objects.requireNonNull(error, "error");
39+
return FormatterStep.createLazy(name,
40+
() -> new State(Pattern.compile(regex, Pattern.UNIX_LINES | Pattern.MULTILINE), error),
41+
State::toLinter);
42+
}
43+
44+
private static final class State implements Serializable {
45+
private static final long serialVersionUID = 1L;
46+
47+
private final Pattern regex;
48+
private final String replacement;
49+
50+
State(Pattern regex, String replacement) {
51+
this.regex = regex;
52+
this.replacement = replacement;
53+
}
54+
55+
FormatterFunc toFormatter() {
56+
return raw -> regex.matcher(raw).replaceAll(replacement);
57+
}
58+
59+
FormatterFunc toLinter() {
60+
return new FormatterFunc() {
61+
@Override
62+
public String apply(String raw) {
63+
return raw;
64+
}
65+
66+
@Override
67+
public List<Lint> lint(String raw, File file) {
68+
List<Lint> lints = new ArrayList<>();
69+
var matcher = regex.matcher(raw);
70+
while (matcher.find()) {
71+
int line = 1 + (int) raw.codePoints().limit(matcher.start()).filter(c -> c == '\n').count();
72+
lints.add(atLine(line, matcher.group(0), replacement));
73+
}
74+
return lints;
75+
}
76+
};
77+
}
78+
}
79+
}

lib/src/main/java/com/diffplug/spotless/java/RemoveWildcardImportsStep.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,21 @@
1616
package com.diffplug.spotless.java;
1717

1818
import com.diffplug.spotless.FormatterStep;
19-
import com.diffplug.spotless.generic.ReplaceRegexStep;
19+
import com.diffplug.spotless.generic.LintRegexStep;
2020

2121
/** Removes any wildcard import statements. */
2222
public final class RemoveWildcardImportsStep {
23+
24+
/**
25+
* Matches lines like 'import foo.*;' or 'import static foo.*;'.
26+
*/
27+
private static final String REGEX = "(?m)^import\\s+(?:static\\s+)?[^;\\n]*\\*;\\R?";
28+
private static final String NAME = "removeWildcardImports";
29+
private static final String ERROR = "Do not use wildcard imports (e.g. java.util.*) - replace with specific class imports (e.g. java.util.List) as 'spotlessApply' cannot auto-fix this";
30+
2331
private RemoveWildcardImportsStep() {}
2432

2533
public static FormatterStep create() {
26-
// Matches lines like 'import foo.*;' or 'import static foo.*;'.
27-
return ReplaceRegexStep.create(
28-
"removeWildcardImports",
29-
"(?m)^import\\s+(?:static\\s+)?[^;\\n]*\\*;\\R?",
30-
"");
34+
return LintRegexStep.lint(NAME, REGEX, ERROR);
3135
}
3236
}

plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaDefaultTargetTest.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
*/
1616
package com.diffplug.gradle.spotless;
1717

18+
import static org.assertj.core.api.Assertions.assertThat;
19+
import static org.junit.jupiter.api.Assertions.assertThrows;
20+
1821
import java.io.IOException;
1922

2023
import org.junit.jupiter.api.Test;
@@ -97,8 +100,17 @@ void removeWildCardImports() throws IOException {
97100
"}");
98101

99102
setFile("test.java").toResource("java/removewildcardimports/JavaCodeWildcardsUnformatted.test");
100-
gradleRunner().withArguments("spotlessApply").build();
101-
assertFile("test.java").sameAsResource("java/removewildcardimports/JavaCodeWildcardsFormatted.test");
103+
gradleRunner().withArguments("spotlessApply").buildAndFail();
104+
assertThat(assertThrows(AssertionError.class, () -> assertFile("test.java").sameAsResource("java/removewildcardimports/JavaCodeWildcardsFormatted.test")).getMessage())
105+
.contains("Extra content at line 1:")
106+
.contains("Extra content at line 3:")
107+
.contains("import io.quarkus.maven.dependency.*;")
108+
.contains("import static io.quarkus.vertx.web.Route.HttpMethod.*;")
109+
.contains("import static org.springframework.web.reactive.function.BodyInserters.*;")
110+
.contains("java.util.*")
111+
.contains("java.util.Collections.*")
112+
.doesNotContain("import mylib.Helper;")
113+
.doesNotContain("public class Test {}");
102114
}
103115

104116
/**

plugin-maven/src/test/java/com/diffplug/spotless/maven/java/RemoveWildcardImportsStepTest.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
*/
1616
package com.diffplug.spotless.maven.java;
1717

18+
import static org.assertj.core.api.Assertions.assertThat;
19+
import static org.junit.jupiter.api.Assertions.assertThrows;
20+
1821
import org.junit.jupiter.api.Test;
1922

2023
import com.diffplug.spotless.maven.MavenIntegrationHarness;
@@ -28,6 +31,25 @@ void testRemoveWildcardImports() throws Exception {
2831
String path = "src/main/java/test.java";
2932
setFile(path).toResource("java/removewildcardimports/JavaCodeWildcardsUnformatted.test");
3033
mavenRunner().withArguments("spotless:apply").runNoError();
31-
assertFile(path).sameAsResource("java/removewildcardimports/JavaCodeWildcardsFormatted.test");
34+
assertThat(assertThrows(AssertionError.class, () -> assertFile(path).sameAsResource("java/removewildcardimports/JavaCodeWildcardsFormatted.test")).getMessage())
35+
.contains("Extra content at line 1:")
36+
.contains("Extra content at line 3:")
37+
.contains("import io.quarkus.maven.dependency.*;")
38+
.contains("import static io.quarkus.vertx.web.Route.HttpMethod.*;")
39+
.contains("import static org.springframework.web.reactive.function.BodyInserters.*;")
40+
.contains("java.util.*")
41+
.contains("java.util.Collections.*")
42+
.doesNotContain("import mylib.Helper;")
43+
.doesNotContain("public class Test {}");
44+
}
45+
46+
@Test
47+
void testRemoveWildcardImportsWithNoResult() throws Exception {
48+
writePomWithJavaSteps("<removeWildcardImports/>");
49+
50+
String path = "src/main/java/test.java";
51+
setFile(path).toResource("java/removewildcardimports/JavaCodeNoWildcardsUnformatted.test");
52+
mavenRunner().withArguments("spotless:apply").runNoError();
53+
assertFile(path).sameAsResource("java/removewildcardimports/JavaCodeNoWildcardsFormatted.test");
3254
}
3355
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import java.util.List;
2+
import mylib.Helper;
3+
4+
public class Test {}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import java.util.List;
2+
import mylib.Helper;
3+
4+
public class Test {}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2025 DiffPlug
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.diffplug.spotless.generic;
17+
18+
import org.junit.jupiter.api.Test;
19+
20+
import com.diffplug.common.base.StringPrinter;
21+
import com.diffplug.spotless.FormatterStep;
22+
import com.diffplug.spotless.StepHarness;
23+
24+
class LintRegexStepTest {
25+
26+
@Test
27+
void lint() throws Exception {
28+
FormatterStep step = LintRegexStep.lint("regex", "bad", "no bad words");
29+
StepHarness.forStep(step)
30+
.expectLintsOf(StringPrinter.buildStringFromLines(
31+
"bad",
32+
"x bad y",
33+
"ok"))
34+
.toBe("L1 regex(bad) no bad words\nL2 regex(bad) no bad words");
35+
}
36+
}

0 commit comments

Comments
 (0)