aboutsummaryrefslogtreecommitdiff
path: root/test-utils/src/main
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2023-04-24 05:24:44 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-04-24 05:24:44 +0000
commit3d25c313be6b4163b067093acdd84fb4709a8318 (patch)
treeeb4f6ef1605d14946320f6652a41372d71d2e7ab /test-utils/src/main
parent295843a05a00584ebc2e7f8154fb6a5bf182b3a2 (diff)
parentd168506853c10dacdd1f7f5f13611b895be492a5 (diff)
downloadksp-3d25c313be6b4163b067093acdd84fb4709a8318.tar.gz
Merge tag '1.8.10-1.0.9' am: 74434ab5e5 am: 083ebb0f8b am: 2ff1c5a5fb am: 66b9316e25 am: d168506853
Original change: https://android-review.googlesource.com/c/platform/external/ksp/+/2536510 Change-Id: I52ddbbfc38752704e89aad25e113d266b241d5a3 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
Diffstat (limited to 'test-utils/src/main')
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AbstractFunctionsProcessor.kt33
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AbstractTestProcessor.kt28
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AllFunctionsProcessor.kt82
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotatedUtilProcessor.kt148
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArbitraryClassValueProcessor.kt70
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArgumentProcessor.kt62
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArrayValueProcessor.kt55
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationDefaultValueProcessor.kt49
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationDefaultValuesProcessor.kt48
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationJavaTypeValueProcessor.kt53
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationOnConstructorParameterProcessor.kt47
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationsInDependenciesProcessor.kt93
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AsMemberOfProcessor.kt235
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/BackingFieldProcessor.kt62
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/BaseVisitor.kt26
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/BuiltInTypesProcessor.kt64
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/CheckOverrideProcessor.kt115
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ClassKindsProcessor.kt59
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ClassWithCompanionProcessor.kt49
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ConstPropertiesProcessor.kt39
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ConstructorDeclarationsProcessor.kt89
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/CrossModuleTypeAliasTestProcessor.kt53
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationInconsistencyProcessor.kt48
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationOrderProcessor.kt44
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationPackageNameProcessor.kt74
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationUtilProcessor.kt67
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclaredProcessor.kt25
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DefaultFunctionProcessor.kt116
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DocStringProcessor.kt47
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/EquivalentJavaWildcardProcessor.kt64
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ErrorTypeProcessor.kt83
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeAliasProcessor.kt58
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeAnnotationProcessor.kt36
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeProcessor.kt53
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetAnnotationByTypeProcessor.kt36
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetByNameProcessor.kt63
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetPackageProcessor.kt29
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetSymbolsFromAnnotationProcessor.kt35
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/HelloProcessor.kt51
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ImplicitElementProcessor.kt94
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ImplicitPropertyAccessorProcessor.kt26
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/InheritedTypeAliasProcessor.kt60
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/InnerTypeProcessor.kt71
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaModifierProcessor.kt74
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaNonNullProcessor.kt64
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaSubtypeProcessor.kt78
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaToKotlinMapProcessor.kt75
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaWildcard2Processor.kt66
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/LateinitPropertiesProcessor.kt39
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/LibOriginsProcessor.kt94
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MakeNullableProcessor.kt51
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MangledNamesProcessor.kt81
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MapSignatureProcessor.kt45
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MultiModuleTestProcessor.kt53
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/NestedClassTypeProcessor.kt31
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/NullableTypeProcessor.kt53
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/OverrideeProcessor.kt113
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ParameterTypeProcessor.kt32
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ParentProcessor.kt34
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/PlatformDeclarationProcessor.kt69
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RawTypesProcessor.kt48
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaAsMemberOfProcessor.kt66
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaGetAllMembersProcessor.kt54
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaOverridesProcessor.kt71
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaProcessor.kt50
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaSupertypesProcessor.kt51
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ReferenceElementProcessor.kt96
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ReplaceWithErrorTypeArgsProcessor.kt67
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ResolveJavaTypeProcessor.kt93
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/SealedClassProcessor.kt54
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/SuperTypesProcessor.kt79
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ThrowListProcessor.kt71
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TopLevelMemberProcessor.kt73
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeAliasComparisonProcessor.kt65
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeAliasProcessor.kt86
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeComparisonProcessor.kt78
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeComposureProcessor.kt87
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeParameterEqualsProcessor.kt22
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeParameterReferenceProcessor.kt63
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ValidateProcessor.kt60
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/processor/VisibilityProcessor.kt83
-rw-r--r--test-utils/src/main/kotlin/com/google/devtools/ksp/testutils/AbstractKSPTest.kt228
82 files changed, 5436 insertions, 0 deletions
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AbstractFunctionsProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AbstractFunctionsProcessor.kt
new file mode 100644
index 00000000..2b49854e
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AbstractFunctionsProcessor.kt
@@ -0,0 +1,33 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSFunctionDeclaration
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class AbstractFunctionsProcessor : AbstractTestProcessor() {
+ private val visitor = Visitor()
+
+ override fun toResult(): List<String> {
+ return visitor.abstractFunctionNames.sorted()
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getNewFiles().forEach { it.accept(visitor, Unit) }
+ return emptyList()
+ }
+
+ private class Visitor : KSTopDownVisitor<Unit, Unit>() {
+ val abstractFunctionNames = arrayListOf<String>()
+
+ override fun defaultHandler(node: KSNode, data: Unit) {
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
+ if (function.isAbstract) {
+ abstractFunctionNames += function.simpleName.asString()
+ }
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AbstractTestProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AbstractTestProcessor.kt
new file mode 100644
index 00000000..c6a81876
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AbstractTestProcessor.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.SymbolProcessor
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
+import com.google.devtools.ksp.processing.SymbolProcessorProvider
+
+abstract class AbstractTestProcessor : SymbolProcessor, SymbolProcessorProvider {
+ abstract fun toResult(): List<String>
+
+ override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor = this
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AllFunctionsProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AllFunctionsProcessor.kt
new file mode 100644
index 00000000..65c682b2
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AllFunctionsProcessor.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+class AllFunctionsProcessor : AbstractTestProcessor() {
+ val visitor = AllFunctionsVisitor()
+
+ override fun toResult(): List<String> {
+ return visitor.toResult()
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getNewFiles().forEach { it.accept(visitor, Unit) }
+ return emptyList()
+ }
+
+ class AllFunctionsVisitor : KSVisitorVoid() {
+ private val declarationsByClass = mutableMapOf<String, MutableList<String>>()
+ fun toResult(): List<String> {
+ return declarationsByClass.entries
+ .sortedBy {
+ it.key
+ }.flatMap {
+ listOf(it.key) + it.value
+ }
+ }
+ fun KSFunctionDeclaration.toSignature(): String {
+ return this.simpleName.asString() +
+ "(${this.parameters.map {
+ buildString {
+ append(it.type.resolve().declaration.qualifiedName?.asString())
+ if (it.hasDefault) {
+ append("(hasDefault)")
+ }
+ if (it.isVararg) {
+ append(" ...")
+ }
+ }
+ }.joinToString(",")})" +
+ ": ${this.returnType?.resolve()?.declaration?.qualifiedName?.asString() ?: ""}"
+ }
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
+ val declarations = mutableListOf<String>()
+ // first add properties
+ declarations.addAll(
+ classDeclaration.getAllProperties().map {
+ it.toString()
+ }.sorted()
+ )
+ // then add functions
+ declarations.addAll(
+ classDeclaration.getAllFunctions().map {
+ it.toSignature()
+ }.sorted()
+ )
+ declarationsByClass["class: ${classDeclaration.simpleName.asString()}"] = declarations
+ }
+
+ override fun visitFile(file: KSFile, data: Unit) {
+ file.declarations.forEach { it.accept(this, Unit) }
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotatedUtilProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotatedUtilProcessor.kt
new file mode 100644
index 00000000..954feb43
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotatedUtilProcessor.kt
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.getAnnotationsByType
+import com.google.devtools.ksp.isAnnotationPresent
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+import kotlin.reflect.KClass
+
+class AnnotatedUtilProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ private val annotationKClasses = listOf(
+ ParametersTestAnnotation::class,
+ ParameterArraysTestAnnotation::class,
+ ParametersTestWithNegativeDefaultsAnnotation::class,
+ OuterAnnotation::class
+ )
+ private val visitors = listOf(IsAnnotationPresentVisitor(), GetAnnotationsByTypeVisitor())
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getSymbolsWithAnnotation("com.google.devtools.ksp.processor.Test", true).forEach {
+ results.add("Test: $it")
+ visitors.forEach { visitor -> it.accept(visitor, results) }
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ inner class IsAnnotationPresentVisitor : KSTopDownVisitor<MutableCollection<String>, Unit>() {
+ @OptIn(KspExperimental::class)
+ override fun visitAnnotated(annotated: KSAnnotated, data: MutableCollection<String>) {
+ annotationKClasses.forEach { clazz ->
+ if (annotated.isAnnotationPresent(clazz)) {
+ data.add("IsPresent: $clazz")
+ }
+ }
+ }
+
+ override fun defaultHandler(node: KSNode, data: MutableCollection<String>) {
+ }
+ }
+
+ inner class GetAnnotationsByTypeVisitor : KSTopDownVisitor<MutableCollection<String>, Unit>() {
+ @OptIn(KspExperimental::class)
+ override fun visitAnnotated(annotated: KSAnnotated, data: MutableCollection<String>) {
+ annotationKClasses.forEach { clazz ->
+ annotated.getAnnotationsByType(clazz).forEach { data.add("ByType: ${it.asString()}") }
+ }
+ }
+
+ override fun defaultHandler(node: KSNode, data: MutableCollection<String>) {
+ }
+ }
+}
+
+@Suppress("LongParameterList")
+annotation class ParametersTestAnnotation(
+ val booleanValue: Boolean = false,
+ val byteValue: Byte = 2,
+ val shortValue: Short = 3,
+ val charValue: Char = 'b',
+ val doubleValue: Double = 4.0,
+ val floatValue: Float = 5.0f,
+ val intValue: Int = 6,
+ val longValue: Long = 7L,
+ val stringValue: String = "emptystring",
+ val kClassValue: KClass<*> = ParametersTestAnnotation::class,
+ val enumValue: TestEnum = TestEnum.NONE,
+)
+
+fun ParameterArraysTestAnnotation.asString(): String =
+ "ParameterArraysTestAnnotation" +
+ "[booleanArrayValue=${booleanArrayValue.asList()}," +
+ "byteArrayValue=${byteArrayValue.asList()}," +
+ "shortArrayValue=${shortArrayValue.asList()}," +
+ "charArrayValue=${charArrayValue.asList()}," +
+ "doubleArrayValue=${doubleArrayValue.asList()}," +
+ "floatArrayValue=${floatArrayValue.asList()}," +
+ "intArrayValue=${intArrayValue.asList()}," +
+ "longArrayValue=${longArrayValue.asList()}," +
+ "stringArrayValue=${stringArrayValue.asList()}," +
+ "kClassArrayValue=${kClassArrayValue.asList()}," +
+ "enumArrayValue=${enumArrayValue.asList()}]"
+
+@Suppress("LongParameterList")
+annotation class ParameterArraysTestAnnotation(
+ val booleanArrayValue: BooleanArray = booleanArrayOf(),
+ val byteArrayValue: ByteArray = byteArrayOf(),
+ val shortArrayValue: ShortArray = shortArrayOf(),
+ val charArrayValue: CharArray = charArrayOf(),
+ val doubleArrayValue: DoubleArray = doubleArrayOf(),
+ val floatArrayValue: FloatArray = floatArrayOf(),
+ val intArrayValue: IntArray = intArrayOf(),
+ val longArrayValue: LongArray = longArrayOf(),
+ val stringArrayValue: Array<String> = emptyArray(),
+ val kClassArrayValue: Array<KClass<*>> = emptyArray(),
+ val enumArrayValue: Array<TestEnum> = emptyArray(),
+)
+
+annotation class ParametersTestWithNegativeDefaultsAnnotation(
+ val byteValue: Byte = -2,
+ val shortValue: Short = -3,
+ val doubleValue: Double = -4.0,
+ val floatValue: Float = -5.0f,
+ val intValue: Int = -6,
+ val longValue: Long = -7L,
+)
+
+enum class TestEnum {
+ NONE, VALUE1, VALUE2
+}
+
+annotation class Test
+
+annotation class InnerAnnotation(val value: String = "default")
+
+annotation class OuterAnnotation(
+ val innerAnnotation: InnerAnnotation = InnerAnnotation(),
+)
+
+fun Annotation.asString(): String {
+ return when (this) {
+ is ParameterArraysTestAnnotation -> asString()
+ else -> toString()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArbitraryClassValueProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArbitraryClassValueProcessor.kt
new file mode 100644
index 00000000..26bbb2a9
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArbitraryClassValueProcessor.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KSTypeNotPresentException
+import com.google.devtools.ksp.KSTypesNotPresentException
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.getAnnotationsByType
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import kotlin.reflect.KClass
+
+@KspExperimental
+class AnnotationArbitraryClassValueProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val symbols = resolver.getSymbolsWithAnnotation(
+ "com.google.devtools.ksp.processor.ClassValueAnnotation"
+ )
+ symbols.flatMap {
+ it.getAnnotationsByType(ClassValueAnnotation::class)
+ }.forEach {
+ logAnnotationValues(it)
+ }
+ return emptyList()
+ }
+
+ private fun logAnnotationValues(classValueAnnotation: ClassValueAnnotation) {
+ try {
+ classValueAnnotation.classValue
+ } catch (e: Exception) {
+ assert(e is KSTypeNotPresentException)
+ e as KSTypeNotPresentException
+ result.add(e.ksType.toString())
+ }
+
+ try {
+ classValueAnnotation.classValues
+ } catch (e: Exception) {
+ assert(e is KSTypesNotPresentException)
+ e as KSTypesNotPresentException
+ result.add(e.ksTypes.joinToString())
+ }
+ }
+}
+
+annotation class ClassValueAnnotation(
+ val classValue: KClass<*>,
+ val classValues: Array<KClass<*>>
+)
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArgumentProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArgumentProcessor.kt
new file mode 100644
index 00000000..68e263c6
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArgumentProcessor.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSType
+import com.google.devtools.ksp.symbol.KSValueArgument
+import com.google.devtools.ksp.symbol.KSVisitorVoid
+
+class AnnotationArgumentProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val visitor = ArgumentVisitor()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getSymbolsWithAnnotation("Bar", true).forEach {
+ it.annotations.forEach { it.arguments.forEach { it.accept(visitor, Unit) } }
+ }
+
+ val C = resolver.getClassDeclarationByName("C")
+ C?.annotations?.first()?.arguments?.forEach { results.add(it.value.toString()) }
+ val ThrowsClass = resolver.getClassDeclarationByName("ThrowsClass")
+ ThrowsClass?.declarations?.filter {
+ it.simpleName.asString() == "throwsException"
+ }?.forEach {
+ it.annotations.single().annotationType.resolve().declaration.let {
+ results.add(it.toString())
+ }
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ inner class ArgumentVisitor : KSVisitorVoid() {
+ override fun visitValueArgument(valueArgument: KSValueArgument, data: Unit) {
+ if (valueArgument.value is KSType) {
+ results.add((valueArgument.value as KSType).declaration.toString())
+ } else {
+ results.add(valueArgument.value.toString())
+ }
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArrayValueProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArrayValueProcessor.kt
new file mode 100644
index 00000000..e82a3252
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArrayValueProcessor.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+
+class AnnotationArrayValueProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val ktClass = resolver.getClassDeclarationByName("KotlinAnnotated")!!
+ logAnnotations(ktClass)
+ val javaClass = resolver.getClassDeclarationByName("JavaAnnotated")!!
+ logAnnotations(javaClass)
+ return emptyList()
+ }
+
+ private fun logAnnotations(classDeclaration: KSClassDeclaration) {
+ result.add(classDeclaration.qualifiedName!!.asString())
+ classDeclaration.annotations.forEach { annotation ->
+ result.add("${annotation.shortName.asString()} ->")
+ annotation.arguments.forEach {
+ val value = it.value
+ val key = it.name?.asString()
+ if (value is Array<*>) {
+ result.add("$key = [${value.joinToString(", ")}]")
+ } else {
+ result.add("$key = ${it.value}")
+ }
+ }
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationDefaultValueProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationDefaultValueProcessor.kt
new file mode 100644
index 00000000..bd2c1aae
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationDefaultValueProcessor.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.isDefault
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+
+class AnnotationDefaultValueProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val ktClass = resolver.getClassDeclarationByName(resolver.getKSNameFromString("A"))!!
+ logAnnotations(ktClass)
+ val javaClass = resolver.getClassDeclarationByName(resolver.getKSNameFromString("JavaAnnotated"))!!
+ logAnnotations(javaClass)
+ return emptyList()
+ }
+
+ private fun logAnnotations(classDeclaration: KSClassDeclaration) {
+ classDeclaration.annotations.forEach { annotation ->
+ result.add(
+ "${annotation.shortName.asString()} -> ${annotation.arguments.map{
+ "${it.name?.asString()}:${it.value}:${it.isDefault()}"
+ }.joinToString(",")}"
+ )
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationDefaultValuesProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationDefaultValuesProcessor.kt
new file mode 100644
index 00000000..2637cb2f
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationDefaultValuesProcessor.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+
+class AnnotationDefaultValuesProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val ktClass = resolver.getClassDeclarationByName(resolver.getKSNameFromString("A"))!!
+ logAnnotations(ktClass)
+ val javaClass = resolver.getClassDeclarationByName(resolver.getKSNameFromString("JavaAnnotated"))!!
+ logAnnotations(javaClass)
+ return emptyList()
+ }
+
+ private fun logAnnotations(classDeclaration: KSClassDeclaration) {
+ classDeclaration.annotations.forEach { annotation ->
+ result.add(
+ "${annotation.shortName.asString()} -> ${annotation.defaultArguments.map{
+ "${it.name?.asString()}:${it.value}"
+ }.joinToString(",")}"
+ )
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationJavaTypeValueProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationJavaTypeValueProcessor.kt
new file mode 100644
index 00000000..e59763de
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationJavaTypeValueProcessor.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+
+class AnnotationJavaTypeValueProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val javaClass = resolver.getClassDeclarationByName("JavaAnnotated")!!
+ logAnnotations(javaClass)
+ return emptyList()
+ }
+
+ private fun logAnnotations(classDeclaration: KSClassDeclaration) {
+ result.add(classDeclaration.qualifiedName!!.asString())
+ classDeclaration.annotations.forEach { annotation ->
+ result.add("${annotation.shortName.asString()} ->")
+ annotation.arguments.forEach {
+ val value = it.value
+ val key = it.name?.asString()
+ if (value is Array<*>) {
+ result.add("$key = [${value.joinToString(", ")}]")
+ } else {
+ result.add("$key = ${it.value}")
+ }
+ }
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationOnConstructorParameterProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationOnConstructorParameterProcessor.kt
new file mode 100644
index 00000000..1b7b0349
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationOnConstructorParameterProcessor.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getDeclaredFunctions
+import com.google.devtools.ksp.getDeclaredProperties
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+class AnnotationOnConstructorParameterProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getAllFiles().first().declarations.single { it.qualifiedName!!.asString() == "Sample" }.let { clz ->
+ clz as KSClassDeclaration
+ val prop1 = clz.getAllProperties().single { it.simpleName.asString() == "fullName" }
+ val prop2 = clz.getDeclaredProperties().single { it.simpleName.asString() == "fullName" }
+ prop1.annotations.forEach { anno ->
+ results.add(anno.shortName.asString())
+ }
+ results.add((prop1 === prop2).toString())
+ val fun1 = clz.getAllFunctions().single { it.simpleName.asString() == "foo" }
+ val fun2 = clz.getDeclaredFunctions().single { it.simpleName.asString() == "foo" }
+ results.add((fun1 === fun2).toString())
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationsInDependenciesProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationsInDependenciesProcessor.kt
new file mode 100644
index 00000000..f80b7ef7
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationsInDependenciesProcessor.kt
@@ -0,0 +1,93 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class AnnotationsInDependenciesProcessor : AbstractTestProcessor() {
+ private val results = mutableListOf<String>()
+ override fun toResult() = results
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ // NOTE: There are two cases this test ignores.
+ // a) For property annotations with target, they get added to the property getter/setter whereas it would show
+ // on the property as well if it was in kotlin source. This test expects it in both for kotlin source
+ // whereas it expects it only in the getter/setter for compiled kotlin source
+ // b) When an annotation without a target is used in a constructor (with field), that annotation is not copied
+ // to the backing field for .class files. The assertion line in test ignores it (see the NoTargetAnnotation
+ // output difference for the DataClass)
+ addToResults(resolver, "main.KotlinClass")
+ addToResults(resolver, "lib.KotlinClass")
+ addToResults(resolver, "main.DataClass")
+ addToResults(resolver, "lib.DataClass")
+ return emptyList()
+ }
+
+ private fun addToResults(resolver: Resolver, qName: String) {
+ results.add("$qName ->")
+ val collected = collectAnnotations(resolver, qName)
+ val signatures = collected.flatMap { (annotated, annotations) ->
+ val annotatedSignature = annotated.toSignature()
+ annotations.map {
+ "$annotatedSignature : ${it.toSignature()}"
+ }
+ }.sorted()
+ results.addAll(signatures)
+ }
+
+ private fun collectAnnotations(resolver: Resolver, qName: String): Map<KSAnnotated, List<KSAnnotation>> {
+ val output = mutableMapOf<KSAnnotated, List<KSAnnotation>>()
+ resolver.getClassDeclarationByName(qName)?.accept(
+ AnnotationVisitor(),
+ output
+ )
+ return output
+ }
+
+ private fun KSAnnotated.toSignature(): String {
+ return when (this) {
+ is KSClassDeclaration -> "class " + (qualifiedName ?: simpleName).asString()
+ is KSPropertyDeclaration -> "property ${simpleName.asString()}"
+ is KSFunctionDeclaration -> "function ${simpleName.asString()}"
+ is KSValueParameter -> name?.let {
+ "parameter ${it.asString()}"
+ } ?: "no-name-value-parameter"
+ is KSPropertyGetter -> "getter of ${receiver.toSignature()}"
+ is KSPropertySetter -> "setter of ${receiver.toSignature()}"
+ else -> {
+ error("unexpected annotated")
+ }
+ }
+ }
+
+ private fun KSAnnotation.toSignature(): String {
+ val type = this.annotationType.resolve().declaration.let {
+ (it.qualifiedName ?: it.simpleName).asString()
+ }
+ val args = this.arguments.map {
+ "[${it.name?.asString()} = ${it.value}]"
+ }.joinToString(",")
+ return "$type{$args}"
+ }
+
+ class AnnotationVisitor : KSTopDownVisitor<MutableMap<KSAnnotated, List<KSAnnotation>>, Unit>() {
+ override fun defaultHandler(node: KSNode, data: MutableMap<KSAnnotated, List<KSAnnotation>>) {
+ }
+
+ override fun visitAnnotated(annotated: KSAnnotated, data: MutableMap<KSAnnotated, List<KSAnnotation>>) {
+ val annotations = annotated.annotations.toList()
+ if (annotations.isNotEmpty()) {
+ data[annotated] = annotations
+ }
+ super.visitAnnotated(annotated, data)
+ }
+
+ override fun visitTypeReference(
+ typeReference: KSTypeReference,
+ data: MutableMap<KSAnnotated, List<KSAnnotation>>
+ ) {
+ // don't traverse type references
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AsMemberOfProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AsMemberOfProcessor.kt
new file mode 100644
index 00000000..7c260375
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AsMemberOfProcessor.kt
@@ -0,0 +1,235 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.getDeclaredFunctions
+import com.google.devtools.ksp.isConstructor
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+@Suppress("unused") // used by generated tests
+class AsMemberOfProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ // keep a list of all signatures we generate and ensure equals work as expected
+ private val functionsBySignature = mutableMapOf<String, MutableSet<KSFunction>>()
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val base = resolver.getClassDeclarationByName("Base")!!
+ val child1 = resolver.getClassDeclarationByName("Child1")!!
+ addToResults(resolver, base, child1.asStarProjectedType())
+ val child2 = resolver.getClassDeclarationByName("Child2")!!
+ addToResults(resolver, base, child2.asStarProjectedType())
+ val child2WithString = resolver.getDeclaration<KSPropertyDeclaration>("child2WithString")
+ addToResults(resolver, base, child2WithString.type.resolve())
+
+ // check cases where given type is not a subtype
+ val notAChild = resolver.getClassDeclarationByName("NotAChild")!!
+ addToResults(resolver, base, notAChild.asStarProjectedType())
+ val listOfStrings = resolver.getDeclaration<KSPropertyDeclaration>("listOfStrings").type.resolve()
+ val setOfStrings = resolver.getDeclaration<KSPropertyDeclaration>("setOfStrings").type.resolve()
+ val listClass = resolver.getClassDeclarationByName("kotlin.collections.List")!!
+ val setClass = resolver.getClassDeclarationByName("kotlin.collections.Set")!!
+ val listGet = listClass.getAllFunctions().first {
+ it.simpleName.asString() == "get"
+ }
+ results.add("List#get")
+ results.add("listOfStrings: " + resolver.asMemberOfSignature(listGet, listOfStrings))
+ results.add("setOfStrings: " + resolver.asMemberOfSignature(listGet, setOfStrings))
+
+ val setContains = setClass.getAllFunctions().first {
+ it.simpleName.asString() == "contains"
+ }
+ results.add("Set#contains")
+ results.add("listOfStrings: " + resolver.asMemberOfSignature(setContains, listOfStrings))
+ results.add("setOfStrings: " + resolver.asMemberOfSignature(setContains, setOfStrings))
+
+ val javaBase = resolver.getClassDeclarationByName("JavaBase")!!
+ val javaChild1 = resolver.getClassDeclarationByName("JavaChild1")!!
+ addToResults(resolver, javaBase, javaChild1.asStarProjectedType())
+
+ val fileLevelFunction = resolver.getDeclaration<KSFunctionDeclaration>("fileLevelFunction")
+ results.add("fileLevelFunction: " + resolver.asMemberOfSignature(fileLevelFunction, listOfStrings))
+
+ // TODO we should eventually support this, probably as different asReceiverOf kind of API
+ val fileLevelExtensionFunction = resolver.getDeclaration<KSFunctionDeclaration>("fileLevelExtensionFunction")
+ results.add(
+ "fileLevelExtensionFunction: " +
+ resolver.asMemberOfSignature(fileLevelExtensionFunction, listOfStrings)
+ )
+
+ val fileLevelProperty = resolver.getDeclaration<KSPropertyDeclaration>("fileLevelProperty")
+ results.add("fileLevelProperty: " + resolver.asMemberOfSignature(fileLevelProperty, listOfStrings))
+
+ val errorType = resolver.getDeclaration<KSPropertyDeclaration>("errorType").type.resolve()
+ results.add("errorType: " + resolver.asMemberOfSignature(listGet, errorType))
+
+ // make sure values are cached
+ val first = listGet.asMemberOf(listOfStrings)
+ val second = listGet.asMemberOf(listOfStrings)
+ if (first !== second) {
+ results.add("cache error, repeated computation")
+ }
+
+ // validate equals implementation
+ // all functions with the same signature should be equal to each-other unless there is an error / incomplete
+ // type in them
+ val notEqualToItself = functionsBySignature.filter { (_, functions) ->
+ functions.size != 1
+ }.keys
+ results.add("expected comparison failures")
+ results.addAll(notEqualToItself)
+ // make sure we don't have any false positive equals
+ functionsBySignature.forEach { (signature, functions) ->
+ functionsBySignature.forEach { (otherSignature, otherFunctions) ->
+ if (signature != otherSignature && functions.any { otherFunctions.contains(it) }) {
+ results.add("Unexpected equals between $otherSignature and $signature")
+ }
+ }
+ }
+ val javaImpl = resolver.getClassDeclarationByName("JavaImpl")!!
+ val getX = javaImpl.getDeclaredFunctions().first { it.simpleName.asString() == "getX" }
+ val getY = javaImpl.getDeclaredFunctions().first { it.simpleName.asString() == "getY" }
+ val setY = javaImpl.getDeclaredFunctions().first { it.simpleName.asString() == "setY" }
+ results.add(getX.asMemberOf(javaImpl.asStarProjectedType()).toSignature())
+ results.add(getY.asMemberOf(javaImpl.asStarProjectedType()).toSignature())
+ results.add(setY.asMemberOf(javaImpl.asStarProjectedType()).toSignature())
+ return emptyList()
+ }
+
+ private inline fun <reified T : KSDeclaration> Resolver.getDeclaration(name: String): T {
+ return getNewFiles().first {
+ it.fileName == "Input.kt"
+ }.declarations.filterIsInstance<T>().first {
+ it.simpleName.asString() == name
+ }
+ }
+
+ private fun addToResults(resolver: Resolver, baseClass: KSClassDeclaration, child: KSType) {
+ results.add(child.toSignature())
+ val baseProperties = baseClass.getAllProperties()
+ val baseFunction = baseClass.getDeclaredFunctions().filterNot { it.isConstructor() }
+ results.addAll(
+ baseProperties.map { property ->
+ val typeSignature = resolver.asMemberOfSignature(
+ property = property,
+ containing = child
+ )
+ "${property.simpleName.asString()}: $typeSignature"
+ }
+ )
+ results.addAll(
+ baseFunction.map { function ->
+ val functionSignature = resolver.asMemberOfSignature(
+ function = function,
+ containing = child
+ )
+ "${function.simpleName.asString()}: $functionSignature"
+ }
+ )
+ }
+
+ private fun Resolver.asMemberOfSignature(
+ function: KSFunctionDeclaration,
+ containing: KSType
+ ): String {
+ val result = kotlin.runCatching {
+ function.asMemberOf(containing).also {
+ if (it !== function.asMemberOf(containing)) {
+ results.add("cache error, repeated computation")
+ }
+ }
+ }
+ return if (result.isSuccess) {
+ val ksFunction = result.getOrThrow()
+ val signature = ksFunction.toSignature()
+ // record it to validate equality against other signatures
+ functionsBySignature.getOrPut(signature) {
+ mutableSetOf()
+ }.add(ksFunction)
+ signature
+ } else {
+ result.exceptionOrNull()!!.toSignature()
+ }
+ }
+
+ private fun Resolver.asMemberOfSignature(
+ property: KSPropertyDeclaration,
+ containing: KSType
+ ): String {
+ val result = kotlin.runCatching {
+ property.asMemberOf(containing).also {
+ if (it !== property.asMemberOf(containing)) {
+ results.add("cache error, repeated computation")
+ }
+ }
+ }
+ return if (result.isSuccess) {
+ result.getOrThrow().toSignature()
+ } else {
+ result.exceptionOrNull()!!.toSignature()
+ }
+ }
+
+ private fun Throwable.toSignature() = "${this::class.qualifiedName}: $message"
+ private fun KSType.toSignature(): String {
+ val name = this.declaration.qualifiedName?.asString()
+ ?: this.declaration.simpleName.asString()
+ val qName = name + nullability.toSignature()
+ if (arguments.toList().isEmpty()) {
+ return qName
+ }
+ val args = arguments.joinToString(", ") {
+ it.type?.resolve()?.toSignature() ?: "no-type"
+ }
+ return "$qName<$args>"
+ }
+
+ private fun KSTypeParameter.toSignature(): String {
+ val boundsSignature = if (bounds.toList().isEmpty()) {
+ ""
+ } else {
+ bounds.joinToString(
+ separator = ", ",
+ prefix = ": "
+ ) {
+ it.resolve().toSignature()
+ }
+ }
+ val varianceSignature = if (variance.label.isBlank()) {
+ ""
+ } else {
+ "${variance.label} "
+ }
+ val name = this.name.asString()
+ return "$varianceSignature$name$boundsSignature"
+ }
+
+ private fun KSFunction.toSignature(): String {
+ val returnType = this.returnType?.toSignature() ?: "no-return-type"
+ val params = parameterTypes.joinToString(", ") {
+ it?.toSignature() ?: "no-type-param"
+ }
+ val paramTypeArgs = this.typeParameters.joinToString(", ") {
+ it.toSignature()
+ }
+ val paramTypesSignature = if (paramTypeArgs.isBlank()) {
+ ""
+ } else {
+ "<$paramTypeArgs>"
+ }
+ val receiverSignature = if (extensionReceiverType != null) {
+ extensionReceiverType!!.toSignature() + "."
+ } else {
+ ""
+ }
+ return "$receiverSignature$paramTypesSignature($params) -> $returnType"
+ }
+
+ private fun Nullability.toSignature() = when (this) {
+ Nullability.NULLABLE -> "?"
+ Nullability.NOT_NULL -> "!!"
+ Nullability.PLATFORM -> ""
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/BackingFieldProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/BackingFieldProcessor.kt
new file mode 100644
index 00000000..ed4d8f39
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/BackingFieldProcessor.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+@Suppress("unused") // used in tests
+@OptIn(KspExperimental::class)
+open class BackingFieldProcessor : AbstractTestProcessor() {
+ lateinit var results: List<String>
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ results = listOf("lib", "main").flatMap { pkg ->
+ resolver.getDeclarationsFromPackage(pkg)
+ .flatMap { declaration ->
+ val properties = mutableListOf<KSPropertyDeclaration>()
+ declaration.accept(AllMembersVisitor(), properties)
+ properties
+ }.map {
+ "${it.qualifiedName?.asString()}: ${it.hasBackingField}"
+ }.sorted()
+ }
+ return emptyList()
+ }
+
+ private class AllMembersVisitor : KSTopDownVisitor<MutableList<KSPropertyDeclaration>, Unit>() {
+ override fun defaultHandler(node: KSNode, data: MutableList<KSPropertyDeclaration>) {
+ }
+
+ override fun visitPropertyDeclaration(
+ property: KSPropertyDeclaration,
+ data: MutableList<KSPropertyDeclaration>
+ ) {
+ data.add(property)
+ super.visitPropertyDeclaration(property, data)
+ }
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/BaseVisitor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/BaseVisitor.kt
new file mode 100644
index 00000000..1f7838dd
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/BaseVisitor.kt
@@ -0,0 +1,26 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+import com.google.devtools.ksp.symbol.KSFile
+import com.google.devtools.ksp.symbol.KSFunctionDeclaration
+import com.google.devtools.ksp.symbol.KSVisitorVoid
+
+open class BaseVisitor : KSVisitorVoid() {
+ override fun visitClassDeclaration(type: KSClassDeclaration, data: Unit) {
+ for (declaration in type.declarations) {
+ declaration.accept(this, Unit)
+ }
+ }
+
+ override fun visitFile(file: KSFile, data: Unit) {
+ for (declaration in file.declarations) {
+ declaration.accept(this, Unit)
+ }
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
+ for (declaration in function.declarations) {
+ declaration.accept(this, Unit)
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/BuiltInTypesProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/BuiltInTypesProcessor.kt
new file mode 100644
index 00000000..fd5f87a1
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/BuiltInTypesProcessor.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+open class BuiltInTypesProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val typeCollector = TypeCollectorNoAccessor()
+ val types = mutableSetOf<KSType>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+ val ignoredNames = mutableSetOf<String>()
+
+ files.forEach {
+ it.accept(typeCollector, types)
+ }
+
+ val builtInTypes = listOf<KSType>(
+ resolver.builtIns.annotationType,
+ resolver.builtIns.anyType,
+ resolver.builtIns.arrayType,
+ resolver.builtIns.booleanType,
+ resolver.builtIns.byteType,
+ resolver.builtIns.charType,
+ resolver.builtIns.doubleType,
+ resolver.builtIns.floatType,
+ resolver.builtIns.intType,
+ resolver.builtIns.iterableType,
+ resolver.builtIns.longType,
+ resolver.builtIns.nothingType,
+ resolver.builtIns.numberType,
+ resolver.builtIns.shortType,
+ resolver.builtIns.stringType,
+ resolver.builtIns.unitType
+ ).sortedBy { it.toString() }
+
+ val collectedTypes = types.sortedBy { it.toString() }
+
+ results.addAll(builtInTypes.zip(collectedTypes).map { (b, c) -> "$b: " + if (b == c) "OK" else "FAIL" })
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/CheckOverrideProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/CheckOverrideProcessor.kt
new file mode 100644
index 00000000..0eefc142
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/CheckOverrideProcessor.kt
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.getDeclaredFunctions
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+class CheckOverrideProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ fun checkOverride(overrider: KSDeclaration, overridee: KSDeclaration, containing: KSClassDeclaration? = null) {
+ results.add(
+ "${overrider.qualifiedName?.asString()} overrides ${overridee.qualifiedName?.asString()}: " +
+ "${containing?.let { resolver.overrides(overrider, overridee, containing) }
+ ?: resolver.overrides(overrider, overridee)}"
+ )
+ }
+ val javaList = resolver.getClassDeclarationByName(resolver.getKSNameFromString("JavaList"))
+ as KSClassDeclaration
+ val kotlinList = resolver.getClassDeclarationByName(resolver.getKSNameFromString("KotlinList"))
+ as KSClassDeclaration
+ val getFunKt = resolver.getSymbolsWithAnnotation("GetAnno").single() as KSFunctionDeclaration
+ val getFunJava = javaList.getAllFunctions().single { it.simpleName.asString() == "get" }
+ val fooFunJava = javaList.getDeclaredFunctions().single { it.simpleName.asString() == "foo" }
+ val fooFunKt = resolver.getSymbolsWithAnnotation("FooAnno").single() as KSFunctionDeclaration
+ val foooFunKt = resolver.getSymbolsWithAnnotation("BarAnno").single() as KSFunctionDeclaration
+ val equalFunKt = kotlinList.getDeclaredFunctions().single { it.simpleName.asString() == "equals" }
+ val equalFunJava = javaList.getAllFunctions().single { it.simpleName.asString() == "equals" }
+ val bazPropKt = resolver.getSymbolsWithAnnotation("BazAnno").single() as KSPropertyDeclaration
+ val baz2PropKt = resolver.getSymbolsWithAnnotation("Baz2Anno").single() as KSPropertyDeclaration
+ val bazzPropKt = resolver.getSymbolsWithAnnotation("BazzAnno")
+ .filterIsInstance<KSPropertyDeclaration>().single()
+ val bazz2PropKt = resolver.getSymbolsWithAnnotation("Bazz2Anno").single() as KSPropertyDeclaration
+ checkOverride(getFunKt, getFunJava)
+ checkOverride(fooFunKt, fooFunJava)
+ checkOverride(foooFunKt, fooFunJava)
+ checkOverride(fooFunKt, fooFunKt)
+ checkOverride(equalFunKt, equalFunJava)
+ checkOverride(bazPropKt, baz2PropKt)
+ checkOverride(bazPropKt, bazz2PropKt)
+ checkOverride(bazzPropKt, bazz2PropKt)
+ checkOverride(bazzPropKt, baz2PropKt)
+ checkOverride(bazPropKt, bazPropKt)
+ val JavaImpl = resolver.getClassDeclarationByName("JavaImpl")!!
+ val MyInterface = resolver.getClassDeclarationByName("MyInterface")!!
+ val MyInterface2 = resolver.getClassDeclarationByName("MyInterface2")!!
+ val MyInterface2ImplWithoutType = resolver.getClassDeclarationByName("MyInterface2ImplWithoutType")!!
+ val MyInterface2ImplWithType = resolver.getClassDeclarationByName("MyInterface2ImplWithType")!!
+ val getX = JavaImpl.getDeclaredFunctions().first { it.simpleName.asString() == "getX" }
+ val getY = JavaImpl.getDeclaredFunctions().first { it.simpleName.asString() == "getY" }
+ val setY = JavaImpl.getDeclaredFunctions().first { it.simpleName.asString() == "setY" }
+ val setX = JavaImpl.getDeclaredFunctions().first { it.simpleName.asString() == "setX" }
+ val myInterfaceX = MyInterface.declarations.first { it.simpleName.asString() == "x" }
+ val myInterfaceY = MyInterface.declarations.first { it.simpleName.asString() == "y" }
+ val myInterface2receiveList = MyInterface2.declarations.single()
+ val myInterface2ImplWithoutTypereceiveList = MyInterface2ImplWithoutType.declarations.single()
+ val myInterface2ImplWithTypereceiveList = MyInterface2ImplWithType.declarations.single()
+ checkOverride(getY, getX)
+ checkOverride(getY, myInterfaceX)
+ checkOverride(getX, myInterfaceX)
+ checkOverride(setY, myInterfaceY)
+ checkOverride(setX, myInterfaceX)
+ checkOverride(getY, getY)
+ checkOverride(myInterfaceX, getY)
+ checkOverride(myInterfaceX, getX)
+ checkOverride(myInterfaceY, setY)
+ checkOverride(myInterfaceY, myInterfaceY)
+ checkOverride(myInterface2receiveList, myInterface2ImplWithoutTypereceiveList)
+ checkOverride(myInterface2ImplWithoutTypereceiveList, myInterface2receiveList)
+ checkOverride(myInterface2ImplWithTypereceiveList, myInterface2receiveList)
+ checkOverride(myInterface2ImplWithTypereceiveList, myInterface2ImplWithoutTypereceiveList)
+
+ val JavaDifferentReturnTypes =
+ resolver.getClassDeclarationByName("JavaDifferentReturnType")!!
+ val diffGetX = JavaDifferentReturnTypes.getDeclaredFunctions()
+ .first { it.simpleName.asString() == "foo" }
+ checkOverride(diffGetX, fooFunJava)
+ val base = resolver.getClassDeclarationByName("Base")!!
+ val baseF1 = base.declarations.filter { it.simpleName.asString() == "f1" }.single()
+ val baseProp = base.declarations.filter { it.simpleName.asString() == "prop" }.single()
+ val myInterface3 = resolver.getClassDeclarationByName("MyInterface3")!!
+ val myInterfaceF1 = myInterface3.declarations.filter { it.simpleName.asString() == "f1" }.single()
+ val myInterfaceProp = myInterface3.declarations.filter { it.simpleName.asString() == "prop" }.single()
+ val baseOverride = resolver.getClassDeclarationByName("BaseOverride")!!
+ checkOverride(baseF1, myInterfaceF1, baseOverride)
+ checkOverride(baseProp, myInterfaceProp, baseOverride)
+ val jbase = resolver.getClassDeclarationByName("JBase")!!
+ val jBaseOverride = resolver.getClassDeclarationByName("JBaseOverride")!!
+ val jbaseProp = jbase.declarations.single { it.simpleName.asString() == "getProp" }
+ checkOverride(jbaseProp, myInterfaceProp, jBaseOverride)
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ClassKindsProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ClassKindsProcessor.kt
new file mode 100644
index 00000000..f2d46467
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ClassKindsProcessor.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+open class ClassKindsProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ fun KSClassDeclaration.pretty(): String = "${qualifiedName!!.asString()}: $classKind"
+ val files = resolver.getNewFiles()
+ files.forEach {
+ it.accept(
+ object : KSTopDownVisitor<Unit, Unit>() {
+ override fun defaultHandler(node: KSNode, data: Unit) = Unit
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
+ results.add(classDeclaration.pretty())
+ super.visitClassDeclaration(classDeclaration, data)
+ }
+ },
+ Unit
+ )
+ }
+
+ results.add(resolver.getClassDeclarationByName("kotlin.Any")!!.pretty())
+ results.add(resolver.getClassDeclarationByName("kotlin.Annotation")!!.pretty())
+ results.add(resolver.getClassDeclarationByName("kotlin.Deprecated")!!.pretty())
+ results.add(resolver.getClassDeclarationByName("kotlin.Double.Companion")!!.pretty())
+ results.add(resolver.getClassDeclarationByName("kotlin.DeprecationLevel")!!.pretty())
+ results.add(resolver.getClassDeclarationByName("kotlin.DeprecationLevel.WARNING")!!.pretty())
+
+ results.sort()
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ClassWithCompanionProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ClassWithCompanionProcessor.kt
new file mode 100644
index 00000000..fb2b0e1e
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ClassWithCompanionProcessor.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+import com.google.devtools.ksp.symbol.KSFile
+import com.google.devtools.ksp.symbol.KSVisitorVoid
+
+class ClassWithCompanionProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val visitor = CompanionVisitor()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getNewFiles().forEach { it.accept(CompanionVisitor(), Unit) }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ inner class CompanionVisitor : KSVisitorVoid() {
+ override fun visitFile(file: KSFile, data: Unit) {
+ file.declarations.forEach { it.accept(this, Unit) }
+ }
+
+ override fun visitClassDeclaration(type: KSClassDeclaration, data: Unit) {
+ results.add("${type.simpleName.asString()}:${type.isCompanionObject}")
+ type.declarations.forEach { it.accept(this, Unit) }
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ConstPropertiesProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ConstPropertiesProcessor.kt
new file mode 100644
index 00000000..eebdafce
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ConstPropertiesProcessor.kt
@@ -0,0 +1,39 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.symbol.Modifier
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class ConstPropertiesProcessor : AbstractTestProcessor() {
+ private val visitor = Visitor()
+
+ override fun toResult(): List<String> {
+ return visitor.constPropertiesNames.sorted()
+ }
+
+ @OptIn(KspExperimental::class)
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getDeclarationsFromPackage("foo.compiled").forEach {
+ it.accept(visitor, Unit)
+ }
+ resolver.getNewFiles().forEach { it.accept(visitor, Unit) }
+ return emptyList()
+ }
+
+ private class Visitor : KSTopDownVisitor<Unit, Unit>() {
+ val constPropertiesNames = arrayListOf<String>()
+
+ override fun defaultHandler(node: KSNode, data: Unit) {
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ if (Modifier.CONST in property.modifiers) {
+ constPropertiesNames += property.simpleName.asString()
+ }
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ConstructorDeclarationsProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ConstructorDeclarationsProcessor.kt
new file mode 100644
index 00000000..ff51f80c
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ConstructorDeclarationsProcessor.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.getConstructors
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+class ConstructorDeclarationsProcessor : AbstractTestProcessor() {
+ val visitor = ConstructorsVisitor()
+
+ override fun toResult(): List<String> {
+ return visitor.toResult()
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getAllFiles().forEach { it.accept(visitor, Unit) }
+ val classNames = visitor.classNames().toList() // copy
+ // each class has a cousin in the lib package, visit them as well, make sure
+ // we report the same structure when they are compiled code as well
+ classNames.forEach {
+ resolver
+ .getClassDeclarationByName("lib.${it.simpleName.asString()}")
+ ?.accept(visitor, Unit)
+ }
+ return emptyList()
+ }
+
+ class ConstructorsVisitor : KSVisitorVoid() {
+ private val declarationsByClass = LinkedHashMap<KSClassDeclaration, MutableList<String>>()
+ fun classNames() = declarationsByClass.keys
+ fun toResult(): List<String> {
+ return declarationsByClass.entries
+ .sortedBy {
+ // sort by simple name to get cousin classes next to each-other
+ // since we traverse the lib after main, lib will be the second one
+ // because sortedBy is stable sort
+ it.key.simpleName.asString()
+ }.flatMap {
+ listOf("class: " + it.key.qualifiedName!!.asString()) + it.value
+ }
+ }
+ fun KSFunctionDeclaration.toSignature(): String {
+ return this.simpleName.asString() +
+ "(${this.parameters.map {
+ buildString {
+ append(it.type.resolve().declaration.qualifiedName?.asString())
+ if (it.hasDefault) {
+ append("(hasDefault)")
+ }
+ }
+ }.joinToString(",")})" +
+ ": ${this.returnType?.resolve()?.declaration?.qualifiedName?.asString()
+ ?: "<no-return>"}"
+ }
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
+ val declarations = mutableListOf<String>()
+ declarations.addAll(
+ classDeclaration.getConstructors().map {
+ it.toSignature()
+ }.sorted()
+ )
+ // TODO add some assertions that if we go through he path of getDeclarations
+ // we still find the same constructors
+ declarationsByClass[classDeclaration] = declarations
+ }
+
+ override fun visitFile(file: KSFile, data: Unit) {
+ file.declarations.forEach { it.accept(this, Unit) }
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/CrossModuleTypeAliasTestProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/CrossModuleTypeAliasTestProcessor.kt
new file mode 100644
index 00000000..36c8554c
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/CrossModuleTypeAliasTestProcessor.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+
+class CrossModuleTypeAliasTestProcessor : AbstractTestProcessor() {
+ private val results = mutableListOf<String>()
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val target = resolver.getClassDeclarationByName("TestTarget")
+ val classes = mutableSetOf<KSClassDeclaration>()
+ val classCollector = object : BaseVisitor() {
+ override fun visitClassDeclaration(type: KSClassDeclaration, data: Unit) {
+ if (classes.add(type)) {
+ super.visitClassDeclaration(type, data)
+ }
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ results.add(
+ property.type.resolve().declaration.let {
+ it.qualifiedName!!.asString() + "(${it.origin})"
+ }
+ )
+ }
+ }
+ target?.accept(classCollector, Unit)
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationInconsistencyProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationInconsistencyProcessor.kt
new file mode 100644
index 00000000..c580d037
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationInconsistencyProcessor.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+
+class DeclarationInconsistencyProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val numberClass = resolver.getClassDeclarationByName("kotlin.Number")!!
+ val serializable = numberClass.superTypes.first {
+ it.resolve().declaration.qualifiedName?.asString() == "java.io.Serializable"
+ }.resolve().declaration as KSClassDeclaration
+ val serizableDirect = resolver.getClassDeclarationByName("java.io.Serializable")!!
+ results.add("via type: ${serializable.qualifiedName?.asString()}")
+ serializable.getAllFunctions().forEach {
+ results.add(it.simpleName.asString())
+ }
+ results.add("via find declaration: ${serizableDirect.qualifiedName?.asString()}")
+ serizableDirect.getAllFunctions().forEach {
+ results.add(it.simpleName.asString())
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationOrderProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationOrderProcessor.kt
new file mode 100644
index 00000000..6d9b9f61
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationOrderProcessor.kt
@@ -0,0 +1,44 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.getClassDeclarationByName
+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
+
+@KspExperimental
+class DeclarationOrderProcessor : AbstractTestProcessor() {
+ private val result = mutableListOf<String>()
+ override fun toResult() = result
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val classNames = listOf(
+ "lib.KotlinClass", "lib.JavaClass",
+ "KotlinClass", "JavaClass"
+ )
+ classNames.map {
+ checkNotNull(resolver.getClassDeclarationByName(it)) {
+ "cannot find $it"
+ }
+ }.forEach { klass ->
+ result.add(klass.qualifiedName!!.asString())
+ result.addAll(
+ resolver.getDeclarationsInSourceOrder(klass).filterIsInstance<KSPropertyDeclaration>().map {
+ it.toSignature(resolver)
+ }
+ )
+ result.addAll(
+ resolver.getDeclarationsInSourceOrder(klass).filterIsInstance<KSFunctionDeclaration>().map {
+ it.toSignature(resolver)
+ }
+ )
+ }
+ return emptyList()
+ }
+
+ private fun KSDeclaration.toSignature(
+ resolver: Resolver
+ ) = "${simpleName.asString()}:${resolver.mapToJvmSignature(this)}"
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationPackageNameProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationPackageNameProcessor.kt
new file mode 100644
index 00000000..7eb809fe
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationPackageNameProcessor.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class DeclarationPackageNameProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result.sorted()
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val visitor = NameCollector()
+ resolver.getNewFiles().forEach { it.accept(visitor, result) }
+ listOf("K1", "J1").mapNotNull {
+ resolver.getClassDeclarationByName(resolver.getKSNameFromString(it))
+ }.forEach {
+ it.accept(visitor, result)
+ }
+ return emptyList()
+ }
+}
+
+class NameCollector : KSTopDownVisitor<MutableCollection<String>, Unit>() {
+
+ override fun defaultHandler(node: KSNode, data: MutableCollection<String>) {}
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: MutableCollection<String>) {
+ classDeclaration.packageName.asString().let {
+ data.add("${if (it == "") "<no name>" else it}:${classDeclaration.simpleName.asString()}")
+ }
+ super.visitClassDeclaration(classDeclaration, data)
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: MutableCollection<String>) {
+ function.packageName.asString().let { packageName ->
+ val packageNamePrefix = if (packageName == "") "<no name>" else packageName
+ val parentDeclaration = function.parentDeclaration
+ val parentPrefix = if (parentDeclaration == null) {
+ ""
+ } else {
+ "${parentDeclaration.simpleName.asString()}."
+ }
+ data.add("$packageNamePrefix:$parentPrefix${function.simpleName.asString()}")
+ }
+ super.visitFunctionDeclaration(function, data)
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: MutableCollection<String>) {
+ property.packageName.asString().let {
+ data.add("${if (it == "") "<no name>" else it}:${property.simpleName.asString()}")
+ }
+ super.visitPropertyDeclaration(property, data)
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationUtilProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationUtilProcessor.kt
new file mode 100644
index 00000000..15bbf140
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclarationUtilProcessor.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.*
+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.KSNode
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class DeclarationUtilProcessor : AbstractTestProcessor() {
+ private val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val visitor = DeclarationCollector()
+ resolver.getNewFiles().forEach { it.accept(visitor, result) }
+ return emptyList()
+ }
+}
+
+class DeclarationCollector : KSTopDownVisitor<MutableCollection<String>, Unit>() {
+ override fun defaultHandler(node: KSNode, data: MutableCollection<String>) {
+ }
+
+ private fun KSDeclaration.toSignature(): String {
+ qualifiedName?.let {
+ return it.asString()
+ }
+ val parentSignature = parentDeclaration?.toSignature() ?: ""
+ return "$parentSignature / ${simpleName.asString()}"
+ }
+
+ override fun visitDeclaration(declaration: KSDeclaration, data: MutableCollection<String>) {
+ data.add(
+ "${declaration.toSignature()}: " + listOf(
+ "internal" to declaration.isInternal(),
+ "local" to declaration.isLocal(),
+ "private" to declaration.isPrivate(),
+ "protected" to declaration.isProtected(),
+ "public" to declaration.isPublic(),
+ "open" to declaration.isOpen()
+ ).filter { it.second }.joinToString(" ") {
+ it.first
+ }
+ )
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclaredProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclaredProcessor.kt
new file mode 100644
index 00000000..23997b36
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DeclaredProcessor.kt
@@ -0,0 +1,25 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+
+class DeclaredProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val sub = resolver.getClassDeclarationByName("Sub")!!
+ val base = resolver.getClassDeclarationByName("Base")!!
+ val javasource = resolver.getClassDeclarationByName("JavaSource")!!
+ result.add("Base class declared functions:")
+ sub.declarations.forEach { result.add(it.toString()) }
+ result.add("Sub class declared functions:")
+ base.declarations.forEach { result.add(it.toString()) }
+ result.add("JavaSource class declared functions:")
+ javasource.declarations.forEach { result.add(it.toString()) }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DefaultFunctionProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DefaultFunctionProcessor.kt
new file mode 100644
index 00000000..7f3a6a97
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DefaultFunctionProcessor.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.getDeclaredFunctions
+import com.google.devtools.ksp.isAbstract
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+
+class DefaultFunctionProcessor : AbstractTestProcessor() {
+
+ private val result = mutableListOf<String>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val ktInterface = resolver.getClassDeclarationByName(resolver.getKSNameFromString("KTInterface"))
+ as KSClassDeclaration
+ val javaInterface = resolver.getClassDeclarationByName(resolver.getKSNameFromString("C"))
+ as KSClassDeclaration
+ result.addAll(checkFunctions(ktInterface, listOf("funLiteral", "funWithBody", "emptyFun")))
+ result.addAll(checkFunctions(javaInterface, listOf("foo", "bar")))
+ val containsFun = ktInterface.getAllFunctions().single {
+ it.simpleName.asString() == "iterator"
+ }
+ result.add("${containsFun.simpleName.asString()}: ${containsFun.isAbstract}")
+ val equalsFun = ktInterface.getAllFunctions().single {
+ it.simpleName.asString() == "equals"
+ }
+ result.add("${equalsFun.simpleName.asString()}: ${equalsFun.isAbstract}")
+ val interfaceProperty = ktInterface.declarations.single {
+ it.simpleName.asString() == "interfaceProperty"
+ } as KSPropertyDeclaration
+ result.add(
+ "${interfaceProperty.simpleName.asString()}: isAbstract: ${interfaceProperty.isAbstract()}: " +
+ "isMutable: ${interfaceProperty.isMutable}"
+ )
+ val interfaceVar = ktInterface.declarations.single {
+ it.simpleName.asString() == "interfaceVar"
+ } as KSPropertyDeclaration
+ result.add(
+ "${interfaceVar.simpleName.asString()}: isAbstract: ${interfaceVar.isAbstract()}: " +
+ "isMutable: ${interfaceVar.isMutable}"
+ )
+ val nonAbstractInterfaceProp =
+ ktInterface.declarations.single { it.simpleName.asString() == "nonAbstractInterfaceProp" }
+ as KSPropertyDeclaration
+ result.add(
+ "${nonAbstractInterfaceProp.simpleName.asString()}: " +
+ "isAbstract: ${nonAbstractInterfaceProp.isAbstract()}: isMutable: ${nonAbstractInterfaceProp.isMutable}"
+ )
+ val abstractClass = resolver.getClassDeclarationByName(resolver.getKSNameFromString("B"))
+ as KSClassDeclaration
+ result.add("${abstractClass.simpleName.asString()}: ${abstractClass.isAbstract()}")
+ val parameterVal = abstractClass.declarations.single {
+ it.simpleName.asString() == "parameterVal"
+ } as KSPropertyDeclaration
+ result.add(
+ "${parameterVal.simpleName.asString()}: isAbstract: ${parameterVal.isAbstract()}: " +
+ "isMutable: ${parameterVal.isMutable}"
+ )
+ val parameterVar = abstractClass.declarations.single {
+ it.simpleName.asString() == "parameterVar"
+ } as KSPropertyDeclaration
+ result.add(
+ "${parameterVar.simpleName.asString()}: isAbstract: ${parameterVar.isAbstract()}: " +
+ "isMutable: ${parameterVar.isMutable}"
+ )
+ val abstractVar = abstractClass.declarations.single {
+ it.simpleName.asString() == "abstractVar"
+ } as KSPropertyDeclaration
+ result.add(
+ "${abstractVar.simpleName.asString()}: isAbstract: ${abstractVar.isAbstract()}: " +
+ "isMutable: ${abstractVar.isMutable}"
+ )
+ val abstractProperty = abstractClass.declarations.single {
+ it.simpleName.asString() == "abstractProperty"
+ } as KSPropertyDeclaration
+ result.add(
+ "${abstractProperty.simpleName.asString()}: isAbstract: ${abstractProperty.isAbstract()}: " +
+ "isMutable: ${abstractProperty.isMutable}"
+ )
+ val aProperty = abstractClass.declarations.single { it.simpleName.asString() == "a" } as KSPropertyDeclaration
+ result.add("${aProperty.simpleName.asString()}: ${aProperty.isAbstract()}")
+ val D = resolver.getClassDeclarationByName("D")!!
+ D.getAllProperties().forEach { result.add("${it.simpleName.asString()}: isMutable: ${it.isMutable}") }
+ return emptyList()
+ }
+
+ private fun checkFunctions(classDec: KSClassDeclaration, funList: List<String>): List<String> {
+ return classDec.getDeclaredFunctions()
+ .filter { funList.contains(it.simpleName.asString()) }
+ .map { "${it.simpleName.asString()}: ${it.isAbstract}" }
+ .toList()
+ }
+
+ override fun toResult(): List<String> {
+ return result
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DocStringProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DocStringProcessor.kt
new file mode 100644
index 00000000..e878a7ad
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/DocStringProcessor.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+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.KSNode
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class DocStringProcessor : AbstractTestProcessor() {
+ private val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ private class DeclarationCollector : KSTopDownVisitor<MutableCollection<String>, Unit>() {
+ override fun defaultHandler(node: KSNode, data: MutableCollection<String>) = Unit
+
+ override fun visitDeclaration(declaration: KSDeclaration, data: MutableCollection<String>) {
+ data.add("${declaration.simpleName.asString()}: ${declaration.docString?.lines()?.joinToString("\\n")}")
+ }
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val visitor = DeclarationCollector()
+ resolver.getNewFiles().forEach { it.accept(visitor, result) }
+ result.sort()
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/EquivalentJavaWildcardProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/EquivalentJavaWildcardProcessor.kt
new file mode 100644
index 00000000..21039a7e
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/EquivalentJavaWildcardProcessor.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+open class EquivalentJavaWildcardProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ @OptIn(KspExperimental::class)
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getNewFiles().forEach {
+ resolver.getNewFiles().forEach {
+ it.accept(RefVisitor(results, resolver), "")
+ }
+ }
+
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ private class RefVisitor(
+ val results: MutableList<String>,
+ val resolver: Resolver
+ ) : KSTopDownVisitor<String, Unit>() {
+ override fun defaultHandler(node: KSNode, data: String) = Unit
+
+ private fun KSTypeReference.pretty(): String {
+ return resolve().toString()
+ }
+
+ @OptIn(KspExperimental::class)
+ override fun visitTypeReference(typeReference: KSTypeReference, data: String) {
+ val wildcard = resolver.getJavaWildcard(typeReference)
+ results.add(
+ data + typeReference.parent.toString() +
+ " : " + typeReference.pretty() +
+ " -> " + wildcard.pretty()
+ )
+ super.visitTypeReference(typeReference, data + "- ")
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ErrorTypeProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ErrorTypeProcessor.kt
new file mode 100644
index 00000000..956aa16d
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ErrorTypeProcessor.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.symbol.KSType
+
+class ErrorTypeProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val classC = resolver.getClassDeclarationByName(resolver.getKSNameFromString("C"))!!
+ val errorAtTop = classC.declarations.single { it.simpleName.asString() == "errorAtTop" }
+ as KSPropertyDeclaration
+ val errorInComponent = classC.declarations.single { it.simpleName.asString() == "errorInComponent" }
+ as KSPropertyDeclaration
+ result.add(errorAtTop.type.resolve().print() ?: "")
+ result.add(errorInComponent.type.resolve().print() ?: "")
+ errorInComponent.type.resolve().arguments.forEach { result.add(it.type!!.resolve().print()) }
+ result.add(
+ "errorInComponent is assignable from errorAtTop: ${
+ errorAtTop.type.resolve().isAssignableFrom(errorAtTop.type.resolve())
+ }"
+ )
+ result.add(
+ "errorInComponent is assignable from class C: ${
+ errorAtTop.type.resolve().isAssignableFrom(classC.asStarProjectedType())
+ }"
+ )
+ result.add(
+ "Any is assignable from errorInComponent: ${
+ resolver.builtIns.anyType.isAssignableFrom(errorAtTop.type.resolve())
+ }"
+ )
+ result.add(
+ "class C is assignable from errorInComponent: ${
+ classC.asStarProjectedType().isAssignableFrom(errorAtTop.type.resolve())
+ }"
+ )
+ result.add(
+ "Any is assignable from class C: ${
+ resolver.builtIns.anyType.isAssignableFrom(classC.asStarProjectedType())
+ }"
+ )
+ val Cls = resolver.getClassDeclarationByName("Cls")!!
+ val type = Cls.superTypes.toList()[0].resolve()
+ result.add("Cls's super type is Error type: ${type.isError}")
+ Cls.annotations.forEach {
+ val annotation = it.annotationType.resolve()
+ result.add("Cls's annotation is Error type: ${annotation.isError}")
+ }
+ return emptyList()
+ }
+
+ private fun KSType.print(): String {
+ return if (this.isError) {
+ if (this.declaration.qualifiedName == null) "ERROR TYPE" else
+ throw IllegalStateException("Error type should resolve to KSErrorTypeClassDeclaration")
+ } else this.declaration.qualifiedName!!.asString()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeAliasProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeAliasProcessor.kt
new file mode 100644
index 00000000..69f70ab9
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeAliasProcessor.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+open class FunctionTypeAliasProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val typeRefCollector = RefCollector()
+ val refs = mutableSetOf<KSTypeReference>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+
+ files.forEach {
+ it.accept(typeRefCollector, refs)
+ }
+
+ val types = refs.mapNotNull { it.resolve() }.sortedBy { it.toString() }.distinctBy { it.toString() }
+
+ for (i in types) {
+ for (j in types) {
+ results.add("$i ?= $j : ${i.isAssignableFrom(j)} / ${i == j}")
+ }
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
+
+open class RefCollector : KSTopDownVisitor<MutableCollection<KSTypeReference>, Unit>() {
+ override fun defaultHandler(node: KSNode, data: MutableCollection<KSTypeReference>) = Unit
+
+ override fun visitTypeReference(typeReference: KSTypeReference, data: MutableCollection<KSTypeReference>) {
+ super.visitTypeReference(typeReference, data)
+ data.add(typeReference)
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeAnnotationProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeAnnotationProcessor.kt
new file mode 100644
index 00000000..c35d156e
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeAnnotationProcessor.kt
@@ -0,0 +1,36 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class FunctionTypeAnnotationProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+
+ files.forEach {
+ it.accept(
+ object : KSTopDownVisitor<Unit, Unit>() {
+ override fun defaultHandler(node: KSNode, data: Unit) = Unit
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ val type = property.type.resolve()
+ val propertyName = property.simpleName.asString()
+ val typeName = type.declaration.simpleName.asString()
+ results.add("$propertyName: $typeName ${type.annotations.joinToString { it.toString() }}")
+ }
+ },
+ Unit
+ )
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeProcessor.kt
new file mode 100644
index 00000000..f361599b
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/FunctionTypeProcessor.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+open class FunctionTypeProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val types = mutableSetOf<KSType>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+
+ files.forEach {
+ it.accept(
+ object : KSTopDownVisitor<Unit, Unit>() {
+ override fun defaultHandler(node: KSNode, data: Unit) = Unit
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ val type = property.type.resolve()
+ val propertyName = property.simpleName.asString()
+ val typeName = type.declaration.simpleName.asString()
+ results.add("$propertyName: $typeName : ${type.isFunctionType}, ${type.isSuspendFunctionType}")
+ }
+ },
+ Unit
+ )
+ }
+
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results.sorted()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetAnnotationByTypeProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetAnnotationByTypeProcessor.kt
new file mode 100644
index 00000000..8615cdb8
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetAnnotationByTypeProcessor.kt
@@ -0,0 +1,36 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.getAnnotationsByType
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+
+annotation class KotlinAnnotationWithInnerDefaults(
+ val innerAnnotationVal: InnerAnnotation = InnerAnnotation(innerAnnotationDefault = 7)
+) {
+ annotation class InnerAnnotation(
+ val innerAnnotationDefault: Int,
+ val moreInnerAnnotation: MoreInnerAnnotation = MoreInnerAnnotation("OK")
+ ) {
+ annotation class MoreInnerAnnotation(val moreInnerAnnotationDefault: String)
+ }
+}
+
+class GetAnnotationByTypeProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ private val annotationKClass = KotlinAnnotationWithInnerDefaults::class
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ @OptIn(KspExperimental::class)
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val decl = resolver.getAllFiles().single().declarations
+ .single { it.simpleName.asString() == "A" } as KSClassDeclaration
+ val anno = decl.getAnnotationsByType(annotationKClass).first()
+ results.add(anno.innerAnnotationVal.toString())
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetByNameProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetByNameProcessor.kt
new file mode 100644
index 00000000..c7e49eec
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetByNameProcessor.kt
@@ -0,0 +1,63 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.getFunctionDeclarationsByName
+import com.google.devtools.ksp.getPropertyDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+
+class GetByNameProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val classNames = listOf(
+ "lib1.Foo",
+ "lib1.Foo.FooNested",
+ "source.FooInSource",
+ "source.FooInSource.FooInSourceNested"
+ )
+ val funNames = listOf(
+ "lib1.Foo.lib1MemberFun",
+ "lib1.lib1TopFun",
+ "lib1.Bar.lib1JavaMemberFun",
+ "lib2.Foo.lib2MemberFun",
+ "source.FooInSource.sourceMemberFun"
+ )
+ val overloadFunctionNames = listOf("lib1.Foo.overload")
+ val propNames = listOf(
+ "lib1.Foo.lib1MemberProp",
+ "lib1.lib1TopProp",
+ "lib2.Foo.lib2MemberProp",
+ "source.FooInSource.sourceMemberProp",
+ "source.propInSource",
+ )
+ for (className in classNames) {
+ if (resolver.getClassDeclarationByName(className) == null) {
+ results.add("failed to get $className")
+ }
+ }
+ for (funName in funNames) {
+ if (resolver.getFunctionDeclarationsByName(funName, true).none()) {
+ results.add("failed to get $funName")
+ }
+ }
+ for (funName in overloadFunctionNames) {
+ if (resolver.getFunctionDeclarationsByName(funName, true).toList().size != 2) {
+ results.add("failed to get all $funName")
+ }
+ }
+ for (propName in propNames) {
+ if (resolver.getPropertyDeclarationByName(propName, true) == null) {
+ results.add("failed to get $propName")
+ }
+ }
+ if (results.isEmpty()) {
+ results.add("all success")
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetPackageProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetPackageProcessor.kt
new file mode 100644
index 00000000..5af50859
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetPackageProcessor.kt
@@ -0,0 +1,29 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+
+class GetPackageProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ @OptIn(KspExperimental::class)
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ addPackage("lib1", resolver)
+ addPackage("lib2", resolver)
+ addPackage("main.test", resolver)
+ return emptyList()
+ }
+
+ @KspExperimental
+ private fun addPackage(name: String, resolver: Resolver) {
+ results.add("symbols from package $name")
+ resolver.getDeclarationsFromPackage(name).forEach {
+ results.add("${it.qualifiedName?.asString() ?: "error"} ${it.origin}")
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetSymbolsFromAnnotationProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetSymbolsFromAnnotationProcessor.kt
new file mode 100644
index 00000000..97b44309
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/GetSymbolsFromAnnotationProcessor.kt
@@ -0,0 +1,35 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+
+class GetSymbolsFromAnnotationProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+ override fun toResult(): List<String> = result
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ result.add("==== Anno superficial====")
+ resolver.getSymbolsWithAnnotation("Anno").forEach { result.add(toString(it)) }
+ result.add("==== Anno in depth ====")
+ resolver.getSymbolsWithAnnotation("Anno", true).forEach { result.add(toString(it)) }
+ result.add("==== Bnno superficial====")
+ resolver.getSymbolsWithAnnotation("Bnno").forEach { result.add(toString(it)) }
+ result.add("==== Bnno in depth ====")
+ resolver.getSymbolsWithAnnotation("Bnno", true).forEach { result.add(toString(it)) }
+ result.add("==== A1 superficial====")
+ resolver.getSymbolsWithAnnotation("A1").forEach { result.add(toString(it)) }
+ result.add("==== A1 in depth ====")
+ resolver.getSymbolsWithAnnotation("A1", true).forEach { result.add(toString(it)) }
+ result.add("==== A2 superficial====")
+ resolver.getSymbolsWithAnnotation("A2").forEach { result.add(toString(it)) }
+ result.add("==== A2 in depth ====")
+ resolver.getSymbolsWithAnnotation("A2", true).forEach { result.add(toString(it)) }
+ result.add("==== Cnno in depth ====")
+ resolver.getSymbolsWithAnnotation("Cnno", true).forEach { result.add(toString(it)) }
+ return emptyList()
+ }
+
+ fun toString(annotated: KSAnnotated): String {
+ return "$annotated:${annotated::class.supertypes.first().classifier.toString().substringAfterLast('.')}"
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/HelloProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/HelloProcessor.kt
new file mode 100644
index 00000000..c8793d89
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/HelloProcessor.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+class HelloProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val visitor = HelloVisitor()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val symbols = resolver.getSymbolsWithAnnotation("test.Anno")
+ results.add(symbols.toList().size.toString())
+ symbols.forEach { it.accept(visitor, Unit) }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results.sorted()
+ }
+
+ inner class HelloVisitor : KSVisitorVoid() {
+ override fun visitClassDeclaration(type: KSClassDeclaration, data: Unit) {
+ results.add(type.qualifiedName?.asString() ?: "<error>")
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
+ results.add(function.qualifiedName?.asString() ?: "<error>")
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ results.add(property.qualifiedName?.asString() ?: "<error>")
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ImplicitElementProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ImplicitElementProcessor.kt
new file mode 100644
index 00000000..4273671c
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ImplicitElementProcessor.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.getConstructors
+import com.google.devtools.ksp.getDeclaredFunctions
+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.KSPropertyDeclaration
+
+class ImplicitElementProcessor : AbstractTestProcessor() {
+ val result: MutableList<String> = mutableListOf()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ private fun nameAndOrigin(declaration: KSDeclaration) =
+ "${declaration.simpleName.asString()}: ${declaration.origin}"
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val ClsClass = resolver.getClassDeclarationByName(resolver.getKSNameFromString("Cls"))!!
+ result.add(
+ "${
+ ClsClass.primaryConstructor?.simpleName?.asString() ?: "<null>"
+ }; origin: ${ClsClass.primaryConstructor?.origin}"
+ )
+ result.add(ClsClass.getConstructors().map { it.toString() }.joinToString(","))
+ val ITF = resolver.getClassDeclarationByName(resolver.getKSNameFromString("ITF"))!!
+ result.add(ITF.primaryConstructor?.simpleName?.asString() ?: "<null>")
+ val JavaClass = resolver.getClassDeclarationByName("JavaClass")!!
+ result.add(JavaClass.primaryConstructor?.simpleName?.asString() ?: "<null>")
+ result.add(JavaClass.getDeclaredFunctions().map { it.simpleName.asString() }.joinToString(","))
+ val readOnly = ClsClass.declarations.single { it.simpleName.asString() == "readOnly" } as KSPropertyDeclaration
+ readOnly.getter?.let {
+ result.add(
+ "readOnly.get(): ${it.origin} annotations from property: ${
+ it.annotations.map { it.shortName.asString() }.joinToString(",")
+ }"
+ )
+ }
+ readOnly.getter?.receiver?.let { result.add("readOnly.getter.owner: " + nameAndOrigin(it)) }
+ readOnly.setter?.let { result.add("readOnly.set(): ${it.origin}") }
+ readOnly.setter?.receiver?.let { result.add("readOnly.setter.owner: " + nameAndOrigin(it)) }
+ val readWrite =
+ ClsClass.declarations.single { it.simpleName.asString() == "readWrite" } as KSPropertyDeclaration
+ readWrite.getter?.let { result.add("readWrite.get(): ${it.origin}") }
+ readWrite.setter?.let {
+ result.add(
+ "readWrite.set(): ${it.origin} annotations from property: ${
+ it.annotations.map {
+ it.shortName.asString()
+ }.joinToString(",")
+ }"
+ )
+ }
+ val dataClass = resolver.getClassDeclarationByName(resolver.getKSNameFromString("Data"))!!
+ result.add(dataClass.getConstructors().map { it.toString() }.joinToString(","))
+ val comp1 = dataClass.declarations.single { it.simpleName.asString() == "comp1" } as KSPropertyDeclaration
+ comp1.getter?.let { result.add("comp1.get(): ${it.origin}") }
+ comp1.setter?.let { result.add("comp1.set(): ${it.origin}") }
+ val comp2 = dataClass.declarations.single { it.simpleName.asString() == "comp2" } as KSPropertyDeclaration
+ comp2.getter?.let { result.add("comp2.get(): ${it.origin}") }
+ comp2.setter?.let { result.add("comp2.set(): ${it.origin}") }
+ val annotationType = comp1.getter?.let {
+ result.add(it.annotations.first().annotationType.resolve().declaration.qualifiedName!!.asString())
+ }
+ val ClassWithoutImplicitPrimaryConstructor =
+ resolver.getClassDeclarationByName("ClassWithoutImplicitPrimaryConstructor")!!
+ result.add(
+ ClassWithoutImplicitPrimaryConstructor.getConstructors().map { it.toString() }.joinToString(",")
+ )
+ val ImplictConstructorJava = resolver.getClassDeclarationByName("ImplictConstructorJava")!!
+ result.add(ImplictConstructorJava.getConstructors().map { it.toString() }.joinToString(","))
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ImplicitPropertyAccessorProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ImplicitPropertyAccessorProcessor.kt
new file mode 100644
index 00000000..cef47f3c
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ImplicitPropertyAccessorProcessor.kt
@@ -0,0 +1,26 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+
+class ImplicitPropertyAccessorProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val foo = resolver.getClassDeclarationByName("Foo")!!
+ foo.declarations.filterIsInstance<KSPropertyDeclaration>().forEach { prop ->
+ result.add(prop.getter?.returnType.toString())
+ prop.setter?.parameter?.let {
+ result.add(it.toString())
+ result.add(it.type.toString())
+ }
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/InheritedTypeAliasProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/InheritedTypeAliasProcessor.kt
new file mode 100644
index 00000000..9b1704bf
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/InheritedTypeAliasProcessor.kt
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+
+class InheritedTypeAliasProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val sub = resolver.getClassDeclarationByName("Sub")!!
+ val sup = resolver.getClassDeclarationByName("Super")!!
+ sub.getAllFunctions().single { it.simpleName.asString() == "foo" }.let { func ->
+ func.parameters.forEach {
+ it.type.element?.typeArguments?.joinToString(prefix = "sub: ${it.name?.asString()} :") {
+ it.toString()
+ }?.let { results.add(it) }
+ }
+ }
+ sub.getAllProperties().forEach { prop ->
+ prop.type.element?.typeArguments?.joinToString(prefix = "sub: ${prop.simpleName.asString()} :") {
+ it.toString()
+ }?.let { results.add(it) }
+ }
+ sup.getAllFunctions().single { it.simpleName.asString() == "foo" }.let { func ->
+ func.parameters.forEach {
+ it.type.element?.typeArguments?.joinToString(prefix = "super: ${it.name?.asString()} :") {
+ it.toString()
+ }?.let { results.add(it) }
+ }
+ }
+ sup.getAllProperties().forEach { prop ->
+ prop.type.element?.typeArguments?.joinToString(prefix = "super: ${prop.simpleName.asString()} :") {
+ it.toString()
+ }?.let { results.add(it) }
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/InnerTypeProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/InnerTypeProcessor.kt
new file mode 100644
index 00000000..7e1556e7
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/InnerTypeProcessor.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.innerArguments
+import com.google.devtools.ksp.outerType
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+open class InnerTypeProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val typeCollector = TypeCollector()
+ val types = mutableSetOf<KSType>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+ val ignoredNames = mutableSetOf<String>()
+
+ files.forEach {
+ it.accept(typeCollector, types)
+ it.annotations.forEach {
+ if (it.shortName.asString() == "Suppress") {
+ it.arguments.forEach {
+ (it.value as List<String>).forEach {
+ ignoredNames.add(it)
+ }
+ }
+ }
+ }
+ }
+
+ val sortedTypes = types.filterNot { it.declaration.simpleName.asString() in ignoredNames }.sortedBy {
+ it.toString()
+ }
+
+ fun KSType.breakDown(): List<String> {
+ var current: KSType? = this
+ val brokenDown = mutableListOf<String>()
+ do {
+ val innerArgs = current!!.innerArguments.joinToString(", ")
+ brokenDown.add("${current.declaration.qualifiedName!!.asString()}<$innerArgs>")
+ current = current.outerType
+ } while (current != null)
+ return brokenDown
+ }
+
+ for (i in sortedTypes) {
+ results.add("$i: ${i.breakDown()}")
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaModifierProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaModifierProcessor.kt
new file mode 100644
index 00000000..9a6cbf65
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaModifierProcessor.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class JavaModifierProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getSymbolsWithAnnotation("Test")
+ .map {
+ it as KSClassDeclaration
+ }
+ .forEach {
+ it.superTypes.single().resolve().declaration.accept(ModifierVisitor(resolver), Unit)
+ }
+ return emptyList()
+ }
+
+ inner class ModifierVisitor(val resolver: Resolver) : KSTopDownVisitor<Unit, Unit>() {
+ override fun defaultHandler(node: KSNode, data: Unit) {
+ }
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
+ results.add(classDeclaration.toSignature())
+ classDeclaration.declarations.forEach { it.accept(this, data) }
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ results.add(property.toSignature())
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
+ results.add(function.toSignature())
+ }
+
+ @OptIn(KspExperimental::class)
+ private fun KSDeclaration.toSignature(): String {
+ val parent = parentDeclaration
+ val id = if (parent == null) {
+ ""
+ } else {
+ "${parent.simpleName.asString()}."
+ } + simpleName.asString()
+ val modifiersSignature = modifiers.map { it.toString() }.sorted().joinToString(" ")
+ val extras = resolver.effectiveJavaModifiers(this).map { it.toString() }.sorted().joinToString(" ").trim()
+ return "$id: $modifiersSignature".trim() + " : " + extras
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaNonNullProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaNonNullProcessor.kt
new file mode 100644
index 00000000..35462894
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaNonNullProcessor.kt
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+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.KSFunctionDeclaration
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.symbol.KSValueParameter
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class JavaNonNullProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getNewFiles().forEach {
+ it.accept(
+ object : KSTopDownVisitor<Unit, Unit>() {
+ override fun defaultHandler(node: KSNode, data: Unit) {
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
+ if (function.isConstructor()) {
+ return
+ }
+ results.add("${function.simpleName.asString()}: ${function.returnType?.resolve()?.nullability}")
+ super.visitFunctionDeclaration(function, data)
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ results.add("${property.simpleName.asString()}: ${property.type.resolve().nullability}")
+ }
+
+ override fun visitValueParameter(valueParameter: KSValueParameter, data: Unit) {
+ results.add("${valueParameter.name?.asString()}: ${valueParameter.type.resolve().nullability}")
+ }
+ },
+ Unit
+ )
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaSubtypeProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaSubtypeProcessor.kt
new file mode 100644
index 00000000..f04b2b5e
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaSubtypeProcessor.kt
@@ -0,0 +1,78 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.getJavaClassByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.symbol.Variance
+
+class JavaSubtypeProcessor : AbstractTestProcessor() {
+ var isOk = true
+ override fun toResult(): List<String> {
+ return listOf(isOk.toString())
+ }
+
+ @OptIn(KspExperimental::class)
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val javaCollection = resolver.getJavaClassByName("kotlin.collections.Collection")!!.asStarProjectedType()
+ val javaSet = resolver.getJavaClassByName("kotlin.collections.Set")!!.asStarProjectedType()
+ val ktFunctionJava = resolver.getJavaClassByName("kotlin.jvm.functions.Function0")!!.asStarProjectedType()
+ val ktCollection = resolver.getClassDeclarationByName("kotlin.collections.Collection")!!.asStarProjectedType()
+ val ktSet = resolver.getClassDeclarationByName("kotlin.collections.Set")!!.asStarProjectedType()
+ val ktFunction = resolver.getClassDeclarationByName("kotlin.jvm.functions.Function0")!!.asStarProjectedType()
+ val javaCollectionRef = resolver.createKSTypeReferenceFromKSType(javaCollection)
+ val ktCollectionRef = resolver.createKSTypeReferenceFromKSType(ktCollection)
+ val javaSetRef = resolver.createKSTypeReferenceFromKSType(javaSet)
+ val ktSetRef = resolver.createKSTypeReferenceFromKSType(ktSet)
+ val javaSetOfJavaSet = javaSet.replace(listOf(resolver.getTypeArgument(javaSetRef, Variance.INVARIANT)))
+ val javaSetOfKtSet = javaSet.replace(listOf(resolver.getTypeArgument(ktSetRef, Variance.INVARIANT)))
+ val ktSetOfJavaSet = ktSet.replace(listOf(resolver.getTypeArgument(javaSetRef, Variance.INVARIANT)))
+ val ktSetOfKtSet = ktSet.replace(listOf(resolver.getTypeArgument(ktSetRef, Variance.INVARIANT)))
+ val javaCollectionOfJavaSet = javaCollection
+ .replace(listOf(resolver.getTypeArgument(javaSetRef, Variance.INVARIANT)))
+ val javaCollectionOfKtSet = javaCollection
+ .replace(listOf(resolver.getTypeArgument(ktSetRef, Variance.INVARIANT)))
+ val ktCollectionOfJavaSet = ktCollection
+ .replace(listOf(resolver.getTypeArgument(javaSetRef, Variance.INVARIANT)))
+ val ktCollectionOfKtSet = ktCollection
+ .replace(listOf(resolver.getTypeArgument(ktSetRef, Variance.INVARIANT)))
+ val ktCollectionOfJavaCollection = ktCollection
+ .replace(listOf(resolver.getTypeArgument(javaCollectionRef, Variance.INVARIANT)))
+ val javaSetOfKtCollection = javaSet
+ .replace(listOf(resolver.getTypeArgument(ktCollectionRef, Variance.INVARIANT)))
+ val container = resolver.getClassDeclarationByName("Container")!!
+ val strRef = resolver.getTypeArgument(
+ (container.declarations.single { it.simpleName.asString() == "str" } as KSPropertyDeclaration).type,
+ Variance.INVARIANT
+ )
+ val javaStrCollection = javaCollection.replace(listOf(strRef))
+ val javaStrSet = javaSet.replace(listOf(strRef))
+ val kotlinFunctionImplementorJava = resolver.getClassDeclarationByName("IntSupplier")!!.asStarProjectedType()
+ isOk = isOk && javaCollection.isAssignableFrom(javaSet)
+ isOk = isOk && javaCollection.isAssignableFrom(javaStrCollection)
+ isOk = isOk && !javaStrCollection.isAssignableFrom(javaCollection)
+ isOk = isOk && !javaStrSet.isAssignableFrom(javaStrCollection)
+ isOk = isOk && javaStrCollection.isAssignableFrom(javaStrSet)
+ isOk = isOk && javaSet.isAssignableFrom(javaStrSet)
+ isOk = isOk && javaCollection.isAssignableFrom(ktCollection)
+ isOk = isOk && ktCollection.isAssignableFrom(javaCollection)
+ isOk = isOk && javaSetOfJavaSet.isAssignableFrom(ktSetOfJavaSet)
+ isOk = isOk && ktSetOfJavaSet.isAssignableFrom(javaSetOfJavaSet)
+ isOk = isOk && javaSetOfJavaSet.isAssignableFrom(javaSetOfKtSet)
+ isOk = isOk && javaSetOfKtSet.isAssignableFrom(javaSetOfJavaSet)
+ isOk = isOk && ktSetOfKtSet.isAssignableFrom(ktSetOfJavaSet)
+ isOk = isOk && ktSetOfJavaSet.isAssignableFrom(ktSetOfKtSet)
+ isOk = isOk && javaCollectionOfJavaSet.isAssignableFrom(ktCollectionOfJavaSet)
+ isOk = isOk && ktCollectionOfJavaSet.isAssignableFrom(javaCollectionOfJavaSet)
+ isOk = isOk && javaCollectionOfKtSet.isAssignableFrom(ktCollectionOfKtSet)
+ isOk = isOk && javaCollectionOfKtSet.isAssignableFrom(ktCollectionOfJavaSet)
+ isOk = isOk && ktCollectionOfJavaCollection.isAssignableFrom(javaSetOfKtCollection)
+ isOk = isOk && !javaSetOfKtCollection.isAssignableFrom(ktCollectionOfJavaCollection)
+ isOk = isOk && ktFunction.isAssignableFrom(kotlinFunctionImplementorJava)
+ isOk = isOk && ktFunctionJava.isAssignableFrom(ktFunction) && ktFunction.isAssignableFrom(ktFunctionJava)
+ isOk = isOk && ktFunctionJava.isAssignableFrom(kotlinFunctionImplementorJava)
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaToKotlinMapProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaToKotlinMapProcessor.kt
new file mode 100644
index 00000000..37978d0b
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaToKotlinMapProcessor.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.getJavaClassByName
+import com.google.devtools.ksp.getKotlinClassByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+@KspExperimental
+open class JavaToKotlinMapProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val typeCollector = TypeCollectorNoAccessor()
+ val types = mutableSetOf<KSType>()
+
+ val javaClasses = listOf(
+ "java.lang.String",
+ "java.lang.Integer",
+ "java.util.List",
+ "java.util.Map.Entry",
+ "java.lang.Void",
+ )
+
+ val kotlinClasses = listOf(
+ "kotlin.Throwable",
+ "kotlin.Int",
+ "kotlin.Nothing",
+ "kotlin.IntArray",
+ )
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ javaClasses.forEach {
+ val k = resolver.mapJavaNameToKotlin(
+ resolver.getKSNameFromString(it)
+ )?.asString()
+ results.add("$it -> $k")
+ }
+
+ kotlinClasses.forEach {
+ val j = resolver.mapKotlinNameToJava(
+ resolver.getKSNameFromString(it)
+ )?.asString()
+ results.add("$it -> $j")
+ }
+
+ if (resolver.getClassDeclarationByName("java.lang.String") != resolver.getJavaClassByName("kotlin.String"))
+ results.add("Error: getJavaClassByName")
+
+ if (resolver.getClassDeclarationByName("kotlin.String") != resolver.getKotlinClassByName("java.lang.String"))
+ results.add("Error: getKotlinClassByName")
+
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaWildcard2Processor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaWildcard2Processor.kt
new file mode 100644
index 00000000..a72cc00c
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/JavaWildcard2Processor.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+open class JavaWildcard2Processor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ @OptIn(KspExperimental::class)
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getNewFiles().forEach {
+ resolver.getNewFiles().forEach {
+ it.accept(RefVisitor(results, resolver), "")
+ }
+ }
+
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ private class RefVisitor(
+ val results: MutableList<String>,
+ val resolver: Resolver
+ ) : KSTopDownVisitor<String, Unit>() {
+ override fun defaultHandler(node: KSNode, data: String) = Unit
+
+ private fun KSTypeReference.pretty(): String {
+ return resolve().toString()
+ }
+
+ override fun visitTypeArgument(typeArgument: KSTypeArgument, data: String) = Unit
+
+ override fun visitAnnotation(annotation: KSAnnotation, data: String) = Unit
+
+ @OptIn(KspExperimental::class)
+ override fun visitTypeReference(typeReference: KSTypeReference, data: String) {
+ val wildcard = resolver.getJavaWildcard(typeReference)
+ results.add(
+ data + typeReference.parent.toString() + " : " + wildcard.pretty()
+ )
+ super.visitTypeReference(typeReference, data + "- ")
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/LateinitPropertiesProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/LateinitPropertiesProcessor.kt
new file mode 100644
index 00000000..25c2546c
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/LateinitPropertiesProcessor.kt
@@ -0,0 +1,39 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.symbol.Modifier
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class LateinitPropertiesProcessor : AbstractTestProcessor() {
+ private val visitor = Visitor()
+
+ override fun toResult(): List<String> {
+ return visitor.lateinitPropertiesNames.sorted()
+ }
+
+ @OptIn(KspExperimental::class)
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getDeclarationsFromPackage("test.compiled").forEach {
+ it.accept(visitor, Unit)
+ }
+ resolver.getNewFiles().forEach { it.accept(visitor, Unit) }
+ return emptyList()
+ }
+
+ private class Visitor : KSTopDownVisitor<Unit, Unit>() {
+ val lateinitPropertiesNames = arrayListOf<String>()
+
+ override fun defaultHandler(node: KSNode, data: Unit) {
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ if (Modifier.LATEINIT in property.modifiers) {
+ lateinitPropertiesNames += property.simpleName.asString()
+ }
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/LibOriginsProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/LibOriginsProcessor.kt
new file mode 100644
index 00000000..e0a8db99
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/LibOriginsProcessor.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.containingFile
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class LibOriginsProcessor : AbstractTestProcessor() {
+ private val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ inner class MyCollector : KSTopDownVisitor<Unit, Unit>() {
+ override fun defaultHandler(node: KSNode, data: Unit) = Unit
+
+ override fun visitDeclaration(declaration: KSDeclaration, data: Unit) {
+ result.add(
+ "declaration: ${
+ declaration.qualifiedName?.asString() ?: declaration.simpleName.asString()
+ }: ${declaration.origin.name}"
+ )
+ super.visitDeclaration(declaration, data)
+ }
+
+ override fun visitAnnotation(annotation: KSAnnotation, data: Unit) {
+ result.add("annotation: ${annotation.shortName.asString()}: ${annotation.origin.name}")
+ super.visitAnnotation(annotation, data)
+ }
+
+ override fun visitTypeReference(typeReference: KSTypeReference, data: Unit) {
+ result.add("reference: $typeReference: ${typeReference.origin.name}")
+ super.visitTypeReference(typeReference, data)
+ }
+
+ override fun visitClassifierReference(reference: KSClassifierReference, data: Unit) {
+ result.add("classifier ref: $reference: ${reference.origin.name}")
+ super.visitClassifierReference(reference, data)
+ }
+
+ override fun visitValueParameter(valueParameter: KSValueParameter, data: Unit) {
+ result.add("value param: $valueParameter: ${valueParameter.origin.name}")
+ super.visitValueParameter(valueParameter, data)
+ }
+
+ override fun visitTypeArgument(typeArgument: KSTypeArgument, data: Unit) {
+ result.add("type arg: $typeArgument: ${typeArgument.origin.name}")
+ super.visitTypeArgument(typeArgument, data)
+ }
+
+ override fun visitPropertyAccessor(accessor: KSPropertyAccessor, data: Unit) {
+ result.add("property accessor: $accessor: ${accessor.origin.name}")
+ super.visitPropertyAccessor(accessor, data)
+ }
+ }
+
+ @OptIn(KspExperimental::class)
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val visitor = MyCollector()
+
+ // FIXME: workaround for https://github.com/google/ksp/issues/418
+ resolver.getDeclarationsFromPackage("foo.bar").forEach {
+ if (it.containingFile == null) {
+ it.accept(visitor, Unit)
+ }
+ }
+
+ resolver.getNewFiles().forEach {
+ it.accept(visitor, Unit)
+ }
+
+ result.sort()
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MakeNullableProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MakeNullableProcessor.kt
new file mode 100644
index 00000000..6d4484d8
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MakeNullableProcessor.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+open class MakeNullableProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val typeCollector = TypeCollector()
+ val types = mutableSetOf<KSType>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+ val ignoredNames = mutableSetOf<String>()
+
+ files.forEach {
+ it.accept(typeCollector, types)
+ }
+
+ val sortedTypes = types.flatMap { setOf(it, it.makeNullable(), it.makeNotNullable()) }.sortedBy {
+ it.toString()
+ }
+
+ for (i in sortedTypes) {
+ for (j in sortedTypes) {
+ results.add("$i ?= $j : ${i.isAssignableFrom(j)}")
+ }
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MangledNamesProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MangledNamesProcessor.kt
new file mode 100644
index 00000000..956c8ed2
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MangledNamesProcessor.kt
@@ -0,0 +1,81 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+@KspExperimental
+@Suppress("unused") // used by the test code
+class MangledNamesProcessor : AbstractTestProcessor() {
+ private val results = mutableListOf<String>()
+ override fun toResult() = results
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val mangleSourceNames = mutableMapOf<String, String?>()
+ resolver.getAllFiles().sortedBy { it.fileName }.forEach {
+ it.accept(MangledNamesVisitor(resolver), mangleSourceNames)
+ }
+ val mangledDependencyNames = LinkedHashMap<String, String?>()
+ // also collect results from library dependencies to ensure we resolve module name property
+ resolver.getClassDeclarationByName("libPackage.Foo")?.accept(
+ MangledNamesVisitor(resolver), mangledDependencyNames
+ )
+ resolver.getClassDeclarationByName("libPackage.AbstractKotlinClass")?.accept(
+ MangledNamesVisitor(resolver), mangledDependencyNames
+ )
+ resolver.getClassDeclarationByName("libPackage.MyInterface")?.accept(
+ MangledNamesVisitor(resolver), mangledDependencyNames
+ )
+ results.addAll(
+ mangleSourceNames.entries.map { (decl, name) ->
+ "$decl -> $name"
+ }
+ )
+ results.addAll(
+ mangledDependencyNames.entries.map { (decl, name) ->
+ "$decl -> $name"
+ }
+ )
+ return emptyList()
+ }
+
+ private class MangledNamesVisitor(
+ val resolver: Resolver
+ ) : KSTopDownVisitor<MutableMap<String, String?>, Unit>() {
+ override fun defaultHandler(node: KSNode, data: MutableMap<String, String?>) {
+ }
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: MutableMap<String, String?>) {
+ if (classDeclaration.modifiers.contains(Modifier.INLINE)) {
+ // do not visit inline classes
+ return
+ }
+ // put a header for readable output
+ data[classDeclaration.qualifiedName!!.asString()] = "declarations"
+ super.visitClassDeclaration(classDeclaration, data)
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: MutableMap<String, String?>) {
+ if (function.simpleName.asString() in IGNORED_FUNCTIONS) return
+ super.visitFunctionDeclaration(function, data)
+ data[function.simpleName.asString()] = resolver.getJvmName(function)
+ }
+
+ override fun visitPropertyGetter(getter: KSPropertyGetter, data: MutableMap<String, String?>) {
+ super.visitPropertyGetter(getter, data)
+ data["get-${getter.receiver.simpleName.asString()}"] = resolver.getJvmName(getter)
+ }
+
+ override fun visitPropertySetter(setter: KSPropertySetter, data: MutableMap<String, String?>) {
+ super.visitPropertySetter(setter, data)
+ data["set-${setter.receiver.simpleName.asString()}"] = resolver.getJvmName(setter)
+ }
+
+ companion object {
+ // do not report these functions as they are generated only in byte code and do not affect the test.
+ val IGNORED_FUNCTIONS = listOf("equals", "hashCode", "toString")
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MapSignatureProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MapSignatureProcessor.kt
new file mode 100644
index 00000000..1eb0cfc1
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MapSignatureProcessor.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+
+@KspExperimental
+class MapSignatureProcessor : AbstractTestProcessor() {
+ private val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ listOf("Cls", "JavaIntefaceWithVoid", "JavaClass", "JavaAnno")
+ .map { className ->
+ resolver.getClassDeclarationByName(className)!!
+ }.forEach { subject ->
+ result.add(resolver.mapToJvmSignature(subject)!!)
+ subject.declarations.forEach {
+ result.add(it.simpleName.asString() + ": " + resolver.mapToJvmSignature(it))
+ }
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MultiModuleTestProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MultiModuleTestProcessor.kt
new file mode 100644
index 00000000..cd5bfee0
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/MultiModuleTestProcessor.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+class MultiModuleTestProcessor : AbstractTestProcessor() {
+ private val results = mutableListOf<String>()
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val target = resolver.getClassDeclarationByName("TestTarget")
+ val classes = mutableSetOf<KSClassDeclaration>()
+ val classCollector = object : BaseVisitor() {
+ override fun visitClassDeclaration(type: KSClassDeclaration, data: Unit) {
+ if (classes.add(type)) {
+ super.visitClassDeclaration(type, data)
+ }
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ (property.type.resolve().declaration as? KSClassDeclaration)?.accept(this, Unit)
+ }
+ }
+ target?.accept(classCollector, Unit)
+ results.addAll(classes.map { it.toSignature() }.sorted())
+ return emptyList()
+ }
+
+ private fun KSClassDeclaration.toSignature(): String {
+ val id = qualifiedName?.asString() ?: "no-qual-name:($this)"
+ return "$id[${origin.name}]"
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/NestedClassTypeProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/NestedClassTypeProcessor.kt
new file mode 100644
index 00000000..7c5b982a
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/NestedClassTypeProcessor.kt
@@ -0,0 +1,31 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+
+class NestedClassTypeProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val c = resolver.getClassDeclarationByName("C")!!
+ c.declarations.filterIsInstance<KSPropertyDeclaration>()
+ .forEach {
+ result.add(it.simpleName.asString())
+ result.add(
+ it.type.resolve().arguments.map {
+ it.type?.annotations?.joinToString(separator = ",") {
+ it.toString()
+ }
+ }.joinToString()
+ )
+ result.add(it.type.resolve().arguments.joinToString(separator = ",") { it.toString() })
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/NullableTypeProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/NullableTypeProcessor.kt
new file mode 100644
index 00000000..8e986967
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/NullableTypeProcessor.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+open class NullableTypeProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val types = mutableSetOf<KSType>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+
+ files.forEach {
+ it.accept(
+ object : KSTopDownVisitor<Unit, Unit>() {
+ override fun defaultHandler(node: KSNode, data: Unit) = Unit
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ val modifiers = property.type.modifiers.map { it.toString() }.toList().sorted()
+ val annotations = property.type.annotations.map { it.toString() }.toList().sorted()
+ val propertyName = property.simpleName.asString()
+ results.add("$propertyName: $modifiers, $annotations")
+ }
+ },
+ Unit
+ )
+ }
+
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results.sorted()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/OverrideeProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/OverrideeProcessor.kt
new file mode 100644
index 00000000..9015f41b
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/OverrideeProcessor.kt
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.closestClassDeclaration
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+@Suppress("unused") // used by tests
+class OverrideeProcessor : AbstractTestProcessor() {
+ private val results = mutableListOf<String>()
+
+ override fun toResult() = results
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ logSubject(resolver, "NoOverride")
+ logSubject(resolver, "Subject")
+ logSubject(resolver, "JavaSubject.Subject")
+ logSubject(resolver, "lib.Subject")
+ logSubject(resolver, "ConflictingSubject1")
+ logSubject(resolver, "ConflictingSubject2")
+ logSubject(resolver, "ConflictingSubject3")
+ logSubject(resolver, "ConflictingSubject4")
+ logSubject(resolver, "OverrideOrder1")
+ logSubject(resolver, "OverrideOrder2")
+ logSubject(resolver, "JavaAccessorImpl")
+ logSubject(resolver, "JavaAnno")
+ logSubject(resolver, "JavaAnnos")
+ logSubject(resolver, "PrimaryConstructorOverride")
+ return emptyList()
+ }
+
+ private fun logSubject(resolver: Resolver, qName: String) {
+ results.add("$qName:")
+ val subject = resolver.getClassDeclarationByName(qName)!!
+ subject.declarations.filterIsInstance<KSClassDeclaration>().forEach {
+ logClass(it)
+ }
+ logClass(subject)
+ }
+
+ private fun logClass(subject: KSClassDeclaration) {
+ subject.declarations.filterIsInstance<KSPropertyDeclaration>()
+ .forEach {
+ checkOverridee(it)
+ }
+ subject.declarations.filterIsInstance<KSFunctionDeclaration>()
+ .filterNot { it.simpleName.asString() in IGNORED_METHOD_NAMES }
+ .forEach {
+ checkOverridee(it)
+ }
+ }
+
+ private fun checkOverridee(declaration: KSDeclaration) {
+ val signature = if (declaration is KSPropertyDeclaration) declaration.toSignature() else
+ (declaration as KSFunctionDeclaration).toSignature()
+ val overrideeSignature = if (declaration is KSPropertyDeclaration) declaration.findOverridee()?.toSignature()
+ else (declaration as KSFunctionDeclaration).findOverridee()?.toSignature()
+ results.add("$signature -> $overrideeSignature")
+ }
+
+ private fun KSDeclaration.toSignature(): String {
+ return when (this) {
+ is KSFunctionDeclaration -> this.toSignature()
+ is KSPropertyDeclaration -> this.toSignature()
+ else -> throw IllegalStateException()
+ }
+ }
+
+ private fun KSFunctionDeclaration.toSignature(): String {
+ val self = this
+ return buildString {
+ append(self.closestClassDeclaration()?.simpleName?.asString())
+ append(".")
+ append(self.simpleName.asString())
+ append(
+ self.parameters.joinToString(", ", prefix = "(", postfix = ")") {
+ "${it.name?.asString()}:${it.type.resolve().declaration.simpleName.asString()}"
+ }
+ )
+ }
+ }
+
+ private fun KSPropertyDeclaration.toSignature(): String {
+ val self = this
+ return buildString {
+ append(self.closestClassDeclaration()?.simpleName?.asString())
+ append(".")
+ append(self.simpleName.asString())
+ }
+ }
+
+ companion object {
+ // ignore these methods as we receive syntetics of it from compiled code
+ private val IGNORED_METHOD_NAMES = listOf("equals", "hashCode", "toString", "<init>")
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ParameterTypeProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ParameterTypeProcessor.kt
new file mode 100644
index 00000000..55e1eec7
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ParameterTypeProcessor.kt
@@ -0,0 +1,32 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSValueParameter
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class ParameterTypeProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result.sorted()
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getNewFiles().forEach {
+ it.accept(
+ object : KSTopDownVisitor<Unit, Unit>() {
+ override fun defaultHandler(node: KSNode, data: Unit) {
+ }
+
+ override fun visitValueParameter(valueParameter: KSValueParameter, data: Unit) {
+ result.add("${valueParameter.name?.asString()}: ${valueParameter.type.resolve()}")
+ }
+ },
+ Unit
+ )
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ParentProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ParentProcessor.kt
new file mode 100644
index 00000000..1b028fe8
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ParentProcessor.kt
@@ -0,0 +1,34 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class ParentProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val collector = AllSymbolProcessor()
+ val nodes = mutableSetOf<KSNode>()
+ resolver.getAllFiles().forEach { it.accept(collector, nodes) }
+ for (e in listOf("YUV", "HSV")) {
+ resolver.getClassDeclarationByName(e)!!.accept(collector, nodes)
+ }
+ nodes.forEach {
+ result.add("parent of $it: ${it.parent}")
+ }
+ return emptyList()
+ }
+
+ class AllSymbolProcessor : KSTopDownVisitor<MutableSet<KSNode>, Unit>() {
+ override fun defaultHandler(node: KSNode, data: MutableSet<KSNode>) {
+ data.add(node)
+ }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/PlatformDeclarationProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/PlatformDeclarationProcessor.kt
new file mode 100644
index 00000000..b8f65468
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/PlatformDeclarationProcessor.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.containingFile
+import com.google.devtools.ksp.isConstructor
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+open class PlatformDeclarationProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val collector = EverythingVisitor()
+ val declarations = mutableListOf<KSDeclaration>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+
+ files.forEach {
+ it.accept(collector, declarations)
+ }
+
+ declarations
+ .filterNot {
+ // TODO we should figure out how constructors work in expect-actual world
+ // expand this test to include constructors
+ it is KSFunctionDeclaration && it.isConstructor()
+ }
+ .sortedBy { "${it.containingFile?.fileName} : ${it.qualifiedName?.asString()}" }.forEach {
+ val r = mutableListOf<Any?>()
+ r.add(it.containingFile?.fileName)
+ r.add(it.qualifiedName?.asString())
+ r.add(it.isActual)
+ r.add(it.isExpect)
+ r.add(it.findActuals().joinToString(", ", "[", "]") { it.containingFile?.fileName.toString() })
+ r.add(it.findExpects().joinToString(", ", "[", "]") { it.containingFile?.fileName.toString() })
+ results.add(r.map { it.toString() }.joinToString(" : "))
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
+
+class EverythingVisitor : KSTopDownVisitor<MutableList<KSDeclaration>, Unit>() {
+ override fun defaultHandler(node: KSNode, data: MutableList<KSDeclaration>) = Unit
+
+ override fun visitDeclaration(declaration: KSDeclaration, data: MutableList<KSDeclaration>) {
+ super.visitDeclaration(declaration, data)
+ data.add(declaration)
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RawTypesProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RawTypesProcessor.kt
new file mode 100644
index 00000000..aa2af3f5
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RawTypesProcessor.kt
@@ -0,0 +1,48 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class RawTypesProcessor : AbstractTestProcessor() {
+ private val rawTypedEntityNames = arrayListOf<String>()
+
+ override fun toResult(): List<String> {
+ return rawTypedEntityNames.sorted()
+ }
+
+ @OptIn(KspExperimental::class)
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val visitor = object : KSTopDownVisitor<Unit, Unit>() {
+ private val KSType.isRawType
+ get() = resolver.isJavaRawType(this)
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
+ function.parameters.forEach { param ->
+ val type = param.type.resolve()
+ if (type.isRawType) {
+ rawTypedEntityNames += param.name?.asString() ?: "???"
+ }
+ }
+ val returnType = function.returnType?.resolve() ?: return
+ if (returnType.isRawType) {
+ rawTypedEntityNames += function.simpleName.asString()
+ }
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
+ val type = property.type.resolve()
+ if (type.isRawType) {
+ rawTypedEntityNames += property.simpleName.asString()
+ }
+ }
+
+ override fun defaultHandler(node: KSNode, data: Unit) = Unit
+ }
+
+ resolver.getDeclarationsFromPackage("").forEach { it.accept(visitor, Unit) }
+
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaAsMemberOfProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaAsMemberOfProcessor.kt
new file mode 100644
index 00000000..8da0f726
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaAsMemberOfProcessor.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+
+class RecordJavaAsMemberOfProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ val finalResult = mutableListOf(results[0])
+ finalResult.addAll(results.subList(1, results.size).sorted())
+ return finalResult
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ var function: KSFunctionDeclaration? = null
+ var type: KSType? = null
+ resolver.getAllFiles().forEach {
+ if (it.fileName == "C.kt") {
+ type = (
+ it.declarations.single {
+ it is KSPropertyDeclaration && it.simpleName.asString() == "a"
+ } as KSPropertyDeclaration
+ ).type.resolve()
+ } else if (it.fileName == "B.java") {
+ function = (
+ it.declarations.single {
+ it is KSClassDeclaration && it.simpleName.asString() == "B"
+ } as KSClassDeclaration
+ ).declarations.single {
+ it is KSFunctionDeclaration && it.simpleName.asString() == "f"
+ } as KSFunctionDeclaration
+ }
+ }
+
+ function!!.asMemberOf(type!!)
+
+ if (resolver is ResolverImpl) {
+ val m = resolver.incrementalContext.dumpLookupRecords()
+ m.toSortedMap().forEach { symbol, files ->
+ files.filter { it.endsWith(".java") }.sorted().forEach {
+ results.add("$symbol: $it")
+ }
+ }
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaGetAllMembersProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaGetAllMembersProcessor.kt
new file mode 100644
index 00000000..e172e0ee
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaGetAllMembersProcessor.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+
+class RecordJavaGetAllMembersProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ val finalResult = mutableListOf(results[0])
+ finalResult.addAll(results.subList(1, results.size).sorted())
+ return finalResult
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getAllFiles().forEach {
+ if (it.fileName == "A.kt") {
+ val c = it.declarations.single {
+ it is KSClassDeclaration && it.simpleName.asString() == "A"
+ } as KSClassDeclaration
+ c.getAllFunctions()
+ c.getAllProperties()
+ }
+ }
+
+ if (resolver is ResolverImpl) {
+ val m = resolver.incrementalContext.dumpLookupRecords().toSortedMap()
+ m.toSortedMap().forEach { symbol, files ->
+ files.filter { it.endsWith(".java") }.sorted().forEach {
+ results.add("$symbol: $it")
+ }
+ }
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaOverridesProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaOverridesProcessor.kt
new file mode 100644
index 00000000..a1872e85
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaOverridesProcessor.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+
+class RecordJavaOverridesProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ val finalResult = mutableListOf(results[0])
+ finalResult.addAll(results.subList(1, results.size).sorted())
+ return finalResult
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ var A_f1: KSFunctionDeclaration? = null
+ var A_f2: KSFunctionDeclaration? = null
+ var C_f1: KSFunctionDeclaration? = null
+ resolver.getAllFiles().forEach {
+ if (it.fileName == "A.java") {
+ val c = it.declarations.single {
+ it is KSClassDeclaration && it.simpleName.asString() == "A"
+ } as KSClassDeclaration
+ A_f1 = c.declarations.single {
+ it is KSFunctionDeclaration && it.simpleName.asString() == "f1"
+ } as KSFunctionDeclaration
+ A_f2 = c.declarations.single {
+ it is KSFunctionDeclaration && it.simpleName.asString() == "f2"
+ } as KSFunctionDeclaration
+ } else if (it.fileName == "C.java") {
+ val c = it.declarations.single {
+ it is KSClassDeclaration && it.simpleName.asString() == "C"
+ } as KSClassDeclaration
+ C_f1 = c.declarations.single {
+ it is KSFunctionDeclaration && it.simpleName.asString() == "f1"
+ } as KSFunctionDeclaration
+ }
+ }
+
+ resolver.overrides(A_f1!!, C_f1!!)
+ A_f2!!.findOverridee()
+
+ if (resolver is ResolverImpl) {
+ val m = resolver.incrementalContext.dumpLookupRecords().toSortedMap()
+ m.toSortedMap().forEach { symbol, files ->
+ files.filter { it.endsWith(".java") }.sorted().forEach {
+ results.add("$symbol: $it")
+ }
+ }
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaProcessor.kt
new file mode 100644
index 00000000..15f06bf2
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaProcessor.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.validate
+
+class RecordJavaProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ val finalResult = mutableListOf(results[0])
+ finalResult.addAll(results.subList(1, results.size).sorted())
+ return finalResult
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ resolver.getAllFiles().forEach {
+ it.declarations.forEach {
+ it.validate()
+ }
+ }
+ if (resolver is ResolverImpl) {
+ val m = resolver.incrementalContext.dumpLookupRecords().toSortedMap()
+ m.forEach { symbol, files ->
+ files.filter { it.endsWith(".java") }.sorted().forEach {
+ results.add("$symbol: $it")
+ }
+ }
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaSupertypesProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaSupertypesProcessor.kt
new file mode 100644
index 00000000..a3f5528d
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/RecordJavaSupertypesProcessor.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.processing.impl.ResolverImpl
+import com.google.devtools.ksp.symbol.*
+
+class RecordJavaSupertypesProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ val finalResult = mutableListOf(results[0])
+ finalResult.addAll(results.subList(1, results.size).sorted())
+ return finalResult
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val types = mutableSetOf<KSType>()
+ resolver.getAllFiles().forEach {
+ it.accept(TypeCollectorNoAccessor(), types)
+ }
+ types.forEach {
+ resolver.builtIns.anyType.isAssignableFrom(it)
+ }
+ if (resolver is ResolverImpl) {
+ val m = resolver.incrementalContext.dumpLookupRecords().toSortedMap()
+ m.forEach { symbol, files ->
+ files.filter { it.endsWith(".java") }.sorted().forEach {
+ results.add("$symbol: $it")
+ }
+ }
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ReferenceElementProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ReferenceElementProcessor.kt
new file mode 100644
index 00000000..c0843f36
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ReferenceElementProcessor.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getPropertyDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+open class ReferenceElementProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val collector = ReferenceCollector()
+ val references = mutableSetOf<KSTypeReference>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+
+ files.forEach {
+ it.accept(collector, references)
+ }
+
+ resolver.getPropertyDeclarationByName("z", true)!!.accept(collector, references)
+ resolver.getPropertyDeclarationByName("w", true)!!.accept(collector, references)
+
+ fun refName(it: KSTypeReference) = (it.element as KSClassifierReference).referencedName()
+
+ val sortedReferences =
+ references.filter { it.element is KSClassifierReference && it.origin == Origin.KOTLIN }.sortedBy(::refName)
+ for (i in sortedReferences)
+ results.add(
+ "KSClassifierReferenceImpl: Qualifier of ${i.element} is ${
+ (i.element as KSClassifierReference).qualifier
+ }"
+ )
+
+ // FIXME: References in getters and type arguments are not compared to equal.
+ val descriptorReferences =
+ references.filter { it.element is KSClassifierReference && it.origin == Origin.KOTLIN_LIB }
+ .distinctBy(::refName).sortedBy(::refName)
+ for (i in descriptorReferences) {
+ results.add(
+ "KSClassifierReferenceDescriptorImpl: Qualifier of ${i.element} is ${
+ (i.element as KSClassifierReference).qualifier
+ }"
+ )
+ }
+
+ val defNonNullReferences =
+ references.filter { it.element is KSDefNonNullReference && it.origin == Origin.KOTLIN }
+ .sortedBy { it.toString() }
+
+ defNonNullReferences.forEach {
+ results.add(
+ "KSDefNonNullReferenceImpl: Enclosed type of ${(it.element as KSDefNonNullReference).enclosedType}"
+ )
+ }
+
+ val javaReferences = references.filter { it.element is KSClassifierReference && it.origin == Origin.JAVA }
+ .sortedBy(::refName)
+ for (i in javaReferences) {
+ results.add(
+ "KSClassifierReferenceJavaImpl: Qualifier of ${i.element} is ${
+ (i.element as KSClassifierReference).qualifier}"
+ )
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
+
+class ReferenceCollector : KSTopDownVisitor<MutableSet<KSTypeReference>, Unit>() {
+ override fun defaultHandler(node: KSNode, data: MutableSet<KSTypeReference>) = Unit
+
+ override fun visitTypeReference(typeReference: KSTypeReference, data: MutableSet<KSTypeReference>) {
+ super.visitTypeReference(typeReference, data)
+ data.add(typeReference)
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ReplaceWithErrorTypeArgsProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ReplaceWithErrorTypeArgsProcessor.kt
new file mode 100644
index 00000000..f248b34a
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ReplaceWithErrorTypeArgsProcessor.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+open class ReplaceWithErrorTypeArgsProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val decls = listOf(
+ // Those have 2 type parameters
+ resolver.getClassDeclarationByName("KS")!!,
+ resolver.getClassDeclarationByName("KL")!!,
+ resolver.getClassDeclarationByName("JS")!!,
+ resolver.getClassDeclarationByName("JL")!!,
+ // Those have 0 or 1 parameters
+ resolver.getClassDeclarationByName("KS1")!!,
+ resolver.getClassDeclarationByName("KL1")!!,
+ resolver.getClassDeclarationByName("JS1")!!,
+ resolver.getClassDeclarationByName("JL1")!!,
+ resolver.getClassDeclarationByName("JSE")!!,
+ resolver.getClassDeclarationByName("JSE.E")!!,
+ resolver.getClassDeclarationByName("JLE")!!,
+ resolver.getClassDeclarationByName("JLE.E")!!,
+ resolver.getClassDeclarationByName("KSE")!!,
+ resolver.getClassDeclarationByName("KSE.E")!!,
+ resolver.getClassDeclarationByName("KLE")!!,
+ resolver.getClassDeclarationByName("KLE.E")!!,
+ )
+ val x = resolver.getPropertyDeclarationByName(resolver.getKSNameFromString("x"), true)!!
+ val xargs = x.type.element!!.typeArguments
+ val y = resolver.getPropertyDeclarationByName(resolver.getKSNameFromString("y"), true)!!
+ val yargs = y.type.element!!.typeArguments
+
+ for (decl in decls) {
+ val declName = decl.qualifiedName!!.asString()
+ results.add("$declName.star.replace($xargs): ${decl.asStarProjectedType().replace(xargs)}")
+ results.add("$declName.star.replace($yargs): ${decl.asStarProjectedType().replace(yargs)}")
+ results.add("$declName.asType($xargs): ${decl.asType(xargs)}")
+ results.add("$declName.asType($yargs): ${decl.asType(yargs)}")
+ results.add("$declName.asType(emptyList()): ${decl.asType(emptyList())}")
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ResolveJavaTypeProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ResolveJavaTypeProcessor.kt
new file mode 100644
index 00000000..b38a800c
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ResolveJavaTypeProcessor.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+import com.google.devtools.ksp.symbol.KSFunctionDeclaration
+import com.google.devtools.ksp.symbol.KSNode
+import com.google.devtools.ksp.symbol.KSTypeReference
+import com.google.devtools.ksp.symbol.Nullability
+import com.google.devtools.ksp.symbol.Origin
+import com.google.devtools.ksp.symbol.Variance
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+class ResolveJavaTypeProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val visitor = ResolveJavaTypeVisitor()
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val symbol = resolver.getClassDeclarationByName(resolver.getKSNameFromString("C"))
+ val symbolTypeParameter = resolver.getClassDeclarationByName(resolver.getKSNameFromString("Base"))
+ val another = resolver.getClassDeclarationByName(resolver.getKSNameFromString("Another"))
+ val javaEnum = resolver.getClassDeclarationByName(resolver.getKSNameFromString("JavaEnum"))
+ assert(symbol?.origin == Origin.JAVA)
+ symbol!!.accept(visitor, Unit)
+ symbolTypeParameter!!.accept(visitor, Unit)
+ another!!.accept(visitor, Unit)
+ javaEnum!!.accept(visitor, Unit)
+ return emptyList()
+ }
+
+ inner class ResolveJavaTypeVisitor : KSTopDownVisitor<Unit, Unit>() {
+ override fun defaultHandler(node: KSNode, data: Unit) {
+ }
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
+ classDeclaration.declarations.forEach { it.accept(this, Unit) }
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
+ function.parameters.forEach {
+ it.type.accept(this, Unit)
+ }
+ function.returnType?.accept(this, Unit)
+ }
+
+ override fun visitTypeReference(typeReference: KSTypeReference, data: Unit) {
+ if (typeReference.origin == Origin.JAVA) {
+ results.add(typeReference.render())
+ }
+ }
+ }
+
+ fun KSTypeReference.render(): String {
+ val sb = StringBuilder(this.resolve().declaration.qualifiedName?.asString() ?: "<ERROR>")
+ if (this.resolve().arguments.toList().isNotEmpty()) {
+ sb.append(
+ "<${this.resolve().arguments.map {
+ when (it.variance) {
+ Variance.STAR -> "*"
+ Variance.INVARIANT -> ""
+ Variance.CONTRAVARIANT -> "in "
+ Variance.COVARIANT -> "out "
+ } + it.type?.render()
+ }.joinToString(", ")}>"
+ )
+ }
+ if (this.resolve().nullability != Nullability.NOT_NULL) {
+ sb.append("?")
+ }
+ return sb.toString()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/SealedClassProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/SealedClassProcessor.kt
new file mode 100644
index 00000000..9cb6ea70
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/SealedClassProcessor.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+class SealedClassProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ result.add("from lib")
+ resolver.getClassDeclarationByName("lib.Expr")!!.let {
+ result.add(
+ it.getSealedSubclasses().map { sub ->
+ "${sub.simpleName.asString()}: ${sub.origin}"
+ }.toList().sorted().toString()
+ )
+ }
+
+ result.add("from source")
+ resolver.getNewFiles().forEach { f ->
+ f.declarations.forEach {
+ if (it is KSClassDeclaration) {
+ val subs = it.getSealedSubclasses().map { sub ->
+ "${sub.simpleName.asString()}: ${sub.origin}"
+ }.toList().sorted()
+ result.add("${it.simpleName.asString()} : $subs")
+ }
+ }
+ }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/SuperTypesProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/SuperTypesProcessor.kt
new file mode 100644
index 00000000..0752e34e
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/SuperTypesProcessor.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+open class SuperTypesProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ fun KSClassDeclaration.toResult(): String {
+ val supers = superTypes.map { it.resolve().declaration.qualifiedName!!.asString() }.joinToString(", ")
+ return "${qualifiedName!!.asString()}: $supers"
+ }
+
+ fun show(decl: String) = results.add(resolver.getClassDeclarationByName(decl)!!.toResult())
+
+ show("KotlinInterfaceInLib")
+ show("KotlinInterfaceInLibWithSuper")
+ show("AbstractKotlinClassInLib")
+ show("AbstractKotlinClassInLibWithSuperClass")
+ show("AbstractKotlinClassInLibWithSuperInterface")
+ show("KotlinClassInLib")
+ show("KotlinClassInLibWithSuperAbstract")
+ show("KotlinClassInLibWithSuperClass")
+ show("KotlinClassInLibWithSuperInterface")
+ show("JavaInterfaceInLib")
+ show("JavaInterfaceInLibWithSuper")
+ show("AbstractJavaClassInLib")
+ show("AbstractJavaClassInLibWithSuperInterface")
+ show("AbstractJavaClassInLibWithSuperClass")
+ show("JavaClassInLib")
+ show("JavaClassInLibWithSuperInterface")
+ show("JavaClassInLibWithSuperAbstract")
+ show("JavaClassInLibWithSuperClass")
+
+ show("KotlinInterfaceInSource")
+ show("KotlinInterfaceInSourceWithSuper")
+ show("AbstractKotlinClassInSource")
+ show("AbstractKotlinClassInSourceWithSuperClass")
+ show("AbstractKotlinClassInSourceWithSuperInterface")
+ show("KotlinClassInSource")
+ show("KotlinClassInSourceWithSuperAbstract")
+ show("KotlinClassInSourceWithSuperClass")
+ show("KotlinClassInSourceWithSuperInterface")
+ show("JavaInterfaceInSource")
+ show("JavaInterfaceInSourceWithSuper")
+ show("AbstractJavaClassInSource")
+ show("AbstractJavaClassInSourceWithSuperInterface")
+ show("AbstractJavaClassInSourceWithSuperClass")
+ show("JavaClassInSource")
+ show("JavaClassInSourceWithSuperInterface")
+ show("JavaClassInSourceWithSuperAbstract")
+ show("JavaClassInSourceWithSuperClass")
+
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ThrowListProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ThrowListProcessor.kt
new file mode 100644
index 00000000..8750151b
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ThrowListProcessor.kt
@@ -0,0 +1,71 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.getConstructors
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSFunctionDeclaration
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.symbol.KSType
+
+@KspExperimental
+class ThrowListProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return result
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val klass = resolver.getClassDeclarationByName("ThrowsKt")!!
+ val jlass = resolver.getClassDeclarationByName("ThrowsException")!!
+ result.add(
+ resolver.getJvmCheckedException(
+ klass.declarations.single {
+ it.simpleName.asString() == "throwsKT"
+ } as KSFunctionDeclaration
+ ).toResult()
+ )
+ result.add(
+ resolver.getJvmCheckedException(
+ (
+ jlass.declarations.single {
+ it.simpleName.asString() == "foo"
+ } as KSFunctionDeclaration
+ )
+ ).toResult()
+ )
+ val propertyA = klass.declarations.single { it.simpleName.asString() == "a" } as KSPropertyDeclaration
+ result.add(resolver.getJvmCheckedException(propertyA.getter!!).toResult())
+ result.add(resolver.getJvmCheckedException(propertyA.setter!!).toResult())
+ val jlib = resolver.getClassDeclarationByName("JavaLib")!!
+ val klib = resolver.getClassDeclarationByName("KtLib")!!
+ klib.declarations.filter { it.simpleName.asString() == "throwsLibKt" }.map {
+ resolver.getJvmCheckedException(it as KSFunctionDeclaration).toResult()
+ }.forEach { result.add(it) }
+ klib.declarations.filter { it.simpleName.asString() == "getterThrows" }.map {
+ resolver.getJvmCheckedException((it as KSPropertyDeclaration).getter!!).toResult()
+ }.forEach { result.add(it) }
+ klib.declarations.filter { it.simpleName.asString() == "setterThrows" }.map {
+ resolver.getJvmCheckedException((it as KSPropertyDeclaration).setter!!).toResult()
+ }.forEach { result.add(it) }
+ klib.declarations.filter { it.simpleName.asString() == "bothThrows" }.map {
+ resolver.getJvmCheckedException((it as KSPropertyDeclaration).getter!!).toResult()
+ }.forEach { result.add(it) }
+ klib.declarations.filter { it.simpleName.asString() == "bothThrows" }.map {
+ resolver.getJvmCheckedException((it as KSPropertyDeclaration).setter!!).toResult()
+ }.forEach { result.add(it) }
+ jlib.declarations.filter { it.simpleName.asString() == "foo" }.map {
+ resolver.getJvmCheckedException(it as KSFunctionDeclaration).toResult()
+ }.forEach { result.add(it) }
+ jlib.getConstructors().map {
+ resolver.getJvmCheckedException(it).toResult()
+ }.forEach { result.add(it) }
+ return emptyList()
+ }
+
+ private fun Sequence<KSType>.toResult() = this.joinToString(separator = ",") {
+ it.declaration.qualifiedName!!.asString()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TopLevelMemberProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TopLevelMemberProcessor.kt
new file mode 100644
index 00000000..05cc4d02
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TopLevelMemberProcessor.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.KspExperimental
+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.KSNode
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+@OptIn(KspExperimental::class)
+open class TopLevelMemberProcessor : AbstractTestProcessor() {
+ lateinit var results: List<String>
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ results = listOf("lib", "main").flatMap { pkg ->
+ resolver.getDeclarationsFromPackage(pkg)
+ .flatMap { declaration ->
+ val declarations = mutableListOf<KSDeclaration>()
+ declaration.accept(AllMembersVisitor(), declarations)
+ declarations
+ }.map {
+ "$pkg : ${it.simpleName.asString()} -> ${resolver.getSyntheticJvmClass(it)}"
+ }.sorted()
+ }
+ return emptyList()
+ }
+
+ private fun Resolver.getSyntheticJvmClass(
+ declaration: KSDeclaration
+ ) = when (declaration) {
+ is KSPropertyDeclaration -> this.getOwnerJvmClassName(declaration)
+ is KSFunctionDeclaration -> this.getOwnerJvmClassName(declaration)
+ else -> error("unexpected declaration $declaration")
+ }
+
+ private class AllMembersVisitor : KSTopDownVisitor<MutableList<KSDeclaration>, Unit>() {
+ override fun defaultHandler(node: KSNode, data: MutableList<KSDeclaration>) {
+ }
+
+ override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: MutableList<KSDeclaration>) {
+ data.add(property)
+ super.visitPropertyDeclaration(property, data)
+ }
+
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: MutableList<KSDeclaration>) {
+ data.add(function)
+ super.visitFunctionDeclaration(function, data)
+ }
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeAliasComparisonProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeAliasComparisonProcessor.kt
new file mode 100644
index 00000000..ac952ce9
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeAliasComparisonProcessor.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+open class TypeAliasComparisonProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val typeRefCollector = TypeRefCollector()
+ val refs = mutableSetOf<KSTypeReference>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+
+ files.forEach {
+ it.accept(typeRefCollector, refs)
+ }
+
+ fun KSType.aliases(): List<KSType> =
+ listOf(this) + ((this.declaration as? KSTypeAlias)?.type?.resolve()?.aliases() ?: emptyList())
+
+ val interesting = setOf("Anno", "Bnno")
+ val iRefs = refs.filterNot {
+ it.origin != Origin.KOTLIN || it.annotations.all { it.shortName.asString() !in interesting }
+ }
+ val types = iRefs.map { it.resolve()!! }.flatMap { it.aliases() }
+
+ for (i in types) {
+ for (j in types) {
+ results.add("$i = $j : ${i.isAssignableFrom(j)}")
+ }
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results.sorted()
+ }
+}
+
+open class TypeRefCollector : KSTopDownVisitor<MutableCollection<KSTypeReference>, Unit>() {
+ override fun defaultHandler(node: KSNode, data: MutableCollection<KSTypeReference>) = Unit
+
+ override fun visitTypeReference(typeReference: KSTypeReference, data: MutableCollection<KSTypeReference>) {
+ super.visitTypeReference(typeReference, data)
+ data.add(typeReference)
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeAliasProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeAliasProcessor.kt
new file mode 100644
index 00000000..40581584
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeAliasProcessor.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+open class TypeAliasProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val types = mutableListOf<KSType>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val byFinalSignature = mutableMapOf<String, MutableList<KSType>>()
+ resolver.getNewFiles().flatMap { file ->
+ file.declarations.filterIsInstance<KSPropertyDeclaration>().map { prop ->
+ buildString {
+ append(prop.simpleName.asString())
+ append(" : ")
+ val propType = prop.type.resolve()
+ val signatures = propType.typeAliasSignatures()
+ append(signatures.joinToString(" = "))
+ byFinalSignature.getOrPut(signatures.last()) {
+ mutableListOf()
+ }.add(propType)
+ }
+ }
+ }.forEach(results::add)
+ byFinalSignature.forEach { (signature, sameTypeAliases) ->
+ // exclude List<T> case from the test because they lose a type argument when resolving aliases, so they
+ // are not the same anymore as we traverse the declarations.
+ if (signature != "List<T>") {
+ for (i in sameTypeAliases) {
+ for (j in sameTypeAliases) {
+ assert(i == j) {
+ "$i and $j both map to $signature, equals should return true"
+ }
+ }
+ }
+ assert(sameTypeAliases.map { it.hashCode() }.distinct().size == 1) {
+ "different hashcodes for members of $signature"
+ }
+ }
+ }
+ return emptyList()
+ }
+
+ private fun KSType.typeAliasSignatures(): List<String> {
+ var self: KSType? = this
+ return buildList {
+ while (self != null) {
+ add(self!!.toSignature())
+ self = (self?.declaration as? KSTypeAlias)?.type?.resolve()
+ }
+ }
+ }
+
+ private fun KSType.toSignature(): String = buildString {
+ append(declaration.simpleName.asString())
+ if (arguments.isNotEmpty()) {
+ append("<")
+ arguments.map {
+ it.type?.resolve()?.toSignature() ?: "<error>"
+ }.forEach(this::append)
+ append(">")
+ }
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeComparisonProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeComparisonProcessor.kt
new file mode 100644
index 00000000..f5850b7b
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeComparisonProcessor.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+open class TypeComparisonProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val typeCollector = TypeCollector()
+ val types = mutableSetOf<KSType>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+ val ignoredNames = mutableSetOf<String>()
+
+ files.forEach {
+ it.accept(typeCollector, types)
+ it.annotations.forEach {
+ if (it.shortName.asString() == "Suppress") {
+ it.arguments.forEach {
+ (it.value as List<String>).forEach {
+ ignoredNames.add(it)
+ }
+ }
+ }
+ }
+ }
+
+ val sortedTypes = types.filterNot { it.declaration.simpleName.asString() in ignoredNames }.sortedBy {
+ it.toString()
+ }
+
+ for (i in sortedTypes) {
+ for (j in sortedTypes) {
+ results.add("$i ?= $j : ${i.isAssignableFrom(j)}")
+ }
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
+
+class TypeCollectorNoAccessor : TypeCollector() {
+ override fun visitPropertyGetter(getter: KSPropertyGetter, data: MutableCollection<KSType>) {
+ }
+
+ override fun visitPropertySetter(setter: KSPropertySetter, data: MutableCollection<KSType>) {
+ }
+}
+
+open class TypeCollector : KSTopDownVisitor<MutableCollection<KSType>, Unit>() {
+ override fun defaultHandler(node: KSNode, data: MutableCollection<KSType>) = Unit
+
+ override fun visitTypeReference(typeReference: KSTypeReference, data: MutableCollection<KSType>) {
+ super.visitTypeReference(typeReference, data)
+ typeReference.resolve().let { data.add(it) }
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeComposureProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeComposureProcessor.kt
new file mode 100644
index 00000000..78e2dc0e
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeComposureProcessor.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.visitor.KSTopDownVisitor
+
+open class TypeComposureProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+ val classes = mutableSetOf<KSClassDeclaration>()
+ val references = mutableSetOf<KSTypeReference>()
+
+ files.forEach {
+ it.accept(
+ object : KSTopDownVisitor<Unit, Unit>() {
+ override fun defaultHandler(node: KSNode, data: Unit) = Unit
+
+ override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
+ super.visitClassDeclaration(classDeclaration, Unit)
+ classes.add(classDeclaration)
+ }
+
+ override fun visitTypeReference(typeReference: KSTypeReference, data: Unit) {
+ super.visitTypeReference(typeReference, data)
+ references.add(typeReference)
+ }
+ },
+ Unit
+ )
+ }
+
+ val composed = mutableSetOf<KSType>()
+ val types = references.filter { it.resolve().arguments.toList().size == 1 }.map { it.resolve() }
+ // TODO: there is a mismatched behavior between 2 implementations, AA implementation has an upperbound of
+ // Any? for unbounded type parameter.
+ val refs0Arg = references.filter { it.resolve().arguments.toList().size == 0 && !it.resolve().isMarkedNullable }
+
+ for (c in classes) {
+ for (ref in refs0Arg) {
+ composed.add(c.asType(listOf(resolver.getTypeArgument(ref, Variance.INVARIANT))))
+ composed.add(c.asType(listOf(resolver.getTypeArgument(ref, Variance.COVARIANT))))
+ composed.add(c.asType(listOf(resolver.getTypeArgument(ref, Variance.CONTRAVARIANT))))
+ composed.add(c.asType(listOf(resolver.getTypeArgument(ref, Variance.STAR))))
+ }
+ }
+
+ for (t in types) {
+ for (ref in refs0Arg) {
+ composed.add(t.replace(listOf(resolver.getTypeArgument(ref, Variance.INVARIANT))))
+ composed.add(t.replace(listOf(resolver.getTypeArgument(ref, Variance.COVARIANT))))
+ composed.add(t.replace(listOf(resolver.getTypeArgument(ref, Variance.CONTRAVARIANT))))
+ composed.add(t.starProjection())
+ }
+ }
+
+ val sorted = composed.sortedBy { it.toString() }
+ for (i in sorted) {
+ for (j in sorted) {
+ results.add("$i ?= $j : ${i.isAssignableFrom(j)}")
+ }
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeParameterEqualsProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeParameterEqualsProcessor.kt
new file mode 100644
index 00000000..b7fa16cb
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeParameterEqualsProcessor.kt
@@ -0,0 +1,22 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.getDeclaredProperties
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+
+class TypeParameterEqualsProcessor : AbstractTestProcessor() {
+ val result = mutableListOf<Boolean>()
+
+ override fun toResult(): List<String> {
+ return result.map { it.toString() }
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val foo = resolver.getClassDeclarationByName("Foo")!!
+ val i = resolver.getClassDeclarationByName("I")!!
+ result.add(foo.typeParameters.first() == foo.getDeclaredProperties().first().type.resolve().declaration)
+ result.add(i.typeParameters[0] == i.typeParameters[1].bounds.single().resolve().declaration)
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeParameterReferenceProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeParameterReferenceProcessor.kt
new file mode 100644
index 00000000..58208d80
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/TypeParameterReferenceProcessor.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.getDeclaredFunctions
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.*
+
+open class TypeParameterReferenceProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+ val collector = ReferenceCollector()
+ val references = mutableSetOf<KSTypeReference>()
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val files = resolver.getNewFiles()
+
+ files.forEach {
+ it.accept(collector, references)
+ }
+
+ val sortedReferences = references.filter { it.element is KSClassifierReference && it.origin == Origin.KOTLIN }
+ .sortedBy { (it.element as KSClassifierReference).referencedName() }
+
+ for (i in sortedReferences) {
+ val r = i.resolve()
+ results.add("${r.declaration.qualifiedName?.asString()}: ${r.isMarkedNullable}")
+ }
+ val libFoo = resolver.getClassDeclarationByName("LibFoo")!!
+ libFoo.declarations.filterIsInstance<KSPropertyDeclaration>().forEach { results.add(it.type.toString()) }
+ val javaLib = resolver.getClassDeclarationByName("JavaLib")!!
+ javaLib.declarations.filterIsInstance<KSFunctionDeclaration>().forEach { results.add(it.returnType.toString()) }
+ val srj = resolver.getClassDeclarationByName("SelfReferencingJava")!!
+ srj.asStarProjectedType().declaration.typeParameters.single().bounds
+ .forEach { results.add(it.resolve().toString()) }
+ val boundedTypeParameter = resolver.getClassDeclarationByName("BoundedTypeParameter")!!
+ boundedTypeParameter.getDeclaredFunctions().filter { it.origin == Origin.JAVA }.forEach {
+ (it.returnType!!.resolve().declaration as KSTypeParameter).bounds.forEach {
+ results.add(it.resolve().toString())
+ }
+ }
+ return emptyList()
+ }
+
+ override fun toResult(): List<String> {
+ return results
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ValidateProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ValidateProcessor.kt
new file mode 100644
index 00000000..16afc8c2
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/ValidateProcessor.kt
@@ -0,0 +1,60 @@
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+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.KSNode
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.validate
+
+class ValidateProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ private fun validate(symbol: KSDeclaration, predicate: (KSNode?, KSNode) -> Boolean = { _, _ -> true }) {
+ if (symbol.validate(predicate)) {
+ results.add("${symbol.simpleName.asString()} valid")
+ } else {
+ results.add("${symbol.simpleName.asString()} invalid")
+ }
+ }
+
+ override fun toResult(): List<String> = results
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val ErrorInMember = resolver.getClassDeclarationByName("ErrorInMember")!!
+ val SkipErrorInMember = resolver.getClassDeclarationByName("SkipErrorInMember")!!
+ val GoodClass = resolver.getClassDeclarationByName("GoodClass")!!
+ val C = resolver.getClassDeclarationByName("C")!!
+ val BadJavaClass = resolver.getClassDeclarationByName("BadJavaClass")!!
+ val ErrorAnnotationType = resolver.getClassDeclarationByName("ErrorAnnotationType")!!
+ val ErrorInAnnotationArgumentSingleType =
+ resolver.getClassDeclarationByName("ErrorInAnnotationArgumentSingleType")!!
+ val ErrorInAnnotationArgumentMultipleTypes =
+ resolver.getClassDeclarationByName("ErrorInAnnotationArgumentMultipleTypes")!!
+ val ErrorInAnnotationArgumentComposed =
+ resolver.getClassDeclarationByName("ErrorInAnnotationArgumentComposed")!!
+ val ValidAnnotationArgumentType =
+ resolver.getClassDeclarationByName("ValidAnnotationArgumentType")!!
+ validate(ErrorInMember)
+ ErrorInMember.declarations.forEach { validate(it) }
+ validate(SkipErrorInMember) { node, _ ->
+ node !is KSPropertyDeclaration && node !is KSFunctionDeclaration
+ }
+ SkipErrorInMember.declarations.forEach {
+ validate(it) { node, _ ->
+ node !is KSPropertyDeclaration && node !is KSFunctionDeclaration
+ }
+ }
+ validate(GoodClass)
+ validate(C)
+ validate(BadJavaClass)
+ validate(ErrorAnnotationType)
+ validate(ErrorInAnnotationArgumentSingleType)
+ validate(ErrorInAnnotationArgumentMultipleTypes)
+ validate(ErrorInAnnotationArgumentComposed)
+ validate(ValidAnnotationArgumentType)
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/VisibilityProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/VisibilityProcessor.kt
new file mode 100644
index 00000000..4489f346
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/VisibilityProcessor.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2020 Google LLC
+ * Copyright 2010-2020 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.
+ */
+
+package com.google.devtools.ksp.processor
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.getVisibility
+import com.google.devtools.ksp.isVisibleFrom
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+import com.google.devtools.ksp.symbol.KSFunctionDeclaration
+import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+
+class VisibilityProcessor : AbstractTestProcessor() {
+ val results = mutableListOf<String>()
+
+ override fun toResult(): List<String> {
+ return results
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val symbolA = resolver.getSymbolsWithAnnotation("TestA").single() as KSClassDeclaration
+ val symbolB = resolver.getSymbolsWithAnnotation("TestB").single() as KSClassDeclaration
+ val symbolD = resolver.getSymbolsWithAnnotation("TestD").single() as KSClassDeclaration
+ val allFunctions = (symbolA.superTypes.single().resolve()!!.declaration as KSClassDeclaration)
+ .declarations.filterIsInstance<KSFunctionDeclaration>()
+ allFunctions.map {
+ "${it.simpleName.asString()}: ${it.getVisibility()},visible in A, B, D: " +
+ "${it.isVisibleFrom(symbolA)}, ${it.isVisibleFrom(symbolB)}, ${it.isVisibleFrom(symbolD)}"
+ }.forEach { results.add(it) }
+ val javaClass = resolver.getClassDeclarationByName("JavaClass")!!
+ val kotlinClass = resolver.getClassDeclarationByName("KotlinClass")!!
+ val kotlinSubClass = resolver.getClassDeclarationByName("KotlinSubClass")!!
+ val javaLibEnum = resolver.getClassDeclarationByName("LibEnumJava")!!
+ val kotlinLibEnum = resolver.getClassDeclarationByName("LibEnum")!!
+ val javaEnum = resolver.getClassDeclarationByName("Enum")!!
+ val kotlinEnum = resolver.getClassDeclarationByName("KtEnum")!!
+ val kotlinEnumWithVal = resolver.getClassDeclarationByName("KtEnumWithVal")!!
+ javaClass.declarations.filterIsInstance<KSPropertyDeclaration>().map {
+ "${it.simpleName.asString()}: ${it.getVisibility()},visible in A, B, D: " +
+ "${it.isVisibleFrom(symbolA)}, ${it.isVisibleFrom(symbolB)}, ${it.isVisibleFrom(symbolD)}"
+ }.forEach { results.add(it) }
+ kotlinClass.declarations.filterIsInstance<KSPropertyDeclaration>().map {
+ "${it.simpleName.asString()}: ${it.getVisibility()},visible in A, B, D: " +
+ "${it.isVisibleFrom(symbolA)}, ${it.isVisibleFrom(symbolB)}, ${it.isVisibleFrom(symbolD)}"
+ }.forEach { results.add(it) }
+ kotlinSubClass.declarations.filterIsInstance<KSPropertyDeclaration>().map {
+ "${it.simpleName.asString()}: ${it.getVisibility()},visible in A, B, D: " +
+ "${it.isVisibleFrom(symbolA)}, ${it.isVisibleFrom(symbolB)}, ${it.isVisibleFrom(symbolD)}"
+ }.forEach { results.add(it) }
+ javaLibEnum.declarations.filterIsInstance<KSFunctionDeclaration>().map {
+ "${javaLibEnum.simpleName.asString()}: ${it.simpleName.asString()}: ${it.getVisibility() }"
+ }.forEach { results.add(it) }
+ kotlinLibEnum.declarations.filterIsInstance<KSFunctionDeclaration>().map {
+ "${kotlinLibEnum.simpleName.asString()}: ${it.simpleName.asString()}: ${it.getVisibility() }"
+ }.forEach { results.add(it) }
+ javaEnum.declarations.filterIsInstance<KSFunctionDeclaration>().map {
+ "${javaEnum.simpleName.asString()}: ${it.simpleName.asString()}: ${it.getVisibility() }"
+ }.forEach { results.add(it) }
+ kotlinEnum.declarations.filterIsInstance<KSFunctionDeclaration>().map {
+ "${kotlinEnum.simpleName.asString()}: ${it.simpleName.asString()}: ${it.getVisibility() }"
+ }.forEach { results.add(it) }
+ kotlinEnumWithVal.declarations.filterIsInstance<KSFunctionDeclaration>().map {
+ "${kotlinEnumWithVal.simpleName.asString()}: ${it.simpleName.asString()}: ${it.getVisibility() }"
+ }.forEach { results.add(it) }
+ return emptyList()
+ }
+}
diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/testutils/AbstractKSPTest.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/testutils/AbstractKSPTest.kt
new file mode 100644
index 00000000..b2d89bfb
--- /dev/null
+++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/testutils/AbstractKSPTest.kt
@@ -0,0 +1,228 @@
+/*
+ * 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.
+ */
+
+package com.google.devtools.ksp.testutils
+
+import com.google.devtools.ksp.processor.AbstractTestProcessor
+import com.intellij.openapi.Disposable
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.Disposer
+import com.intellij.testFramework.TestDataFile
+import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
+import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
+import org.jetbrains.kotlin.cli.jvm.config.addJavaSourceRoot
+import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
+import org.jetbrains.kotlin.codegen.GenerationUtils
+import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
+import org.jetbrains.kotlin.psi.KtFile
+import org.jetbrains.kotlin.test.ExecutionListenerBasedDisposableProvider
+import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
+import org.jetbrains.kotlin.test.builders.testConfiguration
+import org.jetbrains.kotlin.test.compileJavaFiles
+import org.jetbrains.kotlin.test.directives.ConfigurationDirectives
+import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives
+import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives
+import org.jetbrains.kotlin.test.model.DependencyKind
+import org.jetbrains.kotlin.test.model.FrontendKind
+import org.jetbrains.kotlin.test.model.ResultingArtifact
+import org.jetbrains.kotlin.test.model.TestModule
+import org.jetbrains.kotlin.test.runners.AbstractKotlinCompilerTest
+import org.jetbrains.kotlin.test.services.*
+import org.jetbrains.kotlin.test.services.configuration.CommonEnvironmentConfigurator
+import org.jetbrains.kotlin.test.services.configuration.JvmEnvironmentConfigurator
+import org.jetbrains.kotlin.test.services.impl.TemporaryDirectoryManagerImpl
+import org.jetbrains.kotlin.test.util.KtTestUtil
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.Assertions
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.TestInfo
+import java.io.File
+
+abstract class DisposableTest {
+ private var _disposable: Disposable? = null
+ protected val disposable: Disposable get() = _disposable!!
+
+ @BeforeEach
+ private fun initDisposable(testInfo: TestInfo) {
+ _disposable = Disposer.newDisposable("disposable for ${testInfo.displayName}")
+ }
+
+ @AfterEach
+ private fun disposeDisposable() {
+ _disposable?.let { Disposer.dispose(it) }
+ _disposable = null
+ }
+}
+
+abstract class AbstractKSPTest(frontend: FrontendKind<*>) : DisposableTest() {
+ companion object {
+ val TEST_PROCESSOR = "// TEST PROCESSOR:"
+ val EXPECTED_RESULTS = "// EXPECTED:"
+ }
+
+ val kspTestRoot = KtTestUtil.tmpDir("test")
+ fun rootDirForModule(name: String) = File(kspTestRoot, name)
+ fun outDirForModule(name: String) = File(rootDirForModule(name), "out")
+ fun javaDirForModule(name: String) = File(rootDirForModule(name), "javaSrc")
+ val TestModule.testRoot: File
+ get() = rootDirForModule(name)
+ val TestModule.outDir: File
+ get() = outDirForModule(name)
+ val TestModule.javaDir: File
+ get() = javaDirForModule(name)
+
+ protected lateinit var testInfo: KotlinTestInfo
+ private set
+
+ @BeforeEach
+ fun initTestInfo(testInfo: TestInfo) {
+ this.testInfo = KotlinTestInfo(
+ className = testInfo.testClass.orElseGet(null)?.name ?: "_undefined_",
+ methodName = testInfo.testMethod.orElseGet(null)?.name ?: "_testUndefined_",
+ tags = testInfo.tags
+ )
+ }
+
+ open fun configureTest(builder: TestConfigurationBuilder) = Unit
+
+ abstract fun runTest(
+ testServices: TestServices,
+ mainModule: TestModule,
+ libModules: List<TestModule>,
+ testProcessor: AbstractTestProcessor,
+ ): List<String>
+
+ private val configure: TestConfigurationBuilder.() -> Unit = {
+ globalDefaults {
+ this@globalDefaults.frontend = frontend
+ targetPlatform = JvmPlatforms.defaultJvmPlatform
+ dependencyKind = DependencyKind.Source
+ }
+ useConfigurators(
+ ::CommonEnvironmentConfigurator,
+ ::JvmEnvironmentConfigurator,
+ )
+ assertions = JUnit5Assertions
+ useAdditionalService<TemporaryDirectoryManager>(::TemporaryDirectoryManagerImpl)
+ useAdditionalService<ApplicationDisposableProvider> { ExecutionListenerBasedDisposableProvider() }
+ useAdditionalService<KotlinStandardLibrariesPathProvider> { StandardLibrariesPathProviderForKotlinProject }
+
+ useDirectives(*AbstractKotlinCompilerTest.defaultDirectiveContainers.toTypedArray())
+ useDirectives(JvmEnvironmentConfigurationDirectives)
+
+ defaultDirectives {
+ +JvmEnvironmentConfigurationDirectives.FULL_JDK
+ // SourceFileProviderImpl doesn't group files by module. Let's load them manually.
+ +JvmEnvironmentConfigurationDirectives.SKIP_JAVA_SOURCES
+ +ConfigurationDirectives.WITH_STDLIB
+ +LanguageSettingsDirectives.ALLOW_KOTLIN_PACKAGE
+ }
+
+ configureTest(this)
+
+ startingArtifactFactory = { ResultingArtifact.Source() }
+ this.testInfo = this@AbstractKSPTest.testInfo
+ }
+
+ fun TestModule.loadKtFiles(project: Project): List<KtFile> {
+ return files.filter { it.isKtFile }.map {
+ KtTestUtil.createFile(it.name, it.originalContent, project)
+ }
+ }
+
+ fun TestModule.writeJavaFiles(): List<File> {
+ javaDir.mkdirs()
+ val files = javaFiles.map { it to File(javaDir, it.relativePath) }
+ files.forEach { (testFile, file) ->
+ file.parentFile.mkdirs()
+ file.writeText(testFile.originalContent)
+ }
+ return files.map { it.second }
+ }
+
+ // No, this is far from complete. It only works for our test cases.
+ //
+ // No, neither CompiledLibraryProvider nor LibraryEnvironmentConfigurator can be used. They rely on
+ // dist/kotlinc/lib/*
+ //
+ // No, sourceFileProvider doesn't group files by module unfortunately. Let's do it by ourselves.
+ open fun compileModule(module: TestModule, testServices: TestServices) {
+ val javaFiles = module.writeJavaFiles()
+ val compilerConfiguration = testServices.compilerConfigurationProvider.getCompilerConfiguration(module)
+ val dependencies = module.allDependencies.map { outDirForModule(it.moduleName) }
+ compilerConfiguration.addJvmClasspathRoots(dependencies)
+ compilerConfiguration.addJavaSourceRoot(module.javaDir)
+
+ // TODO: other platforms
+ val kotlinCoreEnvironment = KotlinCoreEnvironment.createForTests(
+ disposable,
+ compilerConfiguration,
+ EnvironmentConfigFiles.JVM_CONFIG_FILES
+ )
+ val ktFiles = module.loadKtFiles(kotlinCoreEnvironment.project)
+ GenerationUtils.compileFilesTo(ktFiles, kotlinCoreEnvironment, module.outDir)
+
+ if (module.javaFiles.isEmpty())
+ return
+
+ val classpath = (dependencies + KtTestUtil.getAnnotationsJar() + module.outDir)
+ .joinToString(File.pathSeparator) { it.absolutePath }
+ val options = listOf(
+ "-classpath", classpath,
+ "-d", module.outDir.path
+ )
+ compileJavaFiles(javaFiles, options, assertions = JUnit5Assertions)
+ }
+
+ fun runTest(@TestDataFile path: String) {
+ val testConfiguration = testConfiguration(path, configure)
+ Disposer.register(disposable, testConfiguration.rootDisposable)
+ val testServices = testConfiguration.testServices
+ val moduleStructure = testConfiguration.moduleStructureExtractor.splitTestDataByModules(
+ path,
+ testConfiguration.directives,
+ )
+ val mainModule = moduleStructure.modules.last()
+ val libModules = moduleStructure.modules.dropLast(1)
+
+ for (lib in libModules) {
+ compileModule(lib, testServices)
+ }
+ val compilerConfigurationMain = testServices.compilerConfigurationProvider.getCompilerConfiguration(mainModule)
+ compilerConfigurationMain.addJvmClasspathRoots(libModules.map { it.outDir })
+
+ val contents = mainModule.files.first().originalFile.readLines()
+
+ val testProcessorName = contents
+ .filter { it.startsWith(TEST_PROCESSOR) }
+ .single()
+ .substringAfter(TEST_PROCESSOR)
+ .trim()
+ val testProcessor: AbstractTestProcessor =
+ Class.forName("com.google.devtools.ksp.processor.$testProcessorName")
+ .getDeclaredConstructor().newInstance() as AbstractTestProcessor
+
+ val expectedResults = contents
+ .dropWhile { !it.startsWith(EXPECTED_RESULTS) }
+ .drop(1)
+ .takeWhile { !it.startsWith("// END") }
+ .map { it.substring(3).trim() }
+
+ val results = runTest(testServices, mainModule, libModules, testProcessor)
+ Assertions.assertEquals(expectedResults.joinToString("\n"), results.joinToString("\n"))
+ }
+}