Fields that should be flagged with MissingJvmStatic are now flagged.

Public, non-const properties which are effective constants in a companion
object that are missing @JvmField annotation are now flagged with
MissingJvmStatic warning.

Bug: 138602561

Test: ./gradlew test

Change-Id: I02a8c8ee81e2db619413fdca4a588d1d9bb140f3
diff --git a/src/main/java/com/android/tools/metalava/KotlinInteropChecks.kt b/src/main/java/com/android/tools/metalava/KotlinInteropChecks.kt
index d88ed2a..8c37f34 100644
--- a/src/main/java/com/android/tools/metalava/KotlinInteropChecks.kt
+++ b/src/main/java/com/android/tools/metalava/KotlinInteropChecks.kt
@@ -26,6 +26,8 @@
 import com.android.tools.metalava.model.TypeItem
 import com.android.tools.metalava.model.visitors.ApiVisitor
 import com.intellij.lang.java.lexer.JavaLexer
+import org.jetbrains.kotlin.lexer.KtTokens
+import org.jetbrains.kotlin.psi.KtObjectDeclaration
 import org.jetbrains.kotlin.psi.KtProperty
 import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
 import org.jetbrains.uast.kotlin.KotlinUField
@@ -137,16 +139,40 @@
                             if (modifiers.findAnnotation("kotlin.jvm.JvmField") == null) {
                                 reporter.report(
                                     Issues.MISSING_JVMSTATIC, field,
-                                    "Companion object constants like ${field.name()} should be marked @JvmField for Java interoperability; see https://android.github.io/kotlin-guides/interop.html#companion-constants"
+                                    "Companion object constants like ${field.name()} should be marked @JvmField for Java interoperability; see https://developer.android.com/kotlin/interop#companion_constants"
                                 )
                             } else if (modifiers.findAnnotation("kotlin.jvm.JvmStatic") != null) {
                                 reporter.report(
                                     Issues.MISSING_JVMSTATIC, field,
-                                    "Companion object constants like ${field.name()} should be using @JvmField, not @JvmStatic; see https://android.github.io/kotlin-guides/interop.html#companion-constants"
+                                    "Companion object constants like ${field.name()} should be using @JvmField, not @JvmStatic; see https://developer.android.com/kotlin/interop#companion_constants"
                                 )
                             }
                         }
                     }
+                } else if (sourcePsi is KtObjectDeclaration && sourcePsi.isCompanion()) {
+                    // We are checking if we have public properties that we can expect to be constant
+                    // (that is, declared via `val`) but that aren't declared 'const' in a companion
+                    // object that are not annotated with @JvmField or annotated with @JvmStatic
+                    // https://developer.android.com/kotlin/interop#companion_constants
+                    val ktProperties = sourcePsi.declarations.filter { declaration ->
+                        declaration is KtProperty && !declaration.isVar && !declaration.hasModifier(
+                            KtTokens.CONST_KEYWORD
+                        ) && declaration.annotationEntries.filter {
+                                annotationEntry -> annotationEntry.shortName!!.asString() == "JvmField"
+                        }.isEmpty() }
+                    for (ktProperty in ktProperties) {
+                        if (ktProperty.annotationEntries.filter { annotationEntry -> annotationEntry.shortName!!.asString() == "JvmStatic" }.isEmpty()) {
+                            reporter.report(
+                                Issues.MISSING_JVMSTATIC, ktProperty,
+                                "Companion object constants like ${ktProperty.name} should be marked @JvmField for Java interoperability; see https://developer.android.com/kotlin/interop#companion_constants"
+                            )
+                        } else {
+                            reporter.report(
+                                Issues.MISSING_JVMSTATIC, ktProperty,
+                                "Companion object constants like ${ktProperty.name} should be using @JvmField, not @JvmStatic; see https://developer.android.com/kotlin/interop#companion_constants"
+                            )
+                        }
+                    }
                 }
             }
         }
@@ -201,12 +227,12 @@
                             if (field.modifiers.findAnnotation("kotlin.jvm.JvmStatic") != null) {
                                 reporter.report(
                                     Errors.MISSING_JVMSTATIC, method,
-                                    "Companion object constants should be using @JvmField, not @JvmStatic; see https://android.github.io/kotlin-guides/interop.html#companion-constants"
+                                    "Companion object constants should be using @JvmField, not @JvmStatic; see https://developer.android.com/kotlin/interop#companion_constants"
                                 )
                             } else if (field.modifiers.findAnnotation("kotlin.jvm.JvmField") == null) {
                                 reporter.report(
                                     Errors.MISSING_JVMSTATIC, method,
-                                    "Companion object constants should be marked @JvmField for Java interoperability; see https://android.github.io/kotlin-guides/interop.html#companion-constants"
+                                    "Companion object constants should be marked @JvmField for Java interoperability; see https://developer.android.com/kotlin/interop#companion_constants"
                                 )
                             }
                         }
@@ -215,7 +241,7 @@
             } else if (method.modifiers.findAnnotation("kotlin.jvm.JvmStatic") == null) {
                 reporter.report(
                     Issues.MISSING_JVMSTATIC, method,
-                    "Companion object methods like ${method.name()} should be marked @JvmStatic for Java interoperability; see https://android.github.io/kotlin-guides/interop.html#companion-functions"
+                    "Companion object methods like ${method.name()} should be marked @JvmStatic for Java interoperability; see https://developer.android.com/kotlin/interop#companion_functions"
                 )
             }
         }
diff --git a/src/test/java/com/android/tools/metalava/KotlinInteropChecksTest.kt b/src/test/java/com/android/tools/metalava/KotlinInteropChecksTest.kt
index 49a472c..11ff9fc 100644
--- a/src/test/java/com/android/tools/metalava/KotlinInteropChecksTest.kt
+++ b/src/test/java/com/android/tools/metalava/KotlinInteropChecksTest.kt
@@ -106,8 +106,10 @@
         check(
             extraArguments = arrayOf(ARG_CHECK_KOTLIN_INTEROP),
             warnings = """
-                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]
+                src/test/pkg/Foo.kt:8: warning: Companion object constants like BIG_INTEGER_ONE should be marked @JvmField for Java interoperability; see https://developer.android.com/kotlin/interop#companion_constants [MissingJvmstatic]
+                src/test/pkg/Foo.kt:10: warning: Companion object constants like WRONG should be using @JvmField, not @JvmStatic; see https://developer.android.com/kotlin/interop#companion_constants [MissingJvmstatic]
+                src/test/pkg/Foo.kt:11: warning: Companion object constants like WRONG2 should be using @JvmField, not @JvmStatic; see https://developer.android.com/kotlin/interop#companion_constants [MissingJvmstatic]
+                src/test/pkg/Foo.kt:14: warning: Companion object methods like missing should be marked @JvmStatic for Java interoperability; see https://developer.android.com/kotlin/interop#companion_functions [MissingJvmstatic]
                 """,
             sourceFiles = arrayOf(
                 kotlin(
@@ -119,8 +121,9 @@
                         fun ok1() { }
                         companion object {
                             const val INTEGER_ONE = 1
-                            var BIG_INTEGER_ONE = BigInteger.ONE
-                            @JvmStatic val WRONG = 2 // not yet flagged
+                            val BIG_INTEGER_ONE = BigInteger.ONE
+                            var ok = 1
+                            @JvmStatic val WRONG = 2
                             @JvmStatic @JvmField val WRONG2 = 2
                             @JvmField val ok3 = 3