Skip to content

Commit efe7fdd

Browse files
committed
ICU-12717 Improve errorprone reporting
1 parent 3962233 commit efe7fdd

File tree

7 files changed

+138
-29
lines changed

7 files changed

+138
-29
lines changed

icu4j/main/collate/src/test/java/com/ibm/icu/dev/test/collator/CollationMiscTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2982,6 +2982,7 @@ public void TestMerge() {
29822982

29832983
/* Test the method public int compareTo(RawCollationKey rhs) */
29842984
@Test
2985+
@SuppressWarnings("SelfComparison")
29852986
public void TestRawCollationKeyCompareTo(){
29862987
RawCollationKey rck = new RawCollationKey();
29872988
byte[] b = {(byte) 10, (byte) 20};

icu4j/pom.xml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,8 @@
678678
</profile>
679679

680680
<profile>
681-
<!-- mvn clean test -ntp -DskipTests -DskipITs -l errorprone.log -P errorprone
681+
<!-- mvn clean test -ntp -DskipTests -DskipITs -l /tmp/errorprone.log -P errorprone
682+
mvn exec:java -f tools/build/ -P errorprone_report -DlogFile=/tmp/errorprone.log
682683
Then inspect the content of the errorprone.log file.
683684
We will have some script to convert that to a more friendly format (likely html) -->
684685
<id>errorprone</id>
@@ -701,7 +702,7 @@
701702
So we force them all to be reported as warning.
702703
The drawback is that there are not errors now, they get mixed with the real warnings.
703704
-->
704-
<arg>-Xplugin:ErrorProne -XepAllErrorsAsWarnings</arg>
705+
<arg>-Xplugin:ErrorProne -XepAllErrorsAsWarnings -Xep:UnicodeEscape:OFF</arg>
705706
<arg>-Xmaxerrs</arg>
706707
<arg>10000</arg>
707708
<arg>-J-Dfile.encoding=UTF-8</arg>

icu4j/tools/build/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
<!--
4141
From icu4j:
4242
mvn clean test -ntp -DskipTests -DskipITs -l /tmp/errorprone.log -P errorprone
43-
mvn exec:java -f tools/build/ -P errorprone_report
43+
mvn exec:java -f tools/build/ -P errorprone_report -DlogFile=/tmp/errorprone.log
4444
4545
The links to the source files go to the main GitHub repo (`main` branch).
4646
But when we work locally, or in a fork / branch, the links might point to an incorrect file / line.

icu4j/tools/build/src/main/java/com/ibm/icu/dev/tool/errorprone/ErrorProneReport.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,13 @@
1717
import java.util.Locale;
1818
import java.util.Map;
1919

20-
import com.google.common.collect.ImmutableBiMap;
21-
import com.google.errorprone.BugCheckerInfo;
22-
import com.google.errorprone.scanner.BuiltInCheckerSuppliers;
23-
2420
class ErrorProneReport {
2521
private static final String HTML_REPORT_FILE = "errorprone1.html";
2622
private static final String HTML_REPORT_FILE2 = "errorprone2.html";
2723
private static final String SORTTABLE_JS_FILE = "sorttable.js";
2824
private static final String SORTTABLE_CSS_FILE = "errorprone.css";
2925
private static final String [] EMBEDDED_FILES =
3026
{ SORTTABLE_JS_FILE, SORTTABLE_CSS_FILE };
31-
private static final ImmutableBiMap<String, BugCheckerInfo> KNOWN_ERRORS =
32-
BuiltInCheckerSuppliers.allChecks().getAllChecks();
3327

3428
public static void genReports(String icuDir, String mavenStdOut, String outDir, String baseUrl)
3529
throws IOException {
@@ -95,6 +89,11 @@ private static void genReport1(Map<String, List<ErrorProneEntry>> errors,
9589
? Map.of("target", "errWin")
9690
: Map.of("href", error.url, "target", "errWin");
9791
hu.openTag("a", attr).text(error.type).closeTag("a");
92+
93+
String tags = ErrorProneUtils.getTags(error.type);
94+
if (tags != null) {
95+
hu.openTag("span", Map.of("class", "tags")).text(" " + tags).closeTag("span");
96+
}
9897
hu.closeTag("td");
9998

10099
outDescription(hu, error);
@@ -145,8 +144,12 @@ private static void genReport2(Map<String, List<ErrorProneEntry>> errors,
145144
// "class", "severity_" + errorSeverity)
146145
hu.openTag("h3", Map.of("id", "name_" + errorType))
147146
.text("[" + firstEntry.severity + "] ")
148-
.openTag("span", Map.of("class", "tag")).text(errorType).closeTag("span")
149-
.text(" [" + errorsOfType.size() + "] ");
147+
.openTag("span", Map.of("class", "tag")).text(errorType).closeTag("span");
148+
String tags = ErrorProneUtils.getTags(errorType);
149+
if (tags != null) {
150+
hu.openTag("span", Map.of("class", "tags")).text(" " + tags).closeTag("span");
151+
}
152+
hu.text(" (" + errorsOfType.size() + ") ");
150153
String url = ErrorProneUtils.getUrl(errorType);
151154
if (url != null) {
152155
hu.openTag("a", Map.of("href", url, "target", "errWin"))
@@ -252,8 +255,12 @@ private static void outSummary(HtmlUtils hu, Map<String, List<ErrorProneEntry>>
252255
.openTag("span", Map.of("class", "tag"))
253256
.text(e.getKey())
254257
.closeTag("span")
255-
.closeTag("a")
256-
.text(" [" + e.getValue().size() + "]\n");
258+
.closeTag("a");
259+
String tags = ErrorProneUtils.getTags(e.getKey());
260+
if (tags != null) {
261+
hu.openTag("span", Map.of("class", "tags")).text(" " + tags).closeTag("span");
262+
}
263+
hu.text(" (" + e.getValue().size() + ")\n");
257264
}
258265
if (!first) {
259266
hu.closeTag("p").nl();

icu4j/tools/build/src/main/java/com/ibm/icu/dev/tool/errorprone/ErrorProneUtils.java

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
import java.util.Arrays;
77
import java.util.List;
88
import java.util.Map;
9+
import java.util.Set;
910

10-
import com.google.common.collect.ImmutableBiMap;
1111
import com.google.errorprone.BugCheckerInfo;
1212
import com.google.errorprone.BugPattern;
1313
import com.google.errorprone.scanner.BuiltInCheckerSuppliers;
@@ -32,7 +32,7 @@ class ErrorProneUtils {
3232
* So to "get back" the proper severity level we depend on the errorprone library,
3333
* get all known errors, and then use the `defaultSeverity` field within each `BugCheckerInfo`.
3434
*/
35-
private static final ImmutableBiMap<String, BugCheckerInfo> KNOWN_ERRORS =
35+
private static final Map<String, BugCheckerInfo> KNOWN_ERRORS =
3636
BuiltInCheckerSuppliers.allChecks().getAllChecks();
3737
static final String SEVERITY_UNKNOWN = "UNKNOWN";
3838
// Some special severity classes, to group what ICU considers important to fix.
@@ -55,10 +55,46 @@ class ErrorProneUtils {
5555
BugPattern.SeverityLevel.SUGGESTION.toString());
5656

5757
// A special severity class, where we show first what ICU considers important to fix.
58-
static final Map<String, String> ICU_SPECIAL_SEVERITIES = Map.of(
58+
static final Map<String, String> ICU_SPECIAL_SEVERITIES = Map.ofEntries(
5959
// Example:
60-
// "MissingFail", SEVERITY_ICU_PRI1,
61-
// "ReferenceEquality", SEVERITY_ICU_PRI2
60+
// Map.entry("MissingFail", SEVERITY_ICU_PRI1),
61+
// Map.entry("ReferenceEquality", SEVERITY_ICU_PRI2)
62+
Map.entry("DefaultCharset", SEVERITY_ICU_PRI1),
63+
Map.entry("Finally", SEVERITY_ICU_PRI1),
64+
Map.entry("InvalidBlockTag", SEVERITY_ICU_PRI1),
65+
Map.entry("JdkObsolete", SEVERITY_ICU_PRI1),
66+
Map.entry("MissingFail", SEVERITY_ICU_PRI1),
67+
Map.entry("MutablePublicArray", SEVERITY_ICU_PRI1),
68+
Map.entry("ObjectToString", SEVERITY_ICU_PRI1),
69+
Map.entry("OperatorPrecedence", SEVERITY_ICU_PRI1),
70+
Map.entry("ReferenceEquality", SEVERITY_ICU_PRI1),
71+
Map.entry("StringSplitter", SEVERITY_ICU_PRI1),
72+
Map.entry("SynchronizeOnNonFinalField", SEVERITY_ICU_PRI1),
73+
Map.entry("UnicodeEscape", SEVERITY_ICU_PRI1),
74+
Map.entry("UnusedMethod", SEVERITY_ICU_PRI1),
75+
Map.entry("UnusedVariable", SEVERITY_ICU_PRI1),
76+
Map.entry("AlmostJavadoc", SEVERITY_ICU_PRI2),
77+
Map.entry("BadImport", SEVERITY_ICU_PRI2),
78+
Map.entry("ClassCanBeStatic", SEVERITY_ICU_PRI2),
79+
Map.entry("EmptyCatch", SEVERITY_ICU_PRI2),
80+
Map.entry("EqualsGetClass", SEVERITY_ICU_PRI2),
81+
Map.entry("EqualsUnsafeCast", SEVERITY_ICU_PRI2),
82+
Map.entry("FallThrough", SEVERITY_ICU_PRI2),
83+
Map.entry("Finalize", SEVERITY_ICU_PRI2),
84+
Map.entry("FloatingPointLiteralPrecision", SEVERITY_ICU_PRI2),
85+
Map.entry("IncrementInForLoopAndHeader", SEVERITY_ICU_PRI2),
86+
Map.entry("JavaUtilDate", SEVERITY_ICU_PRI2),
87+
Map.entry("LabelledBreakTarget", SEVERITY_ICU_PRI2),
88+
Map.entry("LockOnNonEnclosingClassLiteral", SEVERITY_ICU_PRI2),
89+
Map.entry("NarrowCalculation", SEVERITY_ICU_PRI2),
90+
Map.entry("NarrowingCompoundAssignment", SEVERITY_ICU_PRI2),
91+
Map.entry("ShortCircuitBoolean", SEVERITY_ICU_PRI2),
92+
Map.entry("StaticAssignmentInConstructor", SEVERITY_ICU_PRI2),
93+
Map.entry("StringCaseLocaleUsage", SEVERITY_ICU_PRI2),
94+
Map.entry("StringCharset", SEVERITY_ICU_PRI2),
95+
Map.entry("UndefinedEquals", SEVERITY_ICU_PRI2),
96+
Map.entry("UnnecessaryStringBuilder", SEVERITY_ICU_PRI2),
97+
Map.entry("UnsynchronizedOverridesSynchronized", SEVERITY_ICU_PRI2)
6298
);
6399

64100
/**
@@ -90,4 +126,20 @@ static String getUrl(String errorType) {
90126
BugCheckerInfo found = KNOWN_ERRORS.get(errorType);
91127
return found == null ? null : found.linkUrl();
92128
}
129+
130+
/**
131+
* Given an error type (for example `BadImport`, `UnusedVariable`)
132+
* it returns the tags associtated with it (`FragileCode`, `Style`, etc.)
133+
*
134+
* @param errorType the error type, as reported by errorprone
135+
* @return the url to a public explanation page
136+
*/
137+
static String getTags(String errorType) {
138+
BugCheckerInfo found = KNOWN_ERRORS.get(errorType);
139+
if (found == null) {
140+
return null;
141+
}
142+
Set<String> tags = found.getTags();
143+
return tags.isEmpty() ? null : tags.toString();
144+
}
93145
}

icu4j/tools/build/src/main/java/com/ibm/icu/dev/tool/errorprone/ParseMavenOutForErrorProne.java

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,24 @@
1010
import java.util.ArrayList;
1111
import java.util.List;
1212
import java.util.Map;
13+
import java.util.Set;
1314
import java.util.TreeMap;
1415
import java.util.regex.Matcher;
1516
import java.util.regex.Pattern;
1617

1718
class ParseMavenOutForErrorProne {
18-
// The `(?:[A-F]:)?` in the beginning is for the Windows drive letter (for example D:)
19+
// The `(?:[A-F]:)?` in the beginning is for the Windows drive letter (for example D:)
1920
private static final String RE_ERROR_PRONE_START =
2021
"^\\[WARNING\\] ((?:[A-F]:)?[\\\\/a-zA-Z0-9_.\\-]+\\.java):\\[(\\d+),(\\d+)\\]"
2122
+ " \\[(\\S+)\\] (.+)";
2223
private static final Pattern PATTERN = Pattern.compile(RE_ERROR_PRONE_START);
2324

25+
// These are ICU custom tags, but errorprone does not allow us to exclude them.
26+
// So we will filter them out in our code.
27+
private static final Set<String> CUSTOM_ICU_TAGS = Set.of(
28+
"bug", "category", "discouraged", "draft", "icuenhanced", "internal", "icu",
29+
"icunote", "obsolete", "provisional", "stable", "summary", "test");
30+
2431
/**
2532
* The result contains the issues reported by errorprone.
2633
*
@@ -91,19 +98,44 @@ static Map<String, List<ErrorProneEntry>> parse(String baseDir, String fileName)
9198
return errorReport;
9299
}
93100

101+
private static boolean isCustomIcuTag(ErrorProneEntry crtError) {
102+
String errorType = crtError.type;
103+
if (errorType.equals("InvalidBlockTag")) {
104+
return false;
105+
}
106+
String message = crtError.message;
107+
// We will filter out the custom ICU tags.
108+
// There is no programatic way to find the name of the tag, we must extract it from the error message.
109+
// Message text 1:
110+
// "Tag name `stable` is unknown. If this is a commonly-used custom tag, please click 'not useful' and file a bug."
111+
int firstBackTick = message.indexOf('`');
112+
if (firstBackTick >= 0) {
113+
int secondBackTick = message.indexOf('`', firstBackTick + 1);
114+
if (secondBackTick >= 0) {
115+
String tagName = message.substring(firstBackTick + 1, secondBackTick);
116+
if (CUSTOM_ICU_TAGS.contains(tagName)) {
117+
return true;
118+
}
119+
}
120+
}
121+
// Message text 2:
122+
// "@summary is not a valid block tag. Should it be an inline tag instead?"
123+
if (message.startsWith("@")) {
124+
int firstSpace = message.indexOf(' ');
125+
if (firstSpace >= 0) {
126+
String tagName = message.substring(1, firstSpace);
127+
if (CUSTOM_ICU_TAGS.contains(tagName)) {
128+
return true;
129+
}
130+
}
131+
}
132+
return false;
133+
}
134+
94135
static ErrorProneEntry addErrorToReportAndReset(Map<String, List<ErrorProneEntry>> errorReport,
95136
ErrorProneEntry crtError) {
96-
if (crtError != null) {
97-
String errorType = crtError.type;
98-
// Fix the severity from parsing, which is never error, to the proper errorprone one
99-
crtError.severity = ErrorProneUtils.getErrorLevel(errorType);
100-
List<ErrorProneEntry> list = errorReport.computeIfAbsent(
101-
errorType, e -> new ArrayList<ErrorProneEntry>());
102-
list.add(crtError);
103-
crtError = null;
104-
}
105137
// We want to reset the currentError after we record it.
106-
// One errorprone issue can take several lines in the log.
138+
// One errorprone issue can take several lines in the log.
107139
// The parsing creates currentError when the start of an issue is detected.
108140
// We add more info to the currentError from the following lines.
109141
// When we find something that does not look like an errorprone line, or at the end of the
@@ -113,6 +145,18 @@ static ErrorProneEntry addErrorToReportAndReset(Map<String, List<ErrorProneEntry
113145
// If we return nothing (void method) we would need to do this in the caller (several times):
114146
// addErrorToReport(errorReport, currentError); => report
115147
// currentError = null; => reset
148+
if (crtError == null) {
149+
return null;
150+
}
151+
if (isCustomIcuTag(crtError)) {
152+
return null;
153+
}
154+
// Fix the severity from parsing, which is never error, to the proper errorprone one
155+
String errorType = crtError.type;
156+
crtError.severity = ErrorProneUtils.getErrorLevel(errorType);
157+
List<ErrorProneEntry> list = errorReport.computeIfAbsent(
158+
errorType, e -> new ArrayList<ErrorProneEntry>());
159+
list.add(crtError);
116160
return null;
117161
}
118162

icu4j/tools/build/src/main/resources/com/ibm/icu/dev/tool/errorprone/errorprone.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ table.sortable tbody tr:nth-child(2n+1) td {
3939
white-space: pre;
4040
}
4141

42+
.tags {
43+
font-size: small;
44+
}
45+
4246
.severity_warning {
4347
color:#aa0;
4448
}

0 commit comments

Comments
 (0)