Update metalava to work with reified methods
This CL updates metalava to work with the latest UAST
which includes the fix for
https://youtrack.jetbrains.com/issue/KT-34316.
Sadly, we found a new regression (see comment in ApiFileTest)
https://youtrack.jetbrains.com/issue/KT-38173
Test: Unit tests included and updated
Bug: 152039666
Bug: KT-34316
Change-Id: Ic28b1bb39ba6b3fe8551a1c53f060ebbbe09f148
diff --git a/build.gradle.kts b/build.gradle.kts
index 39e8b04..8d9434b 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -54,7 +54,7 @@
}
}
-val studioVersion: String = "27.0.0-beta02"
+val studioVersion: String = "27.1.0-alpha05"
val kotlinVersion: String = "1.3.20"
dependencies {
diff --git a/src/main/java/com/android/tools/metalava/model/psi/PsiModifierItem.kt b/src/main/java/com/android/tools/metalava/model/psi/PsiModifierItem.kt
index fa4cef8..69aa109 100644
--- a/src/main/java/com/android/tools/metalava/model/psi/PsiModifierItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/psi/PsiModifierItem.kt
@@ -25,7 +25,6 @@
import com.android.tools.metalava.model.ModifierList
import com.android.tools.metalava.model.MutableModifierList
import com.intellij.psi.PsiDocCommentOwner
-import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiModifier
import com.intellij.psi.PsiModifierList
import com.intellij.psi.PsiModifierListOwner
@@ -42,7 +41,7 @@
import org.jetbrains.uast.UMethod
import org.jetbrains.uast.UVariable
import org.jetbrains.uast.kotlin.KotlinNullabilityUAnnotation
-import org.jetbrains.uast.kotlin.declarations.KotlinUMethodWithFakeLightDelegate
+import org.jetbrains.uast.kotlin.declarations.KotlinUMethod
class PsiModifierItem(
codebase: Codebase,
@@ -110,8 +109,8 @@
var ktModifierList: KtModifierList? = null
if (modifierList is KtLightModifierList<*>) {
ktModifierList = modifierList.kotlinOrigin
- } else if (modifierList is LightModifierList && element is KotlinUMethodWithFakeLightDelegate) {
- ktModifierList = element.original.modifierList
+ } else if (modifierList is LightModifierList && element is KotlinUMethod) {
+ ktModifierList = element.sourcePsi?.modifierList
}
if (ktModifierList != null) {
if (ktModifierList.hasModifier(KtTokens.VARARG_KEYWORD)) {
@@ -129,9 +128,9 @@
if (ktModifierList.hasModifier(KtTokens.INFIX_KEYWORD)) {
flags = flags or INFIX
}
- if (ktModifierList.hasModifier(KtTokens.CONST_KEYWORD)) {
- flags = flags or CONST
- }
+ if (ktModifierList.hasModifier(KtTokens.CONST_KEYWORD)) {
+ flags = flags or CONST
+ }
if (ktModifierList.hasModifier(KtTokens.OPERATOR_KEYWORD)) {
flags = flags or OPERATOR
}
@@ -139,16 +138,14 @@
flags = flags or INLINE
// Workaround for b/117565118:
- if (element is PsiMethod) {
- val t =
- ((element as? UMethod)?.sourcePsi as? KtNamedFunction)?.typeParameterList?.text ?: ""
- if (t.contains("reified") &&
- !ktModifierList.hasModifier(KtTokens.PRIVATE_KEYWORD) &&
- !ktModifierList.hasModifier(KtTokens.INTERNAL_KEYWORD)
- ) {
- // Switch back from private to public
- visibilityFlags = PUBLIC
- }
+ val func = (element as? UMethod)?.sourcePsi as? KtNamedFunction
+ if (func != null &&
+ (func.typeParameterList?.text ?: "").contains("reified") &&
+ !ktModifierList.hasModifier(KtTokens.PRIVATE_KEYWORD) &&
+ !ktModifierList.hasModifier(KtTokens.INTERNAL_KEYWORD)
+ ) {
+ // Switch back from private to public
+ visibilityFlags = PUBLIC
}
}
if (ktModifierList.hasModifier(KtTokens.SUSPEND_KEYWORD)) {
diff --git a/src/main/java/com/android/tools/metalava/model/psi/PsiTypeItem.kt b/src/main/java/com/android/tools/metalava/model/psi/PsiTypeItem.kt
index ead3577..c76c984 100644
--- a/src/main/java/com/android/tools/metalava/model/psi/PsiTypeItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/psi/PsiTypeItem.kt
@@ -50,7 +50,6 @@
import com.intellij.psi.PsiWildcardType
import com.intellij.psi.util.PsiTypesUtil
import com.intellij.psi.util.TypeConversionUtil
-import org.jetbrains.kotlin.asJava.elements.KtLightTypeParameter
import java.util.function.Predicate
/** Represents a type backed by PSI */
@@ -534,7 +533,7 @@
sb.append(">")
return
} else if (element is PsiTypeParameter) {
- if (element is KtLightTypeParameter && element.kotlinOrigin.text.startsWith("reified")) {
+ if (PsiTypeParameterItem.isReified(element)) {
sb.append("reified ")
}
sb.append(element.name)
diff --git a/src/main/java/com/android/tools/metalava/model/psi/PsiTypeParameterItem.kt b/src/main/java/com/android/tools/metalava/model/psi/PsiTypeParameterItem.kt
index 91d27ee..de15c4a 100644
--- a/src/main/java/com/android/tools/metalava/model/psi/PsiTypeParameterItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/psi/PsiTypeParameterItem.kt
@@ -20,6 +20,7 @@
import com.android.tools.metalava.model.TypeParameterItem
import com.android.tools.metalava.model.psi.ClassType.TYPE_PARAMETER
import com.intellij.psi.PsiTypeParameter
+import org.jetbrains.kotlin.asJava.elements.KotlinLightTypeParameterBuilder
import org.jetbrains.kotlin.asJava.elements.KtLightTypeParameter
class PsiTypeParameterItem(
@@ -42,7 +43,7 @@
override fun bounds(): List<ClassItem> = bounds
override fun isReified(): Boolean {
- return element is KtLightTypeParameter && element.kotlinOrigin.text.startsWith("reified")
+ return isReified(element as? PsiTypeParameter)
}
private lateinit var bounds: List<ClassItem>
@@ -75,5 +76,18 @@
item.initialize(emptyList(), emptyList(), emptyList(), emptyList(), emptyList())
return item
}
+
+ fun isReified(element: PsiTypeParameter?): Boolean {
+ element ?: return false
+ if (element is KtLightTypeParameter &&
+ element.kotlinOrigin.text.startsWith("reified")) {
+ return true
+ } else if (element is KotlinLightTypeParameterBuilder) {
+ if (element.sourcePsi.text.startsWith("reified")) {
+ return true
+ }
+ }
+ return false
+ }
}
}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/metalava/ApiFileTest.kt b/src/test/java/com/android/tools/metalava/ApiFileTest.kt
index 5a62c2a..8c4f3f5 100644
--- a/src/test/java/com/android/tools/metalava/ApiFileTest.kt
+++ b/src/test/java/com/android/tools/metalava/ApiFileTest.kt
@@ -416,27 +416,11 @@
method public final <T> T getSystemService(java.lang.Class<T>);
}
public final class _java_Kt {
- method public inline <T> T systemService1();
+ method public static inline <reified T> T systemService1(test.pkg.Context);
method public static inline java.lang.String systemService2(test.pkg.Context);
}
}
"""
-// b/152039666 parameters from methods using reified types are dropped
-// API should contain <reified T>
-// Actual expected output:
-// api = """
-// package test.pkg {
-// public class Context {
-// ctor public Context();
-// method public final <T> T getSystemService(java.lang.Class<T>);
-// }
-// public final class _java_Kt {
-// method public static inline <reified T> T systemService1(test.pkg.Context);
-// method public static inline java.lang.String systemService2(test.pkg.Context);
-// }
-// }
-// """
-
)
}
@@ -464,25 +448,12 @@
package test.pkg {
public final class TestKt {
method public static inline <T> void a(@Nullable T t);
- method public inline <T> void b();
- method public inline <T> void e();
- method public inline <T> void f();
+ method public static inline <reified T> void b(@Nullable T t);
+ method public static inline <reified T> void e(@Nullable T t);
+ method public static inline <reified T> void f(@Nullable T, @Nullable T t);
}
}
"""
-// b/152039666 parameters from methods using reified types are dropped
-// API should contain <reified T>
-// Actual expected output:
-// api = """
-// package test.pkg {
-// public final class TestKt {
-// method public static inline <T> void a(@Nullable T t);
-// method public static inline <reified T> void b(@Nullable T t);
-// method public static inline <reified T> void e(@Nullable T t);
-// method public static inline <reified T> void f(@Nullable T, @Nullable T t);
-// }
-// }
-// """
)
}
@@ -614,13 +585,12 @@
// Signature format: 3.0
package test.pkg {
public final class TestKt {
- method @UiThread public inline <Args> test.pkg2.NavArgsLazy<Args>! navArgs();
+ method @UiThread public static inline <reified Args> test.pkg2.NavArgsLazy<Args>! navArgs(test.pkg2.Fragment);
}
}
""",
-// b/152039666 parameters from methods using reified types are dropped
-// API should contain <reified T>
-// Actual expected output:
+// Actual expected API is below. However, due to KT-38173 the extends information is
+// missing
// api = """
// // Signature format: 3.0
// package test.pkg {
diff --git a/src/test/java/com/android/tools/metalava/ApiLintTest.kt b/src/test/java/com/android/tools/metalava/ApiLintTest.kt
index be56d35..12532b3 100644
--- a/src/test/java/com/android/tools/metalava/ApiLintTest.kt
+++ b/src/test/java/com/android/tools/metalava/ApiLintTest.kt
@@ -837,6 +837,7 @@
src/android/pkg/CheckSynchronization.java:23: error: Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.pkg.CheckSynchronization.errorMethod3() [VisiblySynchronized] [Rule M5 in go/android-api-guidelines]
src/android/pkg/CheckSynchronization2.kt:5: error: Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.pkg.CheckSynchronization2.errorMethod1() [VisiblySynchronized] [Rule M5 in go/android-api-guidelines]
src/android/pkg/CheckSynchronization2.kt:8: error: Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.pkg.CheckSynchronization2.errorMethod2() [VisiblySynchronized] [Rule M5 in go/android-api-guidelines]
+ src/android/pkg/CheckSynchronization2.kt:13: error: Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.pkg.CheckSynchronization2.errorMethod3() [VisiblySynchronized] [Rule M5 in go/android-api-guidelines]
src/android/pkg/CheckSynchronization2.kt:16: error: Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.pkg.CheckSynchronization2.errorMethod4() [VisiblySynchronized] [Rule M5 in go/android-api-guidelines]
src/android/pkg/CheckSynchronization2.kt:18: error: Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.pkg.CheckSynchronization2.errorMethod5() [VisiblySynchronized] [Rule M5 in go/android-api-guidelines]
""",
diff --git a/src/test/java/com/android/tools/metalava/CompatibilityCheckTest.kt b/src/test/java/com/android/tools/metalava/CompatibilityCheckTest.kt
index 22805d1..bfb4e07 100644
--- a/src/test/java/com/android/tools/metalava/CompatibilityCheckTest.kt
+++ b/src/test/java/com/android/tools/metalava/CompatibilityCheckTest.kt
@@ -2479,20 +2479,10 @@
check(
compatibilityMode = false,
inputKotlinStyleNulls = true,
-// b/152039666 parameters from methods using reified types are dropped
-// API should contain <reified T>, but now it sees it as removed / added methods
-// Actual expected output:
-// warnings = """
-// src/test/pkg/test.kt:5: error: Method test.pkg.TestKt.add made type variable T reified: incompatible change [ChangedThrows]
-// src/test/pkg/test.kt:8: error: Method test.pkg.TestKt.two made type variable S reified: incompatible change [ChangedThrows]
-// """,
warnings = """
- src/test/pkg/test.kt: error: Added method test.pkg.TestKt.add() [AddedMethod]
- TESTROOT/current-api.txt:3: error: Removed method test.pkg.TestKt.add(T) [RemovedMethod]
- src/test/pkg/test.kt: error: Added method test.pkg.TestKt.two() [AddedMethod]
- TESTROOT/current-api.txt:6: error: Removed method test.pkg.TestKt.two(S,T) [RemovedMethod]
- src/test/pkg/test.kt: error: Added method test.pkg.TestKt.unchanged() [AddedMethod]
- TESTROOT/current-api.txt:5: error: Removed method test.pkg.TestKt.unchanged(T) [RemovedMethod] """,
+ src/test/pkg/test.kt:5: error: Method test.pkg.TestKt.add made type variable T reified: incompatible change [ChangedThrows]
+ src/test/pkg/test.kt:8: error: Method test.pkg.TestKt.two made type variable S reified: incompatible change [ChangedThrows]
+ """,
checkCompatibilityApi = """
package test.pkg {
public final class TestKt {