diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/UnicodeInCode.java b/core/src/main/java/com/google/errorprone/bugpatterns/UnicodeInCode.java index 2ce775b0a41..2a2c0fa77df 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/UnicodeInCode.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/UnicodeInCode.java @@ -21,6 +21,7 @@ import static com.google.errorprone.BugPattern.SeverityLevel.ERROR; import static com.google.errorprone.matchers.Description.NO_MATCH; import static com.google.errorprone.util.ErrorProneTokens.getTokens; +import static java.lang.String.format; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableRangeSet; @@ -31,10 +32,11 @@ import com.google.errorprone.fixes.FixedPosition; import com.google.errorprone.matchers.Description; import com.google.errorprone.util.ErrorProneToken; +import com.google.errorprone.util.SourceCodeEscapers; import com.sun.source.tree.CompilationUnitTree; import com.sun.tools.javac.parser.Tokens.TokenKind; -import java.util.ArrayList; -import java.util.List; +import java.util.LinkedHashMap; +import java.util.Map; /** Bans using non-ASCII Unicode characters outside string literals and comments. */ @BugPattern( @@ -47,7 +49,7 @@ public final class UnicodeInCode extends BugChecker implements CompilationUnitTr public Description matchCompilationUnit(CompilationUnitTree tree, VisitorState state) { ImmutableRangeSet commentsAndLiterals = commentsAndLiterals(state); - List violatingLocations = new ArrayList<>(); + Map violations = new LinkedHashMap<>(); CharSequence sourceCode = state.getSourceCode(); @@ -55,19 +57,28 @@ public Description matchCompilationUnit(CompilationUnitTree tree, VisitorState s char c = sourceCode.charAt(i); if (!isAcceptableAscii(c) && !commentsAndLiterals.contains(i)) { - violatingLocations.add(i); + violations.put(i, c); } } - if (violatingLocations.isEmpty()) { + if (violations.isEmpty()) { return NO_MATCH; } ImmutableRangeSet suppressedRegions = suppressedRegions(state); - for (Integer violatingLocation : violatingLocations) { + for (var e : violations.entrySet()) { + int violatingLocation = e.getKey(); + char c = e.getValue(); if (!suppressedRegions.contains(violatingLocation)) { - state.reportMatch(describeMatch(new FixedPosition(tree, violatingLocation))); + state.reportMatch( + buildDescription(new FixedPosition(tree, violatingLocation)) + .setMessage( + format( + "Avoid using non-ASCII Unicode character (%s) outside of comments and" + + " literals, as they can be confusing.", + SourceCodeEscapers.javaCharEscaper().escape(Character.toString(c)))) + .build()); } } return NO_MATCH; diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/UnicodeInCodeTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/UnicodeInCodeTest.java index ab2bd61edf4..36b10a5147d 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/UnicodeInCodeTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/UnicodeInCodeTest.java @@ -78,7 +78,7 @@ public void positive() { .addSourceLines( "Test.java", // "class Test {", - " // BUG: Diagnostic contains:", + " // BUG: Diagnostic contains: Unicode character (\\u03c0)", " static final double \u03C0 = 3;", "}") .doTest();