diff options
author | Colin Cross <ccross@android.com> | 2023-04-24 05:24:44 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2023-04-24 05:24:44 +0000 |
commit | 3d25c313be6b4163b067093acdd84fb4709a8318 (patch) | |
tree | eb4f6ef1605d14946320f6652a41372d71d2e7ab /test-utils/src/main | |
parent | 295843a05a00584ebc2e7f8154fb6a5bf182b3a2 (diff) | |
parent | d168506853c10dacdd1f7f5f13611b895be492a5 (diff) | |
download | ksp-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')
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")) + } +} |