Add static modifier to nested kotlin classes

Nested classes in kotlin are static by default.
This CL updates KspHasModifiers to add the static
modifier when it is a nested kotlin class without the
inner modifier.

A possible alternative solution is to add `isInner` to XTypeElement
because Room is using isStatic as a proxy to discover inner classes.
I've not implemented that because removing isStatic is not very feasible
from XHasModifiers but we can do a followup CL to divide XHasModifiers
and remove isStatic from there.

Right now, KSP does not report INNER modifier for .class files which is
why I couldn't add a test with compiled code.
https://github.com/google/ksp/pull/232

I've also renamed KspTypeElementTest to XTypeElementTest since
it runs all but 1 test w/ both processors.

Bug: 160322705
Test: XTypeElementTest
Change-Id: Ie07382a8744b26eda3b4454d45ea74bfae71fd70
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspHasModifiers.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspHasModifiers.kt
index 1ab2cce..dd40fc9 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspHasModifiers.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspHasModifiers.kt
@@ -75,6 +75,24 @@
 
     private class Declaration(declaration: KSDeclaration) : KspHasModifiers(declaration)
 
+    private class ClassDeclaration(declaration: KSDeclaration) : KspHasModifiers(declaration) {
+        override fun isStatic(): Boolean {
+            if (declaration.isStatic()) {
+                return true
+            }
+            // inner classes in kotlin are static by default unless they have inner modifier.
+            // for .class files, there is currently a bug:
+            // https://github.com/google/ksp/pull/232 and once it is fixed, inner modifier will
+            // be reported for .class files as well.
+            if (declaration.origin != Origin.JAVA &&
+                declaration.parentDeclaration is KSClassDeclaration // nested class
+            ) {
+                return !declaration.modifiers.contains(Modifier.INNER)
+            }
+            return false
+        }
+    }
+
     private class PropertyField(
         declaration: KSPropertyDeclaration
     ) : KspHasModifiers(declaration) {
@@ -158,7 +176,7 @@
         }
 
         fun create(owner: KSClassDeclaration): XHasModifiers {
-            return Declaration(owner)
+            return ClassDeclaration(owner)
         }
     }
 }
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeElementTest.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
similarity index 95%
rename from room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeElementTest.kt
rename to room/compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
index 6780ed9..ddd18f3 100644
--- a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeElementTest.kt
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
@@ -14,10 +14,8 @@
  * limitations under the License.
  */
 
-package androidx.room.compiler.processing.ksp
+package androidx.room.compiler.processing
 
-import androidx.room.compiler.processing.XMethodElement
-import androidx.room.compiler.processing.XTypeElement
 import androidx.room.compiler.processing.util.Source
 import androidx.room.compiler.processing.util.XTestInvocation
 import androidx.room.compiler.processing.util.getAllFieldNames
@@ -36,7 +34,7 @@
 import org.junit.runners.JUnit4
 
 @RunWith(JUnit4::class)
-class KspTypeElementTest {
+class XTypeElementTest {
     @Test
     fun qualifiedNames() {
         val src1 = Source.kotlin(
@@ -164,7 +162,7 @@
 
     @Test
     fun modifiers() {
-        val src = Source.kotlin(
+        val kotlinSrc = Source.kotlin(
             "Foo.kt",
             """
             open class OpenClass
@@ -173,9 +171,24 @@
             interface MyInterface
             class Final
             private class PrivateClass
+            class OuterKotlinClass {
+                inner class InnerKotlinClass
+                class NestedKotlinClass
+            }
             """.trimIndent()
         )
-        runProcessorTest(sources = listOf(src)) { invocation ->
+        val javaSrc = Source.java(
+            "OuterJavaClass",
+            """
+            public class OuterJavaClass {
+                public class InnerJavaClass {}
+                public static class NestedJavaClass {}
+            }
+            """.trimIndent()
+        )
+        runProcessorTest(
+            sources = listOf(kotlinSrc, javaSrc)
+        ) { invocation ->
             fun getModifiers(element: XTypeElement): Set<String> {
                 val result = mutableSetOf<String>()
                 if (element.isAbstract()) result.add("abstract")
@@ -185,6 +198,7 @@
                 if (element.isPublic()) result.add("public")
                 if (element.isKotlinObject()) result.add("object")
                 if (element.isInterface()) result.add("interface")
+                if (element.isStatic()) result.add("static")
                 return result
             }
 
@@ -212,6 +226,14 @@
                         listOf("final")
                     }
                 )
+            assertThat(getModifiers("OuterKotlinClass.InnerKotlinClass"))
+                .containsExactly("final", "public")
+            assertThat(getModifiers("OuterKotlinClass.NestedKotlinClass"))
+                .containsExactly("final", "public", "static")
+            assertThat(getModifiers("OuterJavaClass.InnerJavaClass"))
+                .containsExactly("public")
+            assertThat(getModifiers("OuterJavaClass.NestedJavaClass"))
+                .containsExactly("public", "static")
         }
     }