Downgrade "multiple public alternatives" to a warning.
Also add support for reporting warnings which do not fail the build.
Bug: 161156950
Test: atest class2nonsdklisttest
Change-Id: I7bd9e19eae8558f24abd1f0a6f10f9130284e076
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotatedClassContext.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotatedClassContext.java
index a018e1f..8b5a8e1c 100644
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotatedClassContext.java
+++ b/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotatedClassContext.java
@@ -41,14 +41,22 @@
return String.format(Locale.US, signatureFormatString, getClassDescriptor());
}
- @Override
- public void reportError(String message, Object... args) {
+ private String buildReportString(String message, Object... args) {
Formatter error = new Formatter();
error
- .format("%s: %s: ", definingClass.getSourceFileName(), definingClass.getClassName())
- .format(Locale.US, message, args);
+ .format("%s: %s: ", definingClass.getSourceFileName(), definingClass.getClassName())
+ .format(Locale.US, message, args);
+ return error.toString();
+ }
- status.error(error.toString());
+ @Override
+ public void reportError(String message, Object... args) {
+ status.error(buildReportString(message, args));
+ }
+
+ @Override
+ public void reportWarning(String message, Object... args) {
+ status.warning(buildReportString(message, args));
}
}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotatedMemberContext.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotatedMemberContext.java
index 377862c..6276040 100644
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotatedMemberContext.java
+++ b/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotatedMemberContext.java
@@ -46,14 +46,22 @@
getClassDescriptor(), member.getName(), member.getSignature());
}
- @Override
- public void reportError(String message, Object... args) {
+ private String buildReportString(String message, Object... args) {
Formatter error = new Formatter();
error
- .format("%s: %s.%s: ", definingClass.getSourceFileName(),
- definingClass.getClassName(), member.getName())
- .format(Locale.US, message, args);
+ .format("%s: %s.%s: ", definingClass.getSourceFileName(),
+ definingClass.getClassName(), member.getName())
+ .format(Locale.US, message, args);
+ return error.toString();
+ }
- status.error(error.toString());
+ @Override
+ public void reportError(String message, Object... args) {
+ status.error(buildReportString(message, args));
+ }
+
+ @Override
+ public void reportWarning(String message, Object... args) {
+ status.warning(buildReportString(message, args));
}
}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotationContext.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotationContext.java
index ccd3e7a..7ea6807 100644
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotationContext.java
+++ b/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotationContext.java
@@ -20,7 +20,7 @@
/**
*/
-public abstract class AnnotationContext implements ErrorReporter {
+public abstract class AnnotationContext implements StatusReporter {
public final Status status;
public final JavaClass definingClass;
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/ApiResolver.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/ApiResolver.java
index ba8eb08..461bb69 100644
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/ApiResolver.java
+++ b/tools/class2nonsdklist/src/com/android/class2nonsdklist/ApiResolver.java
@@ -62,7 +62,7 @@
public void resolvePublicAlternatives(String publicAlternativesString, String signature,
Integer maxSdkVersion)
throws JavadocLinkSyntaxError, AlternativeNotFoundError,
- RequiredAlternativeNotSpecifiedError {
+ RequiredAlternativeNotSpecifiedError, MultipleAlternativesFoundWarning {
if (Strings.isNullOrEmpty(publicAlternativesString) && maxSdkVersion != null
&& maxSdkVersion >= MIN_SDK_REQUIRING_PUBLIC_ALTERNATIVES) {
throw new RequiredAlternativeNotSpecifiedError();
@@ -96,7 +96,7 @@
if (almostMatches.size() == 0) {
throw new MemberAlternativeNotFoundError(alternative);
} else if (almostMatches.size() > 1) {
- throw new MultipleAlternativesFoundError(alternative, almostMatches);
+ throw new MultipleAlternativesFoundWarning(alternative, almostMatches);
}
}
}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/MultipleAlternativesFoundError.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/MultipleAlternativesFoundWarning.java
similarity index 82%
rename from tools/class2nonsdklist/src/com/android/class2nonsdklist/MultipleAlternativesFoundError.java
rename to tools/class2nonsdklist/src/com/android/class2nonsdklist/MultipleAlternativesFoundWarning.java
index 9347dee..738c906 100644
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/MultipleAlternativesFoundError.java
+++ b/tools/class2nonsdklist/src/com/android/class2nonsdklist/MultipleAlternativesFoundWarning.java
@@ -20,11 +20,11 @@
import java.util.List;
-public class MultipleAlternativesFoundError extends AlternativeNotFoundError {
+public class MultipleAlternativesFoundWarning extends Exception {
public final ApiComponents alternative;
public final List<ApiComponents> almostMatches;
- public MultipleAlternativesFoundError(ApiComponents alternative,
+ public MultipleAlternativesFoundWarning(ApiComponents alternative,
List<ApiComponents> almostMatches) {
this.alternative = alternative;
this.almostMatches = almostMatches;
@@ -32,7 +32,8 @@
@Override
public String toString() {
- return "Alternative " + alternative + " returned multiple matches: "
+ return "Alternative " + alternative + " returned multiple matches. Consider adding method" +
+ " parameters to make the match unique. Matches: "
+ Joiner.on(", ").join(almostMatches);
}
}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/Status.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/Status.java
index 1fd3972..1460a4f 100644
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/Status.java
+++ b/tools/class2nonsdklist/src/com/android/class2nonsdklist/Status.java
@@ -23,6 +23,9 @@
// Highlight "Error:" in red.
private static final String ERROR = "\u001B[31mError: \u001B[0m";
+ // Highlight "Warning:" in yellow.
+ private static final String WARNING = "\u001B[33mWarning: \u001B[0m";
+
private final boolean mDebug;
private boolean mHasErrors;
@@ -48,6 +51,11 @@
mHasErrors = true;
}
+ public void warning(String message, Object... args) {
+ System.err.print(WARNING);
+ System.err.println(String.format(Locale.US, message, args));
+ }
+
public boolean ok() {
return !mHasErrors;
}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/ErrorReporter.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/StatusReporter.java
similarity index 78%
rename from tools/class2nonsdklist/src/com/android/class2nonsdklist/ErrorReporter.java
rename to tools/class2nonsdklist/src/com/android/class2nonsdklist/StatusReporter.java
index 0254e42..5215490 100644
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/ErrorReporter.java
+++ b/tools/class2nonsdklist/src/com/android/class2nonsdklist/StatusReporter.java
@@ -16,10 +16,16 @@
package com.android.class2nonsdklist;
-public interface ErrorReporter {
+public interface StatusReporter {
/**
* Report an error in this context. The final error message will include
* the class and member names, and the source file name.
*/
void reportError(String message, Object... args);
+
+ /**
+ * Report a warning in this context. The final message will include the
+ * class and member names, and the source file name.
+ */
+ void reportWarning(String message, Object... args);
}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/UnsupportedAppUsageAnnotationHandler.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/UnsupportedAppUsageAnnotationHandler.java
index 81e51d9..2bb0da5 100644
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/UnsupportedAppUsageAnnotationHandler.java
+++ b/tools/class2nonsdklist/src/com/android/class2nonsdklist/UnsupportedAppUsageAnnotationHandler.java
@@ -163,6 +163,8 @@
try {
mApiResolver.resolvePublicAlternatives(publicAlternativesString, signature,
maxTargetSdk);
+ } catch (MultipleAlternativesFoundWarning e) {
+ context.reportWarning(e.toString());
} catch (JavadocLinkSyntaxError | AlternativeNotFoundError e) {
context.reportError(e.toString());
} catch (RequiredAlternativeNotSpecifiedError e) {
diff --git a/tools/class2nonsdklist/test/src/com/android/class2nonsdklist/ApiResolverTest.java b/tools/class2nonsdklist/test/src/com/android/class2nonsdklist/ApiResolverTest.java
index 3fd62bb..b51efcd 100644
--- a/tools/class2nonsdklist/test/src/com/android/class2nonsdklist/ApiResolverTest.java
+++ b/tools/class2nonsdklist/test/src/com/android/class2nonsdklist/ApiResolverTest.java
@@ -30,9 +30,7 @@
public class ApiResolverTest extends AnnotationHandlerTestBase {
@Test
- public void testFindPublicAlternativeExactly()
- throws JavadocLinkSyntaxError, AlternativeNotFoundError,
- RequiredAlternativeNotSpecifiedError {
+ public void testFindPublicAlternativeExactly() throws Exception {
Set<String> publicApis = Collections.unmodifiableSet(new HashSet<>(
Arrays.asList("La/b/C;->foo(I)V", "La/b/C;->bar(I)V")));
ApiResolver resolver = new ApiResolver(publicApis);
@@ -40,9 +38,7 @@
}
@Test
- public void testFindPublicAlternativeDeducedPackageName()
- throws JavadocLinkSyntaxError, AlternativeNotFoundError,
- RequiredAlternativeNotSpecifiedError {
+ public void testFindPublicAlternativeDeducedPackageName() throws Exception {
Set<String> publicApis = Collections.unmodifiableSet(new HashSet<>(
Arrays.asList("La/b/C;->foo(I)V", "La/b/C;->bar(I)V")));
ApiResolver resolver = new ApiResolver(publicApis);
@@ -50,9 +46,7 @@
}
@Test
- public void testFindPublicAlternativeDeducedPackageAndClassName()
- throws JavadocLinkSyntaxError, AlternativeNotFoundError,
- RequiredAlternativeNotSpecifiedError {
+ public void testFindPublicAlternativeDeducedPackageAndClassName() throws Exception {
Set<String> publicApis = Collections.unmodifiableSet(new HashSet<>(
Arrays.asList("La/b/C;->foo(I)V", "La/b/C;->bar(I)V")));
ApiResolver resolver = new ApiResolver(publicApis);
@@ -60,9 +54,7 @@
}
@Test
- public void testFindPublicAlternativeDeducedParameterTypes()
- throws JavadocLinkSyntaxError, AlternativeNotFoundError,
- RequiredAlternativeNotSpecifiedError {
+ public void testFindPublicAlternativeDeducedParameterTypes() throws Exception {
Set<String> publicApis = Collections.unmodifiableSet(new HashSet<>(
Arrays.asList("La/b/C;->foo(I)V", "La/b/C;->bar(I)V")));
ApiResolver resolver = new ApiResolver(publicApis);
@@ -70,12 +62,12 @@
}
@Test
- public void testFindPublicAlternativeFailDueToMultipleParameterTypes()
+ public void testFindPublicAlternativeWarnsOnMultipleParameterTypes()
throws SignatureSyntaxError {
Set<String> publicApis = Collections.unmodifiableSet(new HashSet<>(
Arrays.asList("La/b/C;->foo(I)V", "La/b/C;->bar(I)I", "La/b/C;->foo(II)V")));
ApiResolver resolver = new ApiResolver(publicApis);
- MultipleAlternativesFoundError e = expectThrows(MultipleAlternativesFoundError.class,
+ MultipleAlternativesFoundWarning e = expectThrows(MultipleAlternativesFoundWarning.class,
() -> resolver.resolvePublicAlternatives("{@link #foo}", "La/b/C;->bar()V", 1));
assertThat(e.almostMatches).containsExactly(
ApiComponents.fromDexSignature("La/b/C;->foo(I)V"),
@@ -111,9 +103,7 @@
}
@Test
- public void testPublicAlternativesJustPackageAndClassName()
- throws JavadocLinkSyntaxError, AlternativeNotFoundError,
- RequiredAlternativeNotSpecifiedError {
+ public void testPublicAlternativesJustPackageAndClassName() throws Exception {
Set<String> publicApis = Collections.unmodifiableSet(new HashSet<>(
Arrays.asList("La/b/C;->bar(I)V")));
ApiResolver resolver = new ApiResolver(publicApis);
@@ -121,9 +111,7 @@
}
@Test
- public void testPublicAlternativesJustClassName()
- throws JavadocLinkSyntaxError, AlternativeNotFoundError,
- RequiredAlternativeNotSpecifiedError {
+ public void testPublicAlternativesJustClassName() throws Exception {
Set<String> publicApis = Collections.unmodifiableSet(new HashSet<>(
Arrays.asList("La/b/C;->bar(I)V")));
ApiResolver resolver = new ApiResolver(publicApis);
@@ -131,9 +119,7 @@
}
@Test
- public void testNoPublicAlternativesButHasExplanation()
- throws JavadocLinkSyntaxError, AlternativeNotFoundError,
- RequiredAlternativeNotSpecifiedError {
+ public void testNoPublicAlternativesButHasExplanation() throws Exception {
Set<String> publicApis = Collections.unmodifiableSet(new HashSet<>());
ApiResolver resolver = new ApiResolver(publicApis);
resolver.resolvePublicAlternatives("Foo {@code bar}", "La/b/C;->bar()V", 1);
@@ -148,9 +134,7 @@
}
@Test
- public void testNoPublicAlternativesSpecifiedWithMaxLessThanQ()
- throws JavadocLinkSyntaxError, AlternativeNotFoundError,
- RequiredAlternativeNotSpecifiedError {
+ public void testNoPublicAlternativesSpecifiedWithMaxLessThanQ() throws Exception {
Set<String> publicApis = Collections.unmodifiableSet(new HashSet<>());
ApiResolver resolver = new ApiResolver(publicApis);
resolver.resolvePublicAlternatives(null, "La/b/C;->bar()V", 28);