2121import static com .google .errorprone .BugPattern .SeverityLevel .ERROR ;
2222import static com .google .errorprone .matchers .Description .NO_MATCH ;
2323import static com .google .errorprone .util .ErrorProneTokens .getTokens ;
24+ import static java .lang .String .format ;
2425
2526import com .google .common .collect .ImmutableList ;
2627import com .google .common .collect .ImmutableRangeSet ;
3132import com .google .errorprone .fixes .FixedPosition ;
3233import com .google .errorprone .matchers .Description ;
3334import com .google .errorprone .util .ErrorProneToken ;
35+ import com .google .errorprone .util .SourceCodeEscapers ;
3436import com .sun .source .tree .CompilationUnitTree ;
3537import 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 ;
3840
3941/** Bans using non-ASCII Unicode characters outside string literals and comments. */
4042@ BugPattern (
@@ -47,27 +49,36 @@ public final class UnicodeInCode extends BugChecker implements CompilationUnitTr
4749 public Description matchCompilationUnit (CompilationUnitTree tree , VisitorState state ) {
4850 ImmutableRangeSet <Integer > commentsAndLiterals = commentsAndLiterals (state );
4951
50- List <Integer > violatingLocations = new ArrayList <>();
52+ Map <Integer , Character > violations = new LinkedHashMap <>();
5153
5254 CharSequence sourceCode = state .getSourceCode ();
5355
5456 for (int i = 0 ; i < sourceCode .length (); ++i ) {
5557 char c = sourceCode .charAt (i );
5658
5759 if (!isAcceptableAscii (c ) && !commentsAndLiterals .contains (i )) {
58- violatingLocations . add ( i );
60+ violations . put ( i , c );
5961 }
6062 }
6163
62- if (violatingLocations .isEmpty ()) {
64+ if (violations .isEmpty ()) {
6365 return NO_MATCH ;
6466 }
6567
6668 ImmutableRangeSet <Integer > suppressedRegions = suppressedRegions (state );
6769
68- for (Integer violatingLocation : violatingLocations ) {
70+ for (var e : violations .entrySet ()) {
71+ int violatingLocation = e .getKey ();
72+ char c = e .getValue ();
6973 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 ());
7182 }
7283 }
7384 return NO_MATCH ;
0 commit comments