21
21
import static com .google .errorprone .BugPattern .SeverityLevel .ERROR ;
22
22
import static com .google .errorprone .matchers .Description .NO_MATCH ;
23
23
import static com .google .errorprone .util .ErrorProneTokens .getTokens ;
24
+ import static java .lang .String .format ;
24
25
25
26
import com .google .common .collect .ImmutableList ;
26
27
import com .google .common .collect .ImmutableRangeSet ;
31
32
import com .google .errorprone .fixes .FixedPosition ;
32
33
import com .google .errorprone .matchers .Description ;
33
34
import com .google .errorprone .util .ErrorProneToken ;
35
+ import com .google .errorprone .util .SourceCodeEscapers ;
34
36
import com .sun .source .tree .CompilationUnitTree ;
35
37
import com .sun .tools .javac .parser .Tokens .TokenKind ;
36
- import java .util .ArrayList ;
37
- import java .util .List ;
38
+ import java .util .LinkedHashMap ;
39
+ import java .util .Map ;
38
40
39
41
/** Bans using non-ASCII Unicode characters outside string literals and comments. */
40
42
@ BugPattern (
@@ -47,27 +49,36 @@ public final class UnicodeInCode extends BugChecker implements CompilationUnitTr
47
49
public Description matchCompilationUnit (CompilationUnitTree tree , VisitorState state ) {
48
50
ImmutableRangeSet <Integer > commentsAndLiterals = commentsAndLiterals (state );
49
51
50
- List <Integer > violatingLocations = new ArrayList <>();
52
+ Map <Integer , Character > violations = new LinkedHashMap <>();
51
53
52
54
CharSequence sourceCode = state .getSourceCode ();
53
55
54
56
for (int i = 0 ; i < sourceCode .length (); ++i ) {
55
57
char c = sourceCode .charAt (i );
56
58
57
59
if (!isAcceptableAscii (c ) && !commentsAndLiterals .contains (i )) {
58
- violatingLocations . add ( i );
60
+ violations . put ( i , c );
59
61
}
60
62
}
61
63
62
- if (violatingLocations .isEmpty ()) {
64
+ if (violations .isEmpty ()) {
63
65
return NO_MATCH ;
64
66
}
65
67
66
68
ImmutableRangeSet <Integer > suppressedRegions = suppressedRegions (state );
67
69
68
- for (Integer violatingLocation : violatingLocations ) {
70
+ for (var e : violations .entrySet ()) {
71
+ int violatingLocation = e .getKey ();
72
+ char c = e .getValue ();
69
73
if (!suppressedRegions .contains (violatingLocation )) {
70
- state .reportMatch (describeMatch (new FixedPosition (tree , violatingLocation )));
74
+ state .reportMatch (
75
+ buildDescription (new FixedPosition (tree , violatingLocation ))
76
+ .setMessage (
77
+ format (
78
+ "Avoid using non-ASCII Unicode character (%s) outside of comments and"
79
+ + " literals, as they can be confusing." ,
80
+ SourceCodeEscapers .javaCharEscaper ().escape (Character .toString (c ))))
81
+ .build ());
71
82
}
72
83
}
73
84
return NO_MATCH ;
0 commit comments