Switch to UAST 1.3
am: 8b707232af

Change-Id: I159ac4b0dccdd45f1f60ab7a9529c2beaa2581c9
diff --git a/build.gradle b/build.gradle
index eedd62a..24126e6 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,6 +1,6 @@
 buildscript {
-    ext.gradle_version = '3.2.1'
-    ext.studio_version = '26.2.1'
+    ext.gradle_version = '3.4.0-beta01'
+    ext.studio_version = '26.4.0-beta01'
     ext.kotlin_version = '1.3.11'
     repositories {
         google()
diff --git a/src/main/java/com/android/tools/metalava/ComparisonVisitor.kt b/src/main/java/com/android/tools/metalava/ComparisonVisitor.kt
index 77d3dc0..6b703c8 100644
--- a/src/main/java/com/android/tools/metalava/ComparisonVisitor.kt
+++ b/src/main/java/com/android/tools/metalava/ComparisonVisitor.kt
@@ -333,7 +333,17 @@
                                         val simpleType2 = parameter2.type().toCanonicalType()
                                         delta = simpleType1.compareTo(simpleType2)
                                         if (delta != 0) {
-                                            break
+                                            // Special case: Kotlin coroutines
+                                            if (simpleType1.startsWith("kotlin.coroutines.") && simpleType2.startsWith("kotlin.coroutines.")) {
+                                                val t1 = simpleType1.removePrefix("kotlin.coroutines.").removePrefix("experimental.")
+                                                val t2 = simpleType2.removePrefix("kotlin.coroutines.").removePrefix("experimental.")
+                                                delta = t1.compareTo(t2)
+                                                if (delta != 0) {
+                                                    break
+                                                }
+                                            } else {
+                                                break
+                                            }
                                         }
                                     }
                                 }
diff --git a/src/main/java/com/android/tools/metalava/CompatibilityCheck.kt b/src/main/java/com/android/tools/metalava/CompatibilityCheck.kt
index 78aebe1..94ac90b 100644
--- a/src/main/java/com/android/tools/metalava/CompatibilityCheck.kt
+++ b/src/main/java/com/android/tools/metalava/CompatibilityCheck.kt
@@ -510,7 +510,7 @@
             }
         }
 
-        if (new.modifiers.isInline() && new.isKotlin()) {
+        if (new.modifiers.isInline()) {
             val oldTypes = old.typeParameterList().typeParameters()
             val newTypes = new.typeParameterList().typeParameters()
             for (i in 0 until oldTypes.size) {
diff --git a/src/main/java/com/android/tools/metalava/Constants.kt b/src/main/java/com/android/tools/metalava/Constants.kt
index 4e0a3c7..88cd3a7 100644
--- a/src/main/java/com/android/tools/metalava/Constants.kt
+++ b/src/main/java/com/android/tools/metalava/Constants.kt
@@ -32,6 +32,9 @@
 const val ANDROID_REQUIRES_PERMISSION = "android.annotation.RequiresPermission"
 const val RECENTLY_NULLABLE = "androidx.annotation.RecentlyNullable"
 const val RECENTLY_NONNULL = "androidx.annotation.RecentlyNonNull"
+const val ANDROIDX_VISIBLE_FOR_TESTING = "androidx.annotation.VisibleForTesting"
+const val ANDROID_SUPPORT_VISIBLE_FOR_TESTING = "android.support.annotation.VisibleForTesting"
+const val ATTR_OTHERWISE = "otherwise"
 
 const val ENV_VAR_METALAVA_TESTS_RUNNING = "METALAVA_TESTS_RUNNING"
 const val ENV_VAR_METALAVA_DUMP_ARGV = "METALAVA_DUMP_ARGV"
diff --git a/src/main/java/com/android/tools/metalava/DocAnalyzer.kt b/src/main/java/com/android/tools/metalava/DocAnalyzer.kt
index 44eed3b..b831a5b 100644
--- a/src/main/java/com/android/tools/metalava/DocAnalyzer.kt
+++ b/src/main/java/com/android/tools/metalava/DocAnalyzer.kt
@@ -224,7 +224,8 @@
             }
 
             private fun handleKotlinDeprecation(annotation: AnnotationItem, item: Item) {
-                val text = annotation.findAttribute(ATTR_VALUE)?.value?.value()?.toString() ?: return
+                val text = (annotation.findAttribute("message") ?: annotation.findAttribute(ATTR_VALUE))
+                    ?.value?.value()?.toString() ?: return
                 if (text.isBlank() || item.documentation.contains(text)) {
                     return
                 }
diff --git a/src/main/java/com/android/tools/metalava/ExtractAnnotations.kt b/src/main/java/com/android/tools/metalava/ExtractAnnotations.kt
index d69b1af..9076f31 100644
--- a/src/main/java/com/android/tools/metalava/ExtractAnnotations.kt
+++ b/src/main/java/com/android/tools/metalava/ExtractAnnotations.kt
@@ -34,6 +34,7 @@
 import com.android.tools.metalava.model.psi.PsiAnnotationItem
 import com.android.tools.metalava.model.psi.PsiClassItem
 import com.android.tools.metalava.model.psi.PsiMethodItem
+import com.android.tools.metalava.model.psi.UAnnotationItem
 import com.android.tools.metalava.model.visitors.ApiVisitor
 import com.google.common.xml.XmlEscapers
 import com.intellij.psi.JavaRecursiveElementVisitor
@@ -234,26 +235,33 @@
                         )
                     }
 
-                    if (typeDefAnnotation is PsiAnnotationItem && typeDefClass is PsiClassItem) {
-                        val result = AnnotationHolder(
-                            typeDefClass, typeDefAnnotation,
-                            annotationLookup.findRealAnnotation(
-                                typeDefAnnotation.psiAnnotation,
-                                typeDefClass.psiClass,
-                                null
+                    val result =
+                        if (typeDefAnnotation is PsiAnnotationItem && typeDefClass is PsiClassItem) {
+                            AnnotationHolder(
+                                typeDefClass, typeDefAnnotation,
+                                annotationLookup.findRealAnnotation(
+                                    typeDefAnnotation.psiAnnotation,
+                                    typeDefClass.psiClass,
+                                    null
+                                )
                             )
-                        )
-                        classToAnnotationHolder[className] = result
-                        addItem(item, result)
-
-                        if (item is PsiMethodItem && result.uAnnotation != null &&
-                            !reporter.isSuppressed(Errors.RETURNING_UNEXPECTED_CONSTANT)
-                        ) {
-                            verifyReturnedConstants(item, result.uAnnotation, result, className)
+                        } else if (typeDefAnnotation is UAnnotationItem && typeDefClass is PsiClassItem) {
+                            AnnotationHolder(
+                                typeDefClass, typeDefAnnotation, typeDefAnnotation.uAnnotation
+                            )
+                        } else {
+                            continue
                         }
 
-                        continue
+                    classToAnnotationHolder[className] = result
+                    addItem(item, result)
+
+                    if (item is PsiMethodItem && result.uAnnotation != null &&
+                        !reporter.isSuppressed(Errors.RETURNING_UNEXPECTED_CONSTANT)
+                    ) {
+                        verifyReturnedConstants(item, result.uAnnotation, result, className)
                     }
+                    continue
                 }
             }
         }
@@ -469,11 +477,12 @@
     ) {
         val annotationItem = annotationHolder.annotationItem
         val uAnnotation = annotationHolder.uAnnotation
-            ?: if (annotationItem is PsiAnnotationItem) {
-                // Imported annotation
-                JavaUAnnotation.wrap(annotationItem.psiAnnotation)
-            } else {
-                return
+            ?: when (annotationItem) {
+                is UAnnotationItem -> annotationItem.uAnnotation
+                is PsiAnnotationItem ->
+                    // Imported annotation
+                    JavaUAnnotation.wrap(annotationItem.psiAnnotation)
+                else -> return
             }
         val qualifiedName = annotationItem.qualifiedName()
 
diff --git a/src/main/java/com/android/tools/metalava/KotlinInteropChecks.kt b/src/main/java/com/android/tools/metalava/KotlinInteropChecks.kt
index a904af5..278d1c7 100644
--- a/src/main/java/com/android/tools/metalava/KotlinInteropChecks.kt
+++ b/src/main/java/com/android/tools/metalava/KotlinInteropChecks.kt
@@ -95,10 +95,8 @@
             if (checked) {
                 val annotation = method.modifiers.findAnnotation("kotlin.jvm.Throws")
                 if (annotation != null) {
-                    val attribute =
-                        annotation.findAttribute("exceptionClasses") ?: annotation.findAttribute("value")
-                        ?: annotation.attributes().firstOrNull()
-                    if (attribute != null) {
+                    // There can be multiple values
+                    for (attribute in annotation.attributes()) {
                         for (v in attribute.leafValues()) {
                             val source = v.toSource()
                             if (source.endsWith(exception.simpleName() + "::class")) {
diff --git a/src/main/java/com/android/tools/metalava/model/psi/PsiAnnotationItem.kt b/src/main/java/com/android/tools/metalava/model/psi/PsiAnnotationItem.kt
index e8c6acb..decece4 100644
--- a/src/main/java/com/android/tools/metalava/model/psi/PsiAnnotationItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/psi/PsiAnnotationItem.kt
@@ -284,7 +284,7 @@
     override val value: Any?
         get() {
             if (psiValue is PsiLiteral) {
-                return psiValue.value
+                return psiValue.value ?: psiValue.text.removeSurrounding("\"")
             }
 
             val value = ConstantEvaluator.evaluate(null, psiValue)
@@ -292,7 +292,7 @@
                 return value
             }
 
-            return psiValue.text
+            return psiValue.text ?: psiValue.text.removeSurrounding("\"")
         }
 
     override fun value(): Any? = value
diff --git a/src/main/java/com/android/tools/metalava/model/psi/PsiClassItem.kt b/src/main/java/com/android/tools/metalava/model/psi/PsiClassItem.kt
index 564e15c..4a5ba9d 100644
--- a/src/main/java/com/android/tools/metalava/model/psi/PsiClassItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/psi/PsiClassItem.kt
@@ -420,6 +420,8 @@
                 )
             }
 
+            val isKotlin = isKotlin(psiClass)
+
             val constructors: MutableList<PsiConstructorItem> = ArrayList(5)
             for (psiMethod in psiMethods) {
                 if (psiMethod.isPrivate() || psiMethod.isPackagePrivate()) {
@@ -468,7 +470,7 @@
             item.fields = fields
 
             item.properties = emptyList()
-            if (isKotlin(psiClass)) {
+            if (isKotlin) {
                 // Try to initialize the Kotlin properties
                 val properties = mutableListOf<PsiPropertyItem>()
                 for (method in psiMethods) {
diff --git a/src/main/java/com/android/tools/metalava/model/psi/PsiMethodItem.kt b/src/main/java/com/android/tools/metalava/model/psi/PsiMethodItem.kt
index f856c91..c337332 100644
--- a/src/main/java/com/android/tools/metalava/model/psi/PsiMethodItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/psi/PsiMethodItem.kt
@@ -357,9 +357,16 @@
                 // methods with super methods also consider this method non-final.)
                 modifiers.setFinal(false)
             }
-            val parameters = psiMethod.parameterList.parameters.mapIndexed { index, parameter ->
-                PsiParameterItem.create(codebase, parameter, index)
-            }
+            val parameters =
+                if (psiMethod is UMethod) {
+                    psiMethod.uastParameters.mapIndexed { index, parameter ->
+                        PsiParameterItem.create(codebase, parameter, index)
+                    }
+                } else {
+                    psiMethod.parameterList.parameters.mapIndexed { index, parameter ->
+                        PsiParameterItem.create(codebase, parameter, index)
+                    }
+                }
             val returnType = codebase.getType(psiMethod.returnType!!)
             val method = PsiMethodItem(
                 codebase = codebase,
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 3a11295..5ac50e5 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
@@ -16,6 +16,9 @@
 
 package com.android.tools.metalava.model.psi
 
+import com.android.tools.metalava.ANDROIDX_VISIBLE_FOR_TESTING
+import com.android.tools.metalava.ANDROID_SUPPORT_VISIBLE_FOR_TESTING
+import com.android.tools.metalava.ATTR_OTHERWISE
 import com.android.tools.metalava.model.AnnotationItem
 import com.android.tools.metalava.model.Codebase
 import com.android.tools.metalava.model.DefaultModifierList
@@ -24,12 +27,18 @@
 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
 import com.intellij.psi.PsiReferenceExpression
+import com.intellij.psi.PsiPrimitiveType
 import org.jetbrains.kotlin.asJava.elements.KtLightModifierList
+import org.jetbrains.kotlin.asJava.elements.KtLightNullabilityAnnotation
 import org.jetbrains.kotlin.lexer.KtTokens
 import org.jetbrains.kotlin.psi.KtNamedFunction
+import org.jetbrains.uast.UAnnotated
 import org.jetbrains.uast.UMethod
+import org.jetbrains.uast.UVariable
+import org.jetbrains.uast.kotlin.KotlinNullabilityUAnnotation
 
 class PsiModifierItem(
     codebase: Codebase,
@@ -38,8 +47,12 @@
 ) : DefaultModifierList(codebase, flags, annotations), ModifierList, MutableModifierList {
     companion object {
         fun create(codebase: PsiBasedCodebase, element: PsiModifierListOwner, documentation: String?): PsiModifierItem {
-            val modifiers = create(codebase, element)
-
+            val modifiers =
+                if (element is UAnnotated) {
+                    create(codebase, element, element)
+                } else {
+                    create(codebase, element)
+                }
             if (documentation?.contains("@deprecated") == true ||
                 // Check for @Deprecated annotation
                 ((element as? PsiDocCommentOwner)?.isDeprecated == true)
@@ -50,9 +63,7 @@
             return modifiers
         }
 
-        private fun create(codebase: PsiBasedCodebase, element: PsiModifierListOwner): PsiModifierItem {
-            val modifierList = element.modifierList ?: return PsiModifierItem(codebase)
-
+        private fun computeFlag(element: PsiModifierListOwner, modifierList: PsiModifierList): Int {
             var flags = 0
             if (modifierList.hasModifierProperty(PsiModifier.PUBLIC)) {
                 flags = flags or PUBLIC
@@ -139,6 +150,14 @@
                 }
             }
 
+            return flags
+        }
+
+        private fun create(codebase: PsiBasedCodebase, element: PsiModifierListOwner): PsiModifierItem {
+            val modifierList = element.modifierList ?: return PsiModifierItem(codebase)
+
+            var flags = computeFlag(element, modifierList)
+
             val psiAnnotations = modifierList.annotations
             return if (psiAnnotations.isEmpty()) {
                 PsiModifierItem(codebase, flags)
@@ -146,22 +165,16 @@
                 val annotations: MutableList<AnnotationItem> =
                     psiAnnotations.map {
                         val qualifiedName = it.qualifiedName
-                        // TODO: com.android.internal.annotations.VisibleForTesting?
-                        if (qualifiedName == "androidx.annotation.VisibleForTesting" ||
-                            qualifiedName == "android.support.annotation.VisibleForTesting") {
-                            val otherwise = it.findAttributeValue("otherwise")
+                        // Consider also supporting com.android.internal.annotations.VisibleForTesting?
+                        if (qualifiedName == ANDROIDX_VISIBLE_FOR_TESTING ||
+                            qualifiedName == ANDROID_SUPPORT_VISIBLE_FOR_TESTING) {
+                            val otherwise = it.findAttributeValue(ATTR_OTHERWISE)
                             val ref = when {
                                 otherwise is PsiReferenceExpression -> otherwise.referenceName ?: ""
                                 otherwise != null -> otherwise.text
                                 else -> ""
                             }
-                            if (ref.endsWith("PROTECTED")) {
-                                flags = (flags and PUBLIC.inv() and PRIVATE.inv() and INTERNAL.inv()) or PROTECTED
-                            } else if (ref.endsWith("PACKAGE_PRIVATE")) {
-                                flags = (flags and PUBLIC.inv() and PRIVATE.inv() and INTERNAL.inv() and PROTECTED.inv())
-                            } else if (ref.endsWith("PRIVATE") || ref.endsWith("NONE")) {
-                                flags = (flags and PUBLIC.inv() and PROTECTED.inv() and INTERNAL.inv()) or PRIVATE
-                            }
+                            flags = getVisibilityFlag(ref, flags)
                         }
 
                         PsiAnnotationItem.create(codebase, it, qualifiedName)
@@ -170,6 +183,74 @@
             }
         }
 
+        private fun create(
+            codebase: PsiBasedCodebase,
+            element: PsiModifierListOwner,
+            annotated: UAnnotated
+        ): PsiModifierItem {
+            val modifierList = element.modifierList ?: return PsiModifierItem(codebase)
+            var flags = computeFlag(element, modifierList)
+            val uAnnotations = annotated.annotations
+
+            return if (uAnnotations.isEmpty()) {
+                val psiAnnotations = modifierList.annotations
+                if (!psiAnnotations.isEmpty()) {
+                    val annotations: MutableList<AnnotationItem> =
+                        psiAnnotations.map { PsiAnnotationItem.create(codebase, it) }.toMutableList()
+                    PsiModifierItem(codebase, flags, annotations)
+                } else {
+                    PsiModifierItem(codebase, flags)
+                }
+            } else {
+                val isPrimitiveVariable = element is UVariable && element.type is PsiPrimitiveType
+
+                val annotations: MutableList<AnnotationItem> = uAnnotations
+                    // Uast sometimes puts nullability annotations on primitives!?
+                    .filter { !isPrimitiveVariable || it !is KotlinNullabilityUAnnotation }
+                    .map {
+
+                        val qualifiedName = it.qualifiedName
+                        if (qualifiedName == ANDROIDX_VISIBLE_FOR_TESTING ||
+                            qualifiedName == ANDROID_SUPPORT_VISIBLE_FOR_TESTING) {
+                            val otherwise = it.findAttributeValue(ATTR_OTHERWISE)
+                            val ref = when {
+                                otherwise is PsiReferenceExpression -> otherwise.referenceName ?: ""
+                                otherwise != null -> otherwise.asSourceString()
+                                else -> ""
+                            }
+                            flags = getVisibilityFlag(ref, flags)
+                        }
+
+                        UAnnotationItem.create(codebase, it, qualifiedName)
+                    }.toMutableList()
+
+                if (!isPrimitiveVariable) {
+                    val psiAnnotations = modifierList.annotations
+                    if (psiAnnotations.isNotEmpty() && annotations.none { it.isNullnessAnnotation() }) {
+                        val ktNullAnnotation = psiAnnotations.firstOrNull { it is KtLightNullabilityAnnotation }
+                        ktNullAnnotation?.let {
+                            annotations.add(PsiAnnotationItem.create(codebase, it))
+                        }
+                    }
+                }
+
+                PsiModifierItem(codebase, flags, annotations)
+            }
+        }
+
+        /** Modifies the modifier flags based on the VisibleForTesting otherwise constants */
+        private fun getVisibilityFlag(ref: String, flags: Int): Int {
+            return if (ref.endsWith("PROTECTED")) {
+                (flags and PUBLIC.inv() and PRIVATE.inv() and INTERNAL.inv()) or PROTECTED
+            } else if (ref.endsWith("PACKAGE_PRIVATE")) {
+                (flags and PUBLIC.inv() and PRIVATE.inv() and INTERNAL.inv() and PROTECTED.inv())
+            } else if (ref.endsWith("PRIVATE") || ref.endsWith("NONE")) {
+                (flags and PUBLIC.inv() and PROTECTED.inv() and INTERNAL.inv()) or PRIVATE
+            } else {
+                flags
+            }
+        }
+
         fun create(codebase: PsiBasedCodebase, original: PsiModifierItem): PsiModifierItem {
             val originalAnnotations = original.annotations ?: return PsiModifierItem(codebase, original.flags)
             val copy: MutableList<AnnotationItem> = ArrayList(originalAnnotations.size)
diff --git a/src/main/java/com/android/tools/metalava/model/psi/UAnnotationItem.kt b/src/main/java/com/android/tools/metalava/model/psi/UAnnotationItem.kt
new file mode 100644
index 0000000..0d0266e
--- /dev/null
+++ b/src/main/java/com/android/tools/metalava/model/psi/UAnnotationItem.kt
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.metalava.model.psi
+
+import com.android.SdkConstants
+import com.android.tools.lint.detector.api.ConstantEvaluator
+import com.android.tools.metalava.model.AnnotationArrayAttributeValue
+import com.android.tools.metalava.model.AnnotationAttribute
+import com.android.tools.metalava.model.AnnotationAttributeValue
+import com.android.tools.metalava.model.AnnotationItem
+import com.android.tools.metalava.model.AnnotationSingleAttributeValue
+import com.android.tools.metalava.model.AnnotationTarget
+import com.android.tools.metalava.model.ClassItem
+import com.android.tools.metalava.model.DefaultAnnotationItem
+import com.android.tools.metalava.model.Item
+import com.intellij.psi.PsiClass
+import com.intellij.psi.PsiExpression
+import com.intellij.psi.PsiField
+import com.intellij.psi.PsiLiteral
+import com.intellij.psi.PsiMethod
+import com.intellij.psi.impl.JavaConstantExpressionEvaluator
+import org.jetbrains.kotlin.asJava.elements.KtLightNullabilityAnnotation
+import org.jetbrains.uast.UAnnotation
+import org.jetbrains.uast.UBinaryExpression
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.UElement
+import org.jetbrains.uast.UExpression
+import org.jetbrains.uast.ULiteralExpression
+import org.jetbrains.uast.UReferenceExpression
+import org.jetbrains.uast.util.isArrayInitializer
+
+class UAnnotationItem private constructor(
+    override val codebase: PsiBasedCodebase,
+    val uAnnotation: UAnnotation,
+    private val originalName: String?
+) : DefaultAnnotationItem(codebase) {
+    private val qualifiedName = AnnotationItem.mapName(codebase, originalName)
+
+    private var attributes: List<AnnotationAttribute>? = null
+
+    override fun originalName(): String? = originalName
+
+    override fun toString(): String = toSource()
+
+    override fun toSource(target: AnnotationTarget): String {
+        val sb = StringBuilder(60)
+        appendAnnotation(codebase, sb, uAnnotation, originalName, target)
+        return sb.toString()
+    }
+
+    override fun resolve(): ClassItem? {
+        return codebase.findClass(originalName ?: return null)
+    }
+
+    override fun isNonNull(): Boolean {
+        if (uAnnotation.javaPsi is KtLightNullabilityAnnotation &&
+            originalName == ""
+        ) {
+            // Hack/workaround: some UAST annotation nodes do not provide qualified name :=(
+            return true
+        }
+        return super.isNonNull()
+    }
+
+    override fun qualifiedName() = qualifiedName
+
+    override fun attributes(): List<AnnotationAttribute> {
+        if (attributes == null) {
+            val uAttributes = uAnnotation.attributeValues
+            attributes = if (uAttributes.isEmpty()) {
+                emptyList()
+            } else {
+                val list = mutableListOf<AnnotationAttribute>()
+                for (parameter in uAttributes) {
+                    list.add(
+                        UAnnotationAttribute(
+                            codebase,
+                            parameter.name ?: SdkConstants.ATTR_VALUE, parameter.expression
+                        )
+                    )
+                }
+                list
+            }
+        }
+
+        return attributes!!
+    }
+
+    companion object {
+        fun create(codebase: PsiBasedCodebase, uAnnotation: UAnnotation, qualifiedName: String? = uAnnotation.qualifiedName): UAnnotationItem {
+            return UAnnotationItem(codebase, uAnnotation, qualifiedName)
+        }
+
+        fun create(codebase: PsiBasedCodebase, original: UAnnotationItem): UAnnotationItem {
+            return UAnnotationItem(codebase, original.uAnnotation, original.originalName)
+        }
+
+        private fun appendAnnotation(
+            codebase: PsiBasedCodebase,
+            sb: StringBuilder,
+            uAnnotation: UAnnotation,
+            originalName: String?,
+            target: AnnotationTarget
+        ) {
+            val qualifiedName = AnnotationItem.mapName(codebase, originalName, null, target) ?: return
+
+            val attributes = uAnnotation.attributeValues
+            if (attributes.isEmpty()) {
+                sb.append("@$qualifiedName")
+                return
+            }
+
+            sb.append("@")
+            sb.append(qualifiedName)
+            sb.append("(")
+            if (attributes.size == 1 && (attributes[0].name == null || attributes[0].name == SdkConstants.ATTR_VALUE)) {
+                // Special case: omit "value" if it's the only attribute
+                appendValue(codebase, sb, attributes[0].expression, target)
+            } else {
+                var first = true
+                for (attribute in attributes) {
+                    if (first) {
+                        first = false
+                    } else {
+                        sb.append(", ")
+                    }
+                    sb.append(attribute.name ?: SdkConstants.ATTR_VALUE)
+                    sb.append('=')
+                    appendValue(codebase, sb, attribute.expression, target)
+                }
+            }
+            sb.append(")")
+        }
+
+        private fun appendValue(
+            codebase: PsiBasedCodebase,
+            sb: StringBuilder,
+            value: UExpression?,
+            target: AnnotationTarget
+        ) {
+            // Compute annotation string -- we don't just use value.text here
+            // because that may not use fully qualified names, e.g. the source may say
+            //  @RequiresPermission(Manifest.permission.ACCESS_COARSE_LOCATION)
+            // and we want to compute
+            //  @android.support.annotation.RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
+            when (value) {
+                null -> sb.append("null")
+                is ULiteralExpression -> sb.append(CodePrinter.constantToSource(value.value))
+                is UReferenceExpression -> {
+                    val resolved = value.resolve()
+                    when (resolved) {
+                        is PsiField -> {
+                            val containing = resolved.containingClass
+                            if (containing != null) {
+                                // If it's a field reference, see if it looks like the field is hidden; if
+                                // so, inline the value
+                                val cls = codebase.findOrCreateClass(containing)
+                                val initializer = resolved.initializer
+                                if (initializer != null) {
+                                    val fieldItem = cls.findField(resolved.name)
+                                    if (fieldItem == null || fieldItem.isHiddenOrRemoved()) {
+                                        // Use the literal value instead
+                                        val source = getConstantSource(initializer)
+                                        if (source != null) {
+                                            sb.append(source)
+                                            return
+                                        }
+                                    }
+                                }
+                                containing.qualifiedName?.let {
+                                    sb.append(it).append('.')
+                                }
+                            }
+
+                            sb.append(resolved.name)
+                        }
+                        is PsiClass -> resolved.qualifiedName?.let { sb.append(it) }
+                        else -> {
+                            sb.append(value.sourcePsi?.text ?: value.asSourceString())
+                        }
+                    }
+                }
+                is UBinaryExpression -> {
+                    appendValue(codebase, sb, value.leftOperand, target)
+                    sb.append(' ')
+                    sb.append(value.operator.text)
+                    sb.append(' ')
+                    appendValue(codebase, sb, value.rightOperand, target)
+                }
+                is UCallExpression -> {
+                    if (value.isArrayInitializer()) {
+                        sb.append('{')
+                        var first = true
+                        for (initializer in value.valueArguments) {
+                            if (first) {
+                                first = false
+                            } else {
+                                sb.append(", ")
+                            }
+                            appendValue(codebase, sb, initializer, target)
+                        }
+                        sb.append('}')
+                    } else {
+                        println("todo")
+                    }
+                }
+                is UAnnotation -> {
+                    appendAnnotation(codebase, sb, value, value.qualifiedName, target)
+                }
+                else -> {
+                    val source = getConstantSource(value)
+                    if (source != null) {
+                        sb.append(source)
+                        return
+                    }
+                    sb.append(value.sourcePsi?.text ?: value.asSourceString())
+                }
+            }
+        }
+
+        private fun getConstantSource(value: UExpression): String? {
+            val constant = value.evaluate()
+            return CodePrinter.constantToExpression(constant)
+        }
+
+        private fun getConstantSource(value: PsiExpression): String? {
+            val constant = JavaConstantExpressionEvaluator.computeConstantExpression(value, false)
+            return CodePrinter.constantToExpression(constant)
+        }
+    }
+}
+
+class UAnnotationAttribute(
+    codebase: PsiBasedCodebase,
+    override val name: String,
+    psiValue: UExpression
+) : AnnotationAttribute {
+    override val value: AnnotationAttributeValue = UAnnotationValue.create(
+        codebase, psiValue
+    )
+}
+
+abstract class UAnnotationValue : AnnotationAttributeValue {
+    companion object {
+        fun create(codebase: PsiBasedCodebase, value: UExpression): UAnnotationValue {
+            return if (value.isArrayInitializer()) {
+                UAnnotationArrayAttributeValue(codebase, value as UCallExpression)
+            } else {
+                UAnnotationSingleAttributeValue(codebase, value)
+            }
+        }
+    }
+
+    override fun toString(): String = toSource()
+}
+
+class UAnnotationSingleAttributeValue(
+    private val codebase: PsiBasedCodebase,
+    private val psiValue: UExpression
+) : UAnnotationValue(), AnnotationSingleAttributeValue {
+    override val valueSource: String = getText(psiValue)
+    override val value: Any?
+        get() {
+            if (psiValue is ULiteralExpression) {
+                val value = psiValue.value
+                if (value != null) {
+                    return value
+                } else if (psiValue.isNull) {
+                    return null
+                }
+            }
+            if (psiValue is PsiLiteral) {
+                return psiValue.value ?: getText(psiValue).removeSurrounding("\"")
+            }
+
+            val value = ConstantEvaluator.evaluate(null, psiValue)
+            if (value != null) {
+                return value
+            }
+
+            return getText(psiValue).removeSurrounding("\"")
+        }
+
+    override fun value(): Any? = value
+
+    override fun toSource(): String = getText(psiValue)
+
+    override fun resolve(): Item? {
+        if (psiValue is UReferenceExpression) {
+            val resolved = psiValue.resolve()
+            when (resolved) {
+                is PsiField -> return codebase.findField(resolved)
+                is PsiClass -> return codebase.findOrCreateClass(resolved)
+                is PsiMethod -> return codebase.findMethod(resolved)
+            }
+        }
+        return null
+    }
+}
+
+class UAnnotationArrayAttributeValue(codebase: PsiBasedCodebase, private val value: UCallExpression) :
+    UAnnotationValue(), AnnotationArrayAttributeValue {
+    override val values = value.valueArguments.map {
+        create(codebase, it)
+    }.toList()
+
+    override fun toSource(): String = getText(value)
+}
+
+private fun getText(element: UElement): String {
+    return element.sourcePsi?.text ?: element.asSourceString()
+}
\ No newline at end of file
diff --git a/src/main/resources/version.properties b/src/main/resources/version.properties
index 233e17e..0e3b7f6 100644
--- a/src/main/resources/version.properties
+++ b/src/main/resources/version.properties
@@ -2,4 +2,4 @@
 # Version definition
 # This file is read by gradle build scripts, but also packaged with metalava
 # as a resource for the Version classes to read.
-metalavaVersion=1.2.5
+metalavaVersion=1.2.6
diff --git a/src/test/java/com/android/tools/metalava/ApiFileTest.kt b/src/test/java/com/android/tools/metalava/ApiFileTest.kt
index 962f9c6..61bf801 100644
--- a/src/test/java/com/android/tools/metalava/ApiFileTest.kt
+++ b/src/test/java/com/android/tools/metalava/ApiFileTest.kt
@@ -285,7 +285,7 @@
                 package androidx.core.util {
                   public final class TestKt {
                     ctor public TestKt();
-                    method public static inline <K, V> android.util.LruCache<K,V> lruCache(int maxSize, kotlin.jvm.functions.Function2<? super K,? super V,java.lang.Integer> sizeOf = { _, _ -> 1 }, kotlin.jvm.functions.Function1<? super K,? extends V> create = { (V)null }, kotlin.jvm.functions.Function4<? super java.lang.Boolean,? super K,? super V,? super V,kotlin.Unit> onEntryRemoved = { _, _, _, _ ->  });
+                    method public static inline <K, V> android.util.LruCache<K,V> lruCache(int maxSize, kotlin.jvm.functions.Function2<? super K,? super V,java.lang.Integer> sizeOf = { _, _ -> 1 }, kotlin.jvm.functions.Function1<? super K,? extends V> create = { (java.lang.Object)null }, kotlin.jvm.functions.Function4<? super java.lang.Boolean,? super K,? super V,? super V,kotlin.Unit> onEntryRemoved = { _, _, _, _ ->  });
                   }
                 }
                 """,
@@ -457,10 +457,10 @@
                 package test.pkg {
                   public final class TestKt {
                     ctor public TestKt();
-                    method public static inline <T> void a(T t);
-                    method public static inline <reified T> void b(T t);
-                    method public static inline <reified T> void e(T t);
-                    method public static inline <reified T> void f(T, T t);
+                    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);
                   }
                 }
                 """,
@@ -484,7 +484,7 @@
                 package test.pkg {
                   public final class TestKt {
                     ctor public TestKt();
-                    method public static suspend inline Object hello(kotlin.coroutines.experimental.Continuation<? super kotlin.Unit> p);
+                    method public static suspend inline Object hello(@NonNull kotlin.coroutines.Continuation<? super kotlin.Unit> p);
                   }
                 }
                 """,
@@ -3212,8 +3212,8 @@
                     import androidx.annotation.VisibleForTesting;
 
                     @SuppressWarnings({"ClassNameDiffersFromFileName", "WeakerAccess"})
-                    public class ProductionCode {
-                        private ProductionCode() { }
+                    public class ProductionCodeJava {
+                        private ProductionCodeJava() { }
 
                         @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
                         public void shouldBeProtected() {
@@ -3242,7 +3242,7 @@
                     package test.pkg
                     import androidx.annotation.VisibleForTesting
 
-                    open class ProductionCode2 private constructor() {
+                    open class ProductionCodeKotlin private constructor() {
 
                         @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
                         fun shouldBeProtected() {
@@ -3270,10 +3270,10 @@
             ),
             api = """
                 package test.pkg {
-                  public class ProductionCode {
+                  public class ProductionCodeJava {
                     method protected void shouldBeProtected();
                   }
-                  public class ProductionCode2 {
+                  public class ProductionCodeKotlin {
                     method protected final void shouldBeProtected();
                   }
                 }
@@ -3331,4 +3331,4 @@
             )
         )
     }
-}
\ No newline at end of file
+}
diff --git a/src/test/java/com/android/tools/metalava/ApiLintTest.kt b/src/test/java/com/android/tools/metalava/ApiLintTest.kt
index 87d9a74..bcb59a8 100644
--- a/src/test/java/com/android/tools/metalava/ApiLintTest.kt
+++ b/src/test/java/com/android/tools/metalava/ApiLintTest.kt
@@ -1456,7 +1456,7 @@
                     import java.io.InputStream;
 
                     public class CheckFiles {
-                        public MyClass(Context context, File file) {
+                        public CheckFiles(Context context, File file) {
                         }
                         public void ok(int i, File file) { }
                         public void ok(int i, InputStream stream) { }
@@ -1487,7 +1487,7 @@
                     import java.io.InputStream;
 
                     public class CheckFiles {
-                        public MyClass(Context context, File file) {
+                        public CheckFiles(Context context, File file) {
                         }
                         public void ok(int i, File file) { }
                         public void ok(int i, InputStream stream) { }
diff --git a/src/test/java/com/android/tools/metalava/CompatibilityCheckTest.kt b/src/test/java/com/android/tools/metalava/CompatibilityCheckTest.kt
index a457fcd..819bd2b 100644
--- a/src/test/java/com/android/tools/metalava/CompatibilityCheckTest.kt
+++ b/src/test/java/com/android/tools/metalava/CompatibilityCheckTest.kt
@@ -285,6 +285,32 @@
     }
 
     @Test
+    fun `Kotlin Coroutines`() {
+        check(
+            warnings = "",
+            compatibilityMode = false,
+            inputKotlinStyleNulls = true,
+            outputKotlinStyleNulls = true,
+            checkCompatibilityApi = """
+                package test.pkg {
+                  public final class TestKt {
+                    ctor public TestKt();
+                    method public static suspend inline java.lang.Object hello(kotlin.coroutines.experimental.Continuation<? super kotlin.Unit>);
+                  }
+                }
+                """,
+            signatureSource = """
+                package test.pkg {
+                  public final class TestKt {
+                    ctor public TestKt();
+                    method public static suspend inline Object hello(@NonNull kotlin.coroutines.Continuation<? super kotlin.Unit> p);
+                  }
+                }
+                """
+        )
+    }
+
+    @Test
     fun `Add flag new methods but not overrides from platform`() {
         check(
             warnings = """
diff --git a/src/test/java/com/android/tools/metalava/DriverTest.kt b/src/test/java/com/android/tools/metalava/DriverTest.kt
index 780c067..5d521dc 100644
--- a/src/test/java/com/android/tools/metalava/DriverTest.kt
+++ b/src/test/java/com/android/tools/metalava/DriverTest.kt
@@ -131,6 +131,9 @@
         }
     }
 
+    // This is here to make sure we don't have any unexpected random println's
+    // in the source that are left behind after debugging and ends up polluting
+    // the production output
     class OutputForbiddenWriter(private val stream: String) : ByteArrayOutputStream() {
         override fun write(b: ByteArray?, off: Int, len: Int) {
             fail("Unexpected write directly to $stream")
diff --git a/src/test/java/com/android/tools/metalava/KotlinInteropChecksTest.kt b/src/test/java/com/android/tools/metalava/KotlinInteropChecksTest.kt
index f3efebc..037100f 100644
--- a/src/test/java/com/android/tools/metalava/KotlinInteropChecksTest.kt
+++ b/src/test/java/com/android/tools/metalava/KotlinInteropChecksTest.kt
@@ -91,6 +91,7 @@
             extraArguments = arrayOf(ARG_CHECK_KOTLIN_INTEROP),
             warnings = """
                 src/test/pkg/Foo.kt:7: warning: Companion object constants like INTEGER_ONE should be marked @JvmField for Java interoperability; see https://android.github.io/kotlin-guides/interop.html#companion-constants [MissingJvmstatic]
+                src/test/pkg/Foo.kt:10: warning: Companion object constants like WRONG2 should be using @JvmField, not @JvmStatic; see https://android.github.io/kotlin-guides/interop.html#companion-constants [MissingJvmstatic]
                 src/test/pkg/Foo.kt:13: warning: Companion object methods like missing should be marked @JvmStatic for Java interoperability; see https://android.github.io/kotlin-guides/interop.html#companion-functions [MissingJvmstatic]
                 """,
             sourceFiles = *arrayOf(
@@ -105,7 +106,7 @@
                             const val INTEGER_ONE = 1
                             var BIG_INTEGER_ONE = BigInteger.ONE
                             @JvmStatic val WRONG = 2 // not yet flagged
-                            @JvmStatic @JvmField val WRONG2 = 2 // not yet flagged
+                            @JvmStatic @JvmField val WRONG2 = 2
                             @JvmField val ok3 = 3
 
                             fun missing() { }