Fix metalava treatment of "for stubs" annotations
Previously, if an API was annotated with multiple showAnnotations
but also one showForStubsPurposesAnnotations, it would be excluded.
The correct behavior is to include the API if it is annotated with any
showAnnotation that isn't also a showForStubsPurposesAnnotation.
Bug: 170447778
Test: ShowForStubPurposesAnnotationsTest
Test: exp. CL with -showAnnotation TestApi -showForStubs SystemApi
Exempt-From-Owner-Approval: cp
Change-Id: Iac1d6ae6bd544db25c26f64f50e4c4df787dc9f6
Merged-In: Iac1d6ae6bd544db25c26f64f50e4c4df787dc9f6
(cherry picked from commit 0b4293b29b8ff9805f5c0e6a810d8caee3e4d5e9)
diff --git a/src/main/java/com/android/tools/metalava/doclava1/ApiPredicate.kt b/src/main/java/com/android/tools/metalava/doclava1/ApiPredicate.kt
index 4392954..bac6155 100644
--- a/src/main/java/com/android/tools/metalava/doclava1/ApiPredicate.kt
+++ b/src/main/java/com/android/tools/metalava/doclava1/ApiPredicate.kt
@@ -125,8 +125,8 @@
return false
}
- // If the item has a "show" annotation, then return whether it has a "for stubs" annotation
- // or not.
+ // If the item has a "show" annotation, then return whether it *only* has a "for stubs"
+ // show annotation or not.
//
// Note, If the item does not have a show annotation, then it can't have a "for stubs" one,
// because the later must be a subset of the former, which we don't detect in *this*
@@ -134,7 +134,7 @@
// is executed for the parent API, we'd detect it as
// [Issues.SHOWING_MEMBER_IN_HIDDEN_CLASS].
if (item.hasShowAnnotationInherited()) {
- return item.hasShowForStubPurposesAnnotationInherited()
+ return item.onlyShowForStubPurposesInherited()
}
// If this item has neither --show-annotation nor --parent-api-annotation,
// Then defer to the "parent" item (i.e. the enclosing class or package).
diff --git a/src/main/java/com/android/tools/metalava/model/Item.kt b/src/main/java/com/android/tools/metalava/model/Item.kt
index c5d66a6..27c5fe9 100644
--- a/src/main/java/com/android/tools/metalava/model/Item.kt
+++ b/src/main/java/com/android/tools/metalava/model/Item.kt
@@ -161,7 +161,7 @@
fun isKotlin() = !isJava()
fun hasShowAnnotation(): Boolean = modifiers.hasShowAnnotation()
- fun hasShowForStubPurposesAnnotation(): Boolean = modifiers.hasShowForStubPurposesAnnotation()
+ fun onlyShowForStubPurposes(): Boolean = modifiers.onlyShowForStubPurposes()
fun hasHideAnnotation(): Boolean = modifiers.hasHideAnnotations()
fun hasHideMetaAnnotation(): Boolean = modifiers.hasHideMetaAnnotations()
@@ -176,14 +176,14 @@
fun hasShowAnnotationInherited(): Boolean = hasShowAnnotation()
/**
- * Same as [hasShowForStubPurposesAnnotation], except if it's a method, take into account super methods'
- * annotations.
+ * Same as [onlyShowForStubPurposes], except if it's a method,
+ * take into account super methods' annotations.
*
* Unlike classes or fields, methods implicitly inherits visibility annotations, and for
* some visibility calculation we need to take it into account.
* (See ShowAnnotationTest.`Methods inherit showAnnotations but fields and classes don't`.)
*/
- fun hasShowForStubPurposesAnnotationInherited(): Boolean = hasShowForStubPurposesAnnotation()
+ fun onlyShowForStubPurposesInherited(): Boolean = onlyShowForStubPurposes()
fun checkLevel(): Boolean {
return modifiers.checkLevel()
diff --git a/src/main/java/com/android/tools/metalava/model/MethodItem.kt b/src/main/java/com/android/tools/metalava/model/MethodItem.kt
index 98fbf5a..262d78c 100644
--- a/src/main/java/com/android/tools/metalava/model/MethodItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/MethodItem.kt
@@ -523,12 +523,12 @@
}
}
- override fun hasShowForStubPurposesAnnotationInherited(): Boolean {
- if (super.hasShowForStubPurposesAnnotationInherited()) {
+ override fun onlyShowForStubPurposesInherited(): Boolean {
+ if (super.onlyShowForStubPurposesInherited()) {
return true
}
return superMethods().any {
- it.hasShowForStubPurposesAnnotationInherited()
+ it.onlyShowForStubPurposesInherited()
}
}
diff --git a/src/main/java/com/android/tools/metalava/model/ModifierList.kt b/src/main/java/com/android/tools/metalava/model/ModifierList.kt
index 4d2ee67..c3afff6 100644
--- a/src/main/java/com/android/tools/metalava/model/ModifierList.kt
+++ b/src/main/java/com/android/tools/metalava/model/ModifierList.kt
@@ -120,14 +120,16 @@
/**
* Returns true if this modifier list contains any annotations explicitly passed in
- * via [Options.showForStubPurposesAnnotations]
+ * via [Options.showForStubPurposesAnnotations], and this is the only showAnnotation.
*/
- fun hasShowForStubPurposesAnnotation(): Boolean {
+ fun onlyShowForStubPurposes(): Boolean {
if (options.showForStubPurposesAnnotations.isEmpty()) {
return false
}
return annotations().any {
options.showForStubPurposesAnnotations.matches(it)
+ } && !annotations().any {
+ options.showAnnotations.matches(it) && !options.showForStubPurposesAnnotations.matches(it)
}
}
diff --git a/src/test/java/com/android/tools/metalava/ShowForStubPurposesAnnotationTest.kt b/src/test/java/com/android/tools/metalava/ShowForStubPurposesAnnotationTest.kt
index 4254a31..ebb364e 100644
--- a/src/test/java/com/android/tools/metalava/ShowForStubPurposesAnnotationTest.kt
+++ b/src/test/java/com/android/tools/metalava/ShowForStubPurposesAnnotationTest.kt
@@ -57,6 +57,12 @@
public void module() {
}
+ @test.annotation.Hide
+ @test.annotation.ModuleApi
+ @test.annotation.SystemApi
+ public void moduleAndSystem() {
+ }
+
public static class NestedDefault {
public void noAnnotation() {
}
@@ -248,6 +254,7 @@
public class SystemClass {
ctor public SystemClass();
method public void module();
+ method public void moduleAndSystem();
method public void noAnnotation();
method public void referFromModuleToSystem(test.pkg.SystemClass2);
method public void system();
@@ -290,6 +297,7 @@
}
public class SystemClass {
ctor public SystemClass();
+ method public void moduleAndSystem();
method public void noAnnotation();
method public void system();
}
@@ -336,6 +344,7 @@
}
public class SystemClass {
method public void module();
+ method public void moduleAndSystem();
method public void referFromModuleToSystem(test.pkg.SystemClass2);
}
public static class SystemClass.NestedDefault {
@@ -356,6 +365,7 @@
public void noAnnotation() { throw new RuntimeException("Stub!"); }
public void system() { throw new RuntimeException("Stub!"); }
public void module() { throw new RuntimeException("Stub!"); }
+ public void moduleAndSystem() { throw new RuntimeException("Stub!"); }
public void referFromModuleToSystem(test.pkg.SystemClass2 arg) { throw new RuntimeException("Stub!"); }
@SuppressWarnings({"unchecked", "deprecation", "all"})
public static class NestedDefault {