20
20
import java .util .Collection ;
21
21
import java .util .List ;
22
22
import java .util .Objects ;
23
+ import java .util .regex .Matcher ;
24
+ import java .util .regex .Pattern ;
23
25
24
26
/**
25
27
* Models a linted line or line range. Note that there is no concept of severity level - responsibility
26
28
* for severity and confidence are pushed down to the configuration of the lint tool. If a lint makes it
27
29
* to Spotless, then it is by definition.
28
30
*/
29
31
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 );
33
34
}
34
35
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 );
38
38
}
39
39
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 ;
43
78
}
44
79
45
80
/** Any exception which implements this interface will have its lints extracted and reported cleanly to the user. */
@@ -48,14 +83,15 @@ public interface Has {
48
83
}
49
84
50
85
/** 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 {
52
87
public ShortcutException (Lint ... lints ) {
53
88
this (Arrays .asList (lints ));
54
89
}
55
90
56
91
private final List <Lint > lints ;
57
92
58
- public ShortcutException (Collection <Lint > lints ) {
93
+ ShortcutException (Collection <Lint > lints ) {
94
+ super (lints .iterator ().next ().detail );
59
95
this .lints = List .copyOf (lints );
60
96
}
61
97
@@ -65,56 +101,26 @@ public List<Lint> getLints() {
65
101
}
66
102
}
67
103
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 );
79
107
}
80
108
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 );
106
112
}
107
113
108
114
@ Override
109
115
public String toString () {
110
116
if (lineStart == lineEnd ) {
111
117
if (lineStart == LINE_UNDEFINED ) {
112
- return "LINE_UNDEFINED: (" + code + ") " + msg ;
118
+ return "LINE_UNDEFINED: (" + ruleId + ") " + detail ;
113
119
} else {
114
- return lineStart + ": (" + code + ") " + msg ;
120
+ return "L" + lineStart + ": (" + ruleId + ") " + detail ;
115
121
}
116
122
} else {
117
- return lineStart + "-" + lineEnd + ": (" + code + ") " + msg ;
123
+ return "L" + lineStart + "-" + lineEnd + ": (" + ruleId + ") " + detail ;
118
124
}
119
125
}
120
126
@@ -125,27 +131,36 @@ public boolean equals(Object o) {
125
131
if (o == null || getClass () != o .getClass ())
126
132
return false ;
127
133
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 );
129
135
}
130
136
131
137
@ Override
132
138
public int hashCode () {
133
- return Objects .hash (lineStart , lineEnd , code , msg );
139
+ return Objects .hash (lineStart , lineEnd , ruleId , detail );
134
140
}
135
141
136
142
/** 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 ) {
138
144
Throwable current = e ;
139
145
while (current != null ) {
140
146
String message = current .getMessage ();
141
147
int lineNumber = lineNumberFor (message );
142
148
if (lineNumber != -1 ) {
143
- return Lint . create ( step .getName (), msgFrom (message ), lineNumber );
149
+ return new Lint ( lineNumber , step .getName (), msgFrom (message ));
144
150
}
145
151
current = current .getCause ();
146
152
}
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 );
149
164
}
150
165
151
166
private static int lineNumberFor (String message ) {
0 commit comments