Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

manually look up in scope when annotation argument type is nested annotation. #1099

Merged
merged 1 commit into from Sep 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -20,6 +20,7 @@ package com.google.devtools.ksp.symbol.impl.binary
import com.google.devtools.ksp.ExceptionMessage
import com.google.devtools.ksp.KSObjectCache
import com.google.devtools.ksp.findPsi
import com.google.devtools.ksp.getClassDeclarationByName
import com.google.devtools.ksp.processing.impl.ResolverImpl
import com.google.devtools.ksp.symbol.*
import com.google.devtools.ksp.symbol.impl.java.KSAnnotationJavaImpl
Expand All @@ -35,6 +36,7 @@ import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.NotFoundClasses
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.load.java.components.JavaAnnotationDescriptor
Expand All @@ -53,7 +55,9 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
import org.jetbrains.kotlin.resolve.constants.*
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.isError
import org.jetbrains.kotlin.types.typeUtil.builtIns
import org.jetbrains.org.objectweb.asm.AnnotationVisitor
Expand Down Expand Up @@ -160,14 +164,31 @@ internal fun AnnotationDescriptor.getDefaultArguments(ownerAnnotation: KSAnnotat
return this.type.getDefaultConstructorArguments(emptyList(), ownerAnnotation)
}

internal fun TypeConstructor.toDeclarationDescriptor(): ClassDescriptor? {
if (this.declarationDescriptor !is NotFoundClasses.MockClassDescriptor) {
return this.declarationDescriptor as? ClassDescriptor
}
val fqName = (this.declarationDescriptor as? ClassDescriptor)?.fqNameSafe ?: return null
val shortNames = fqName.shortName().asString().split("$")
var parent = ResolverImpl.instance!!
.getClassDeclarationByName("${fqName.parent().asString()}.${shortNames.first()}")
for (i in 1 until shortNames.size) {
if (parent == null) {
return null
}
parent = parent.declarations
.filterIsInstance<KSClassDeclaration>()
.singleOrNull { it.simpleName.asString() == shortNames[i] }
}
return parent?.let { ResolverImpl.instance!!.resolveClassDeclaration(it) }
}

internal fun KotlinType.getDefaultConstructorArguments(
excludeNames: List<String>,
ownerAnnotation: KSAnnotation
): List<KSValueArgument> {
return (this.constructor.declarationDescriptor as? ClassDescriptor)?.constructors?.single()
?.let { argumentsFromDefault ->
argumentsFromDefault.getAbsentDefaultArguments(excludeNames, ownerAnnotation)
} ?: emptyList()
return this.constructor.toDeclarationDescriptor()?.constructors?.single()
?.getAbsentDefaultArguments(excludeNames, ownerAnnotation) ?: emptyList()
}

fun ClassConstructorDescriptor.getAbsentDefaultArguments(
Expand Down
Expand Up @@ -230,6 +230,12 @@ class KSPCompilerPluginTest : AbstractKSPCompilerPluginTest() {
runTest("testData/api/functionTypes.kt")
}

@TestMetadata("getAnnotationByTypeWithInnerDefault.kt")
@Test
fun testGetAnnotationByTypeWithInnerDefault() {
runTest("testData/api/getAnnotationByTypeWithInnerDefault.kt")
}

@DisabledOnOs(OS.WINDOWS)
@TestMetadata("getPackage.kt")
@Test
Expand Down
@@ -0,0 +1,42 @@
/*
* Copyright 2022 Google LLC
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// WITH_RUNTIME
// TEST PROCESSOR: GetAnnotationByTypeProcessor
// EXPECTED:
// com.google.devtools.ksp.processor.KotlinAnnotationWithInnerDefaults.InnerAnnotation[innerAnnotationDefault=7, moreInnerAnnotation=com.google.devtools.ksp.processor.KotlinAnnotationWithInnerDefaults.InnerAnnotation.MoreInnerAnnotation[moreInnerAnnotationDefault=OK]]
// END
// MODULE: lib
// FILE: KotlinAnnotationWithInnerDefaults.kt
package com.google.devtools.ksp.processor
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)
}
}

// MODULE: main(lib)
// FILE: com/google/devtools/ksp/processor/a.kt
package com.google.devtools.ksp.processor

@KotlinAnnotationWithInnerDefaults
class A
3 changes: 3 additions & 0 deletions compiler-plugin/testData/api/getByName.kt
Expand Up @@ -28,6 +28,8 @@ open class Foo {
fun overload(a: Int) = "Overload"
fun overload() = "Overload"
val lib1MemberProp = 1.0

class FooNested {}
}

fun lib1TopFun(): Int {
Expand Down Expand Up @@ -61,6 +63,7 @@ package source
class FooInSource {
fun sourceMemberFun() = 1
val sourceMemberProp = 1.0
class FooInSourceNested
}

val propInSource = 1
Expand Down
@@ -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()
}
}
@@ -1,5 +1,6 @@
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
Expand All @@ -13,6 +14,12 @@ class GetByNameProcessor : AbstractTestProcessor() {
}

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",
Expand All @@ -28,6 +35,11 @@ class GetByNameProcessor : AbstractTestProcessor() {
"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")
Expand Down