Skip to content

Commit

Permalink
getDeclarationsInSourceOrder: use AA for companion objects
Browse files Browse the repository at this point in the history
Members of companion objects can be compiled into ContainingClass.class
and ContainingClass$Companion.class. Therefore, the total ordering is
not recoverable from class files only.

KSP1's behavior is left unchanged.
  • Loading branch information
ting-yuan committed Sep 12, 2024
1 parent 558a73c commit 5eea483
Show file tree
Hide file tree
Showing 5 changed files with 294 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,8 @@
package com.google.devtools.ksp.impl

import com.google.devtools.ksp.*
import com.google.devtools.ksp.common.JVM_DEFAULT_ANNOTATION_FQN
import com.google.devtools.ksp.common.JVM_DEFAULT_WITHOUT_COMPATIBILITY_ANNOTATION_FQN
import com.google.devtools.ksp.common.JVM_STATIC_ANNOTATION_FQN
import com.google.devtools.ksp.common.JVM_STRICTFP_ANNOTATION_FQN
import com.google.devtools.ksp.common.JVM_SYNCHRONIZED_ANNOTATION_FQN
import com.google.devtools.ksp.common.JVM_TRANSIENT_ANNOTATION_FQN
import com.google.devtools.ksp.common.JVM_VOLATILE_ANNOTATION_FQN
import com.google.devtools.ksp.common.extractThrowsAnnotation
import com.google.devtools.ksp.common.impl.KSNameImpl
import com.google.devtools.ksp.common.impl.KSTypeReferenceSyntheticImpl
import com.google.devtools.ksp.common.impl.RefPosition
import com.google.devtools.ksp.common.impl.findOuterMostRef
import com.google.devtools.ksp.common.impl.findRefPosition
import com.google.devtools.ksp.common.impl.isReturnTypeOfAnnotationMethod
import com.google.devtools.ksp.common.javaModifiers
import com.google.devtools.ksp.common.memoized
import com.google.devtools.ksp.common.*
import com.google.devtools.ksp.common.impl.*
import com.google.devtools.ksp.common.visitor.CollectAnnotatedSymbolsVisitor
import com.google.devtools.ksp.impl.symbol.java.KSAnnotationJavaImpl
import com.google.devtools.ksp.impl.symbol.kotlin.*
Expand Down Expand Up @@ -359,8 +345,18 @@ class ResolverAAImpl(
) {
parentClass = parentClass.parent!!
}
val classId = (parentClass as KSClassDeclarationImpl).ktClassOrObjectSymbol.classId
?: return container.declarations

if (parentClass !is KSClassDeclarationImpl) {
return container.declarations
}

// Members of Foo's companion object are compiled into Foo and Foo$Companion. Total ordering is not recoverable
// from class files. Let's give up and rely on AA for now.
if (parentClass.isCompanionObject) {
return container.declarations
}

val classId = parentClass.ktClassOrObjectSymbol.classId ?: return container.declarations
val virtualFile = analyze {
(fileManager.findClass(classId, analysisScope) as? JavaClassImpl)?.virtualFile
} ?: return container.declarations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ class KSPAATest : AbstractKSPAATest() {
@TestMetadata("declarationOrder.kt")
@Test
fun testDeclarationOrder() {
runTest("../test-utils/testData/api/declarationOrder.kt")
runTest("../kotlin-analysis-api/testData/declarationOrder.kt")
}

@TestMetadata("declarationUtil.kt")
Expand Down
220 changes: 220 additions & 0 deletions kotlin-analysis-api/testData/declarationOrder.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
/*
* Copyright 2022 Google LLC
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
*
* 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.
*/

// WITH_RUNTIME
// TEST PROCESSOR: DeclarationOrderProcessor
// EXPECTED:
// lib.KotlinClass
// b:Ljava/lang/String;
// a:Ljava/lang/String;
// c:Ljava/lang/String;
// isB:Ljava/lang/String;
// isA:Ljava/lang/String;
// isC:Ljava/lang/String;
// noBackingB:Ljava/lang/String;
// noBackingA:Ljava/lang/String;
// noBackingC:Ljava/lang/String;
// noBackingVarB:Ljava/lang/String;
// noBackingVarA:Ljava/lang/String;
// noBackingVarC:Ljava/lang/String;
// privateFun:()V
// protectedFun:()V
// internalFun:()V
// publicFun:()V
// overloaded:(Ljava/lang/String;)Ljava/lang/String;
// overloaded:(I)Ljava/lang/String;
// overloaded:()Ljava/lang/String;
// overloaded:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
// lib.JavaClass
// b:Ljava/lang/String;
// a:Ljava/lang/String;
// c:Ljava/lang/String;
// overloaded:(Ljava/lang/String;)V
// overloaded:(I)V
// overloaded:()V
// overloaded:(Ljava/lang/String;Ljava/lang/String;)V
// KotlinClass
// b:Ljava/lang/String;
// a:Ljava/lang/String;
// c:Ljava/lang/String;
// isB:Ljava/lang/String;
// isA:Ljava/lang/String;
// isC:Ljava/lang/String;
// noBackingB:Ljava/lang/String;
// noBackingA:Ljava/lang/String;
// noBackingC:Ljava/lang/String;
// noBackingVarB:Ljava/lang/String;
// noBackingVarA:Ljava/lang/String;
// noBackingVarC:Ljava/lang/String;
// privateFun:()V
// protectedFun:()V
// internalFun:()V
// publicFun:()V
// overloaded:(Ljava/lang/String;)Ljava/lang/String;
// overloaded:(I)Ljava/lang/String;
// overloaded:()Ljava/lang/String;
// overloaded:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
// JavaClass
// b:Ljava/lang/String;
// a:Ljava/lang/String;
// c:Ljava/lang/String;
// overloaded:(Ljava/lang/String;)V
// overloaded:(I)V
// overloaded:()V
// overloaded:(Ljava/lang/String;Ljava/lang/String;)V
// KotlinCompanion.Companion
// companionObjectProperty:Ljava/lang/String;
// companionObjectPropertyJvmStatic:Ljava/lang/String;
// companionObjectPropertyJvmField:Ljava/lang/String;
// companionObjectPropertyLateinit:Ljava/lang/String;
// companionObjectPropertyConst:Ljava/lang/String;
// companionObjectFunction:(Ljava/lang/String;)V
// companionObjectFunctionJvmStatic:(Ljava/lang/String;)V
// lib.KotlinCompanion.Companion
// companionObjectProperty:Ljava/lang/String;
// companionObjectPropertyJvmStatic:Ljava/lang/String;
// companionObjectPropertyJvmField:Ljava/lang/String;
// companionObjectPropertyLateinit:Ljava/lang/String;
// companionObjectPropertyConst:Ljava/lang/String;
// companionObjectFunction:(Ljava/lang/String;)V
// companionObjectFunctionJvmStatic:(Ljava/lang/String;)V
// equals:(Ljava/lang/Object;)Z
// hashCode:()I
// toString:()Ljava/lang/String;
// <init>:()V
// END
// MODULE: module1
// FILE: lib/KotlinClass.kt
package lib;
class KotlinClass {
val b: String = TODO()
val a: String = TODO()
val c: String = TODO()
val isB:String = TODO()
val isA:String = TODO()
val isC:String = TODO()
val noBackingB: String
get() = ""
val noBackingA: String
get() = ""
val noBackingC: String
get() = ""
var noBackingVarB: String
get() = ""
set(value) {}
var noBackingVarA: String
get() = ""
set(value) {}
var noBackingVarC: String
get() = ""
set(value) {}
private fun privateFun(): Unit = TODO()
protected fun protectedFun(): Unit = TODO()
internal fun internalFun(): Unit = TODO()
fun publicFun(): Unit = TODO()
fun overloaded(x:String): String = TODO()
fun overloaded(x:Int): String = TODO()
fun overloaded(): String = TODO()
fun overloaded(x:String, y:String): String = TODO()
}
// FILE: lib/JavaClass.java
package lib;
public class JavaClass {
// notice the non alphabetic order, which is triggering the problem
String b = "";
String a = "";
String c = "";
void overloaded(String x) {}
void overloaded(int x) {}
void overloaded() {}
void overloaded(String x, String y) {}
}

// FILE: lib/KotlinCompanion.kt
package lib
class KotlinCompanion {
companion object {
val companionObjectProperty: String = "hello"
@JvmStatic
val companionObjectPropertyJvmStatic: String = "hello"
@JvmField val companionObjectPropertyJvmField: String = "hello"
lateinit var companionObjectPropertyLateinit: String
const val companionObjectPropertyConst: String = "hello"
fun companionObjectFunction(companionFunctionParam: String) {}
@JvmStatic
fun companionObjectFunctionJvmStatic(companionFunctionParam: String) {}
}
}

// MODULE: main(module1)
// FILE: main.kt
class KotlinClass {
val b: String? = TODO()
val a: String = TODO()
val c: String? = TODO()
val isB:String = TODO()
val isA:String = TODO()
val isC:String = TODO()
val noBackingB: String
get() = ""
val noBackingA: String
get() = ""
val noBackingC: String
get() = ""
var noBackingVarB: String
get() = ""
set(value) {}
var noBackingVarA: String
get() = ""
set(value) {}
var noBackingVarC: String
get() = ""
set(value) {}
private fun privateFun(): Unit = TODO()
protected fun protectedFun(): Unit = TODO()
internal fun internalFun(): Unit = TODO()
fun publicFun(): Unit = TODO()
fun overloaded(x:String): String = TODO()
fun overloaded(x:Int): String = TODO()
fun overloaded(): String = TODO()
fun overloaded(x:String, y:String): String = TODO()
}
// FILE: JavaClass.java
public class JavaClass {
String b = "";
String a = "";
String c = "";
void overloaded(String x) {}
void overloaded(int x) {}
void overloaded() {}
void overloaded(String x, String y) {}
}

// FILE: KotlinCompanion.kt
class KotlinCompanion {
companion object {
val companionObjectProperty: String = "hello"
@JvmStatic
val companionObjectPropertyJvmStatic: String = "hello"
@JvmField val companionObjectPropertyJvmField: String = "hello"
lateinit var companionObjectPropertyLateinit: String
const val companionObjectPropertyConst: String = "hello"
fun companionObjectFunction(companionFunctionParam: String) {}
@JvmStatic
fun companionObjectFunctionJvmStatic(companionFunctionParam: String) {}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ import com.google.devtools.ksp.KspExperimental
import com.google.devtools.ksp.getClassDeclarationByName
import com.google.devtools.ksp.isConstructor
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSDeclaration
import com.google.devtools.ksp.symbol.KSFunctionDeclaration
import com.google.devtools.ksp.symbol.KSPropertyDeclaration
import com.google.devtools.ksp.symbol.*

@KspExperimental
class DeclarationOrderProcessor : AbstractTestProcessor() {
Expand All @@ -19,11 +16,19 @@ class DeclarationOrderProcessor : AbstractTestProcessor() {
"lib.KotlinClass", "lib.JavaClass",
"KotlinClass", "JavaClass"
)
classNames.map {
val companionClsses = listOf("KotlinCompanion", "lib.KotlinCompanion")
val containers = classNames.map {
checkNotNull(resolver.getClassDeclarationByName(it)) {
"cannot find $it"
}
}.forEach { klass ->
} + companionClsses.map {
checkNotNull(resolver.getClassDeclarationByName(it)) {
"cannot find $it"
}.declarations.single {
it is KSClassDeclaration && it.isCompanionObject
} as KSClassDeclaration
}
containers.forEach { klass ->
result.add(klass.qualifiedName!!.asString())
result.addAll(
resolver.getDeclarationsInSourceOrder(klass).filterIsInstance<KSPropertyDeclaration>().map {
Expand Down
48 changes: 48 additions & 0 deletions test-utils/testData/api/declarationOrder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,22 @@
// overloaded:(I)V
// overloaded:()V
// overloaded:(Ljava/lang/String;Ljava/lang/String;)V
// KotlinCompanion.Companion
// companionObjectProperty:Ljava/lang/String;
// companionObjectPropertyJvmStatic:Ljava/lang/String;
// companionObjectPropertyJvmField:Ljava/lang/String;
// companionObjectPropertyLateinit:Ljava/lang/String;
// companionObjectPropertyConst:Ljava/lang/String;
// companionObjectFunction:(Ljava/lang/String;)V
// companionObjectFunctionJvmStatic:(Ljava/lang/String;)V
// lib.KotlinCompanion.Companion
// companionObjectProperty:Ljava/lang/String;
// companionObjectPropertyJvmStatic:Ljava/lang/String;
// companionObjectPropertyLateinit:Ljava/lang/String;
// companionObjectPropertyConst:Ljava/lang/String;
// companionObjectPropertyJvmField:Ljava/lang/String;
// companionObjectFunction:(Ljava/lang/String;)V
// companionObjectFunctionJvmStatic:(Ljava/lang/String;)V
// equals:(Ljava/lang/Object;)Z
// hashCode:()I
// toString:()Ljava/lang/String;
Expand Down Expand Up @@ -127,6 +143,23 @@ public class JavaClass {
void overloaded() {}
void overloaded(String x, String y) {}
}

// FILE: lib/KotlinCompanion.kt
package lib
class KotlinCompanion {
companion object {
val companionObjectProperty: String = "hello"
@JvmStatic
val companionObjectPropertyJvmStatic: String = "hello"
@JvmField val companionObjectPropertyJvmField: String = "hello"
lateinit var companionObjectPropertyLateinit: String
const val companionObjectPropertyConst: String = "hello"
fun companionObjectFunction(companionFunctionParam: String) {}
@JvmStatic
fun companionObjectFunctionJvmStatic(companionFunctionParam: String) {}
}
}

// MODULE: main(module1)
// FILE: main.kt
class KotlinClass {
Expand Down Expand Up @@ -170,3 +203,18 @@ public class JavaClass {
void overloaded() {}
void overloaded(String x, String y) {}
}

// FILE: KotlinCompanion.kt
class KotlinCompanion {
companion object {
val companionObjectProperty: String = "hello"
@JvmStatic
val companionObjectPropertyJvmStatic: String = "hello"
@JvmField val companionObjectPropertyJvmField: String = "hello"
lateinit var companionObjectPropertyLateinit: String
const val companionObjectPropertyConst: String = "hello"
fun companionObjectFunction(companionFunctionParam: String) {}
@JvmStatic
fun companionObjectFunctionJvmStatic(companionFunctionParam: String) {}
}
}

0 comments on commit 5eea483

Please sign in to comment.