Skip to content

Commit 8300fda

Browse files
committed
Fix ambiguities in the Lint class around treating it as data vs exception.
1 parent ae31ea5 commit 8300fda

File tree

1 file changed

+71
-56
lines changed
  • lib/src/main/java/com/diffplug/spotless

1 file changed

+71
-56
lines changed

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

Lines changed: 71 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -20,26 +20,61 @@
2020
import java.util.Collection;
2121
import java.util.List;
2222
import java.util.Objects;
23+
import java.util.regex.Matcher;
24+
import java.util.regex.Pattern;
2325

2426
/**
2527
* Models a linted line or line range. Note that there is no concept of severity level - responsibility
2628
* for severity and confidence are pushed down to the configuration of the lint tool. If a lint makes it
2729
* to Spotless, then it is by definition.
2830
*/
2931
public final class Lint implements Serializable {
30-
/** Returns a runtime exception which, if thrown, will create a lint at an undefined line. */
31-
public static ShortcutException atUndefinedLine(String code, String msg) {
32-
return new ShortcutException(Lint.create(code, msg, LINE_UNDEFINED));
32+
public static Lint atUndefinedLine(String ruleId, String detail) {
33+
return new Lint(LINE_UNDEFINED, ruleId, detail);
3334
}
3435

35-
/** Returns a runtime exception which, if thrown, will lint a specific line. */
36-
public static ShortcutException atLine(int line, String code, String msg) {
37-
return new ShortcutException(Lint.create(code, msg, line));
36+
public static Lint atLine(int line, String ruleId, String detail) {
37+
return new Lint(line, ruleId, detail);
3838
}
3939

40-
/** Returns a runtime exception which, if thrown, will lint a specific line range. */
41-
public static ShortcutException atLineRange(int lineStart, int lineEnd, String code, String msg) {
42-
return new ShortcutException(Lint.create(code, msg, lineStart, lineEnd));
40+
public static Lint atLineRange(int lineStart, int lineEnd, String ruleId, String detail) {
41+
return new Lint(lineStart, lineEnd, ruleId, detail);
42+
}
43+
44+
private static final long serialVersionUID = 1L;
45+
46+
private int lineStart, lineEnd; // 1-indexed, inclusive
47+
private String ruleId; // e.g. CN_IDIOM https://spotbugs.readthedocs.io/en/stable/bugDescriptions.html#cn-class-implements-cloneable-but-does-not-define-or-use-clone-method-cn-idiom
48+
private String detail;
49+
50+
private Lint(int lineStart, int lineEnd, String ruleId, String detail) {
51+
if (lineEnd < lineStart) {
52+
throw new IllegalArgumentException("lineEnd must be >= lineStart: lineStart=" + lineStart + " lineEnd=" + lineEnd);
53+
}
54+
this.lineStart = lineStart;
55+
this.lineEnd = lineEnd;
56+
this.ruleId = LineEnding.toUnix(ruleId);
57+
this.detail = LineEnding.toUnix(detail);
58+
}
59+
60+
private Lint(int line, String ruleId, String detail) {
61+
this(line, line, ruleId, detail);
62+
}
63+
64+
public int getLineStart() {
65+
return lineStart;
66+
}
67+
68+
public int getLineEnd() {
69+
return lineEnd;
70+
}
71+
72+
public String getRuleId() {
73+
return ruleId;
74+
}
75+
76+
public String getDetail() {
77+
return detail;
4378
}
4479

4580
/** Any exception which implements this interface will have its lints extracted and reported cleanly to the user. */
@@ -48,14 +83,15 @@ public interface Has {
4883
}
4984

5085
/** An exception for shortcutting execution to report a lint to the user. */
51-
public static class ShortcutException extends RuntimeException implements Has {
86+
static class ShortcutException extends RuntimeException implements Has {
5287
public ShortcutException(Lint... lints) {
5388
this(Arrays.asList(lints));
5489
}
5590

5691
private final List<Lint> lints;
5792

58-
public ShortcutException(Collection<Lint> lints) {
93+
ShortcutException(Collection<Lint> lints) {
94+
super(lints.iterator().next().detail);
5995
this.lints = List.copyOf(lints);
6096
}
6197

@@ -65,56 +101,26 @@ public List<Lint> getLints() {
65101
}
66102
}
67103

68-
private static final long serialVersionUID = 1L;
69-
70-
private int lineStart, lineEnd; // 1-indexed, inclusive
71-
private String code; // e.g. CN_IDIOM https://spotbugs.readthedocs.io/en/stable/bugDescriptions.html#cn-class-implements-cloneable-but-does-not-define-or-use-clone-method-cn-idiom
72-
private String msg;
73-
74-
private Lint(int lineStart, int lineEnd, String lintCode, String lintMsg) {
75-
this.lineStart = lineStart;
76-
this.lineEnd = lineEnd;
77-
this.code = LineEnding.toUnix(lintCode);
78-
this.msg = LineEnding.toUnix(lintMsg);
104+
/** Returns an exception which will wrap all of the given lints using {@link Has} */
105+
public static RuntimeException shortcut(Collection<Lint> lints) {
106+
return new ShortcutException(lints);
79107
}
80108

81-
public static Lint create(String code, String msg, int lineStart, int lineEnd) {
82-
if (lineEnd < lineStart) {
83-
throw new IllegalArgumentException("lineEnd must be >= lineStart: lineStart=" + lineStart + " lineEnd=" + lineEnd);
84-
}
85-
return new Lint(lineStart, lineEnd, code, msg);
86-
}
87-
88-
public static Lint create(String code, String msg, int line) {
89-
return new Lint(line, line, code, msg);
90-
}
91-
92-
public int getLineStart() {
93-
return lineStart;
94-
}
95-
96-
public int getLineEnd() {
97-
return lineEnd;
98-
}
99-
100-
public String getCode() {
101-
return code;
102-
}
103-
104-
public String getMsg() {
105-
return msg;
109+
/** Returns an exception which will wrap this lint using {@link Has} */
110+
public RuntimeException shortcut() {
111+
return new ShortcutException(this);
106112
}
107113

108114
@Override
109115
public String toString() {
110116
if (lineStart == lineEnd) {
111117
if (lineStart == LINE_UNDEFINED) {
112-
return "LINE_UNDEFINED: (" + code + ") " + msg;
118+
return "LINE_UNDEFINED: (" + ruleId + ") " + detail;
113119
} else {
114-
return lineStart + ": (" + code + ") " + msg;
120+
return "L" + lineStart + ": (" + ruleId + ") " + detail;
115121
}
116122
} else {
117-
return lineStart + "-" + lineEnd + ": (" + code + ") " + msg;
123+
return "L" + lineStart + "-" + lineEnd + ": (" + ruleId + ") " + detail;
118124
}
119125
}
120126

@@ -125,27 +131,36 @@ public boolean equals(Object o) {
125131
if (o == null || getClass() != o.getClass())
126132
return false;
127133
Lint lint = (Lint) o;
128-
return lineStart == lint.lineStart && lineEnd == lint.lineEnd && Objects.equals(code, lint.code) && Objects.equals(msg, lint.msg);
134+
return lineStart == lint.lineStart && lineEnd == lint.lineEnd && Objects.equals(ruleId, lint.ruleId) && Objects.equals(detail, lint.detail);
129135
}
130136

131137
@Override
132138
public int hashCode() {
133-
return Objects.hash(lineStart, lineEnd, code, msg);
139+
return Objects.hash(lineStart, lineEnd, ruleId, detail);
134140
}
135141

136142
/** Attempts to parse a line number from the given exception. */
137-
static Lint createFromThrowable(FormatterStep step, String content, Throwable e) {
143+
static Lint createFromThrowable(FormatterStep step, Throwable e) {
138144
Throwable current = e;
139145
while (current != null) {
140146
String message = current.getMessage();
141147
int lineNumber = lineNumberFor(message);
142148
if (lineNumber != -1) {
143-
return Lint.create(step.getName(), msgFrom(message), lineNumber);
149+
return new Lint(lineNumber, step.getName(), msgFrom(message));
144150
}
145151
current = current.getCause();
146152
}
147-
int numNewlines = (int) content.codePoints().filter(c -> c == '\n').count();
148-
return Lint.create(step.getName(), ThrowingEx.stacktrace(e), 1, 1 + numNewlines);
153+
String exceptionName = e.getClass().getName();
154+
String detail = ThrowingEx.stacktrace(e);
155+
if (detail.startsWith(exceptionName + ": ")) {
156+
detail = detail.substring(exceptionName.length() + 2);
157+
}
158+
Matcher matcher = Pattern.compile("line (\\d+)").matcher(detail);
159+
int line = LINE_UNDEFINED;
160+
if (matcher.find()) {
161+
line = Integer.parseInt(matcher.group(1));
162+
}
163+
return Lint.atLine(line, exceptionName, detail);
149164
}
150165

151166
private static int lineNumberFor(String message) {

0 commit comments

Comments
 (0)