Deserialize receiver parameter annotations for extension functions
This commit is contained in:
+22
@@ -0,0 +1,22 @@
|
||||
package test
|
||||
|
||||
target(AnnotationTarget.VALUE_PARAMETER)
|
||||
annotation class Ann
|
||||
|
||||
class A {
|
||||
|
||||
@receiver:Ann
|
||||
fun String.myLength(@Ann q:String): Int {
|
||||
return length()
|
||||
}
|
||||
|
||||
@receiver:Ann
|
||||
val String.myLength2: Int
|
||||
get() = length()
|
||||
|
||||
@receiver:Ann
|
||||
var String.myLength3: Int
|
||||
get() = length()
|
||||
set(v) {}
|
||||
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package test
|
||||
|
||||
internal final class A {
|
||||
/*primary*/ public constructor A()
|
||||
@receiver:test.Ann() internal final val kotlin.String.myLength2: kotlin.Int
|
||||
internal final fun kotlin.String.<get-myLength2>(): kotlin.Int
|
||||
@receiver:test.Ann() internal final var kotlin.String.myLength3: kotlin.Int
|
||||
internal final fun kotlin.String.<get-myLength3>(): kotlin.Int
|
||||
internal final fun kotlin.String.<set-myLength3>(/*0*/ v: kotlin.Int): kotlin.Unit
|
||||
@receiver:test.Ann() internal final fun kotlin.String.myLength(/*0*/ test.Ann() q: kotlin.String): kotlin.Int
|
||||
}
|
||||
|
||||
kotlin.annotation.target(allowedTargets = {AnnotationTarget.VALUE_PARAMETER}) kotlin.annotation.annotation() internal final class Ann : kotlin.Annotation {
|
||||
/*primary*/ public constructor Ann()
|
||||
}
|
||||
@@ -2361,6 +2361,21 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest {
|
||||
doTestCompiledKotlin(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class WithUseSiteTarget extends AbstractLoadJavaTest {
|
||||
public void testAllFilesPresentInWithUseSiteTarget() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("ReceiverTarget.kt")
|
||||
public void testReceiverTarget() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget/ReceiverTarget.kt");
|
||||
doTestCompiledKotlin(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/loadJava/compiledKotlin/class")
|
||||
|
||||
+15
@@ -470,6 +470,21 @@ public class JvmRuntimeDescriptorLoaderTestGenerated extends AbstractJvmRuntimeD
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class WithUseSiteTarget extends AbstractJvmRuntimeDescriptorLoaderTest {
|
||||
public void testAllFilesPresentInWithUseSiteTarget() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("ReceiverTarget.kt")
|
||||
public void testReceiverTarget() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget/ReceiverTarget.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/loadJava/compiledKotlin/class")
|
||||
|
||||
+16
@@ -132,6 +132,22 @@ public abstract class AbstractBinaryClassAnnotationAndConstantLoader<A : Any, C
|
||||
return listOf()
|
||||
}
|
||||
|
||||
override fun loadExtensionReceiverParameterAnnotations(
|
||||
container: ProtoContainer,
|
||||
callable: ProtoBuf.Callable,
|
||||
nameResolver: NameResolver,
|
||||
kind: AnnotatedCallableKind
|
||||
): List<A> {
|
||||
if (!callable.hasReceiverType()) return emptyList()
|
||||
val methodSignature = getCallableSignature(callable, nameResolver, kind)
|
||||
if (methodSignature != null) {
|
||||
val paramSignature = MemberSignature.fromMethodSignatureAndParameterIndex(methodSignature, 0)
|
||||
return findClassAndLoadMemberAnnotations(container, callable, nameResolver, kind, paramSignature)
|
||||
}
|
||||
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override fun loadTypeAnnotations(type: ProtoBuf.Type, nameResolver: NameResolver): List<A> {
|
||||
return type.getExtension(JvmProtoBuf.typeAnnotation).map { loadTypeAnnotation(it, nameResolver) }
|
||||
}
|
||||
|
||||
+7
@@ -58,6 +58,13 @@ class BuiltInsAnnotationAndConstantLoader(
|
||||
return annotations.map { proto -> deserializer.deserializeAnnotation(proto, nameResolver) }
|
||||
}
|
||||
|
||||
override fun loadExtensionReceiverParameterAnnotations(
|
||||
container: ProtoContainer,
|
||||
callable: ProtoBuf.Callable,
|
||||
nameResolver: NameResolver,
|
||||
kind: AnnotatedCallableKind
|
||||
): List<AnnotationDescriptor> = emptyList()
|
||||
|
||||
override fun loadTypeAnnotations(proto: ProtoBuf.Type, nameResolver: NameResolver): List<AnnotationDescriptor> {
|
||||
// TODO: support type annotations in built-ins
|
||||
return listOf()
|
||||
|
||||
+8
@@ -47,6 +47,14 @@ public interface AnnotationAndConstantLoader<A, C> {
|
||||
@NotNull ProtoBuf.Callable.ValueParameter proto
|
||||
);
|
||||
|
||||
@NotNull
|
||||
List<A> loadExtensionReceiverParameterAnnotations(
|
||||
@NotNull ProtoContainer container,
|
||||
@NotNull ProtoBuf.Callable callable,
|
||||
@NotNull NameResolver nameResolver,
|
||||
@NotNull AnnotatedCallableKind kind
|
||||
);
|
||||
|
||||
@NotNull
|
||||
List<A> loadTypeAnnotations(
|
||||
@NotNull ProtoBuf.Type type,
|
||||
|
||||
+40
-4
@@ -17,6 +17,9 @@
|
||||
package org.jetbrains.kotlin.serialization.deserialization
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyGetterDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertySetterDescriptorImpl
|
||||
@@ -29,6 +32,7 @@ import org.jetbrains.kotlin.serialization.ProtoBuf.Callable.CallableKind.VAL
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf.Callable.CallableKind.VAR
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.*
|
||||
import org.jetbrains.kotlin.utils.toReadOnlyList
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
|
||||
public class MemberDeserializer(private val c: DeserializationContext) {
|
||||
public fun loadCallable(proto: Callable): CallableMemberDescriptor {
|
||||
@@ -43,9 +47,16 @@ public class MemberDeserializer(private val c: DeserializationContext) {
|
||||
private fun loadProperty(proto: Callable): PropertyDescriptor {
|
||||
val flags = proto.getFlags()
|
||||
|
||||
val hasGetter = Flags.HAS_GETTER.get(flags)
|
||||
|
||||
val propertyAnnotations = if (hasGetter)
|
||||
getAnnotationsWithReceiverTargeted(proto, AnnotatedCallableKind.PROPERTY, AnnotatedCallableKind.PROPERTY_GETTER)
|
||||
else
|
||||
getAnnotations(proto, flags, AnnotatedCallableKind.PROPERTY)
|
||||
|
||||
val property = DeserializedPropertyDescriptor(
|
||||
c.containingDeclaration, null,
|
||||
getAnnotations(proto, flags, AnnotatedCallableKind.PROPERTY),
|
||||
propertyAnnotations,
|
||||
modality(Flags.MODALITY.get(flags)),
|
||||
visibility(Flags.VISIBILITY.get(flags)),
|
||||
Flags.CALLABLE_KIND.get(flags) == Callable.CallableKind.VAR,
|
||||
@@ -63,7 +74,7 @@ public class MemberDeserializer(private val c: DeserializationContext) {
|
||||
if (proto.hasReceiverType()) local.typeDeserializer.type(proto.getReceiverType()) else null
|
||||
)
|
||||
|
||||
val getter = if (Flags.HAS_GETTER.get(flags)) {
|
||||
val getter = if (hasGetter) {
|
||||
val getterFlags = proto.getGetterFlags()
|
||||
val isNotDefault = proto.hasGetterFlags() && Flags.IS_NOT_DEFAULT.get(getterFlags)
|
||||
val getter = if (isNotDefault) {
|
||||
@@ -128,11 +139,13 @@ public class MemberDeserializer(private val c: DeserializationContext) {
|
||||
}
|
||||
|
||||
private fun loadFunction(proto: Callable): CallableMemberDescriptor {
|
||||
val annotations = getAnnotations(proto, proto.getFlags(), AnnotatedCallableKind.FUNCTION)
|
||||
val annotations = getAnnotationsWithReceiverTargeted(proto, AnnotatedCallableKind.FUNCTION)
|
||||
val function = DeserializedSimpleFunctionDescriptor.create(c.containingDeclaration, proto, c.nameResolver, annotations)
|
||||
val local = c.childContext(function, proto.getTypeParameterList())
|
||||
val receiverParameterType = if (proto.hasReceiverType()) local.typeDeserializer.type(proto.getReceiverType()) else null
|
||||
|
||||
function.initialize(
|
||||
if (proto.hasReceiverType()) local.typeDeserializer.type(proto.getReceiverType()) else null,
|
||||
receiverParameterType,
|
||||
getDispatchReceiverParameter(),
|
||||
local.typeDeserializer.ownTypeParameters,
|
||||
local.memberDeserializer.valueParameters(proto, AnnotatedCallableKind.FUNCTION),
|
||||
@@ -163,6 +176,29 @@ public class MemberDeserializer(private val c: DeserializationContext) {
|
||||
return descriptor
|
||||
}
|
||||
|
||||
private fun getAnnotationsWithReceiverTargeted(
|
||||
proto: Callable,
|
||||
kind: AnnotatedCallableKind,
|
||||
receiverTargetedKind: AnnotatedCallableKind = kind
|
||||
): Annotations {
|
||||
return DeserializedAnnotationsWithPossibleTargets(c.storageManager) {
|
||||
val annotations = arrayListOf<AnnotationWithTarget>()
|
||||
val container = c.containingDeclaration.asProtoContainer()
|
||||
|
||||
annotations += c.components.annotationAndConstantLoader
|
||||
.loadCallableAnnotations(container, proto, c.nameResolver, kind)
|
||||
.map { AnnotationWithTarget(it, null) }
|
||||
|
||||
if (proto.hasReceiverType()) {
|
||||
annotations += c.components.annotationAndConstantLoader
|
||||
.loadExtensionReceiverParameterAnnotations(container, proto, c.nameResolver, receiverTargetedKind)
|
||||
.map { AnnotationWithTarget(it, AnnotationUseSiteTarget.RECEIVER) }
|
||||
}
|
||||
|
||||
annotations
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAnnotations(proto: Callable, flags: Int, kind: AnnotatedCallableKind): Annotations {
|
||||
if (!Flags.HAS_ANNOTATIONS.get(flags)) {
|
||||
return Annotations.EMPTY
|
||||
|
||||
+17
-7
@@ -28,22 +28,32 @@ import org.jetbrains.kotlin.utils.toReadOnlyList
|
||||
class DeserializedAnnotations(
|
||||
storageManager: StorageManager,
|
||||
compute: () -> List<AnnotationDescriptor>
|
||||
) : DeserializedAnnotationsWithPossibleTargets(
|
||||
storageManager,
|
||||
{ compute().map { AnnotationWithTarget(it, null) } })
|
||||
|
||||
open class DeserializedAnnotationsWithPossibleTargets(
|
||||
storageManager: StorageManager,
|
||||
compute: () -> List<AnnotationWithTarget>
|
||||
) : Annotations {
|
||||
private val annotations = storageManager.createLazyValue { compute().toReadOnlyList() }
|
||||
|
||||
override fun isEmpty(): Boolean = annotations().isEmpty()
|
||||
|
||||
override fun findAnnotation(fqName: FqName) = annotations().firstOrNull {
|
||||
annotation ->
|
||||
val descriptor = annotation.getType().getConstructor().getDeclarationDescriptor()
|
||||
annotationWithTarget ->
|
||||
if (annotationWithTarget.target != null) return@firstOrNull false
|
||||
val descriptor = annotationWithTarget.annotation.type.constructor.declarationDescriptor
|
||||
descriptor is ClassDescriptor && fqName.equalsTo(DescriptorUtils.getFqName(descriptor))
|
||||
}
|
||||
}?.annotation
|
||||
|
||||
override fun findExternalAnnotation(fqName: FqName) = null
|
||||
|
||||
override fun getUseSiteTargetedAnnotations() = emptyList<AnnotationWithTarget>()
|
||||
override fun getUseSiteTargetedAnnotations() = annotations().filter { it.target != null }
|
||||
|
||||
override fun getAllAnnotations() = this.map { AnnotationWithTarget(it, null) }
|
||||
override fun getAllAnnotations() = annotations()
|
||||
|
||||
override fun iterator(): Iterator<AnnotationDescriptor> = annotations().iterator()
|
||||
}
|
||||
override fun iterator(): Iterator<AnnotationDescriptor> {
|
||||
return annotations().asSequence().filter { it.target == null }.map { it.annotation }.iterator()
|
||||
}
|
||||
}
|
||||
+7
@@ -49,6 +49,13 @@ public class AnnotationLoaderForKotlinJavaScriptStubBuilder() : AnnotationAndCon
|
||||
): List<ClassId> =
|
||||
proto.getExtension(JsProtoBuf.parameterAnnotation).orEmpty().map { nameResolver.getClassId(it.getId()) }
|
||||
|
||||
override fun loadExtensionReceiverParameterAnnotations(
|
||||
container: ProtoContainer,
|
||||
callable: ProtoBuf.Callable,
|
||||
nameResolver: NameResolver,
|
||||
kind: AnnotatedCallableKind
|
||||
): List<ClassId> = emptyList()
|
||||
|
||||
override fun loadTypeAnnotations(
|
||||
proto: ProtoBuf.Type,
|
||||
nameResolver: NameResolver
|
||||
|
||||
@@ -468,6 +468,21 @@ public class ResolveByStubTestGenerated extends AbstractResolveByStubTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class WithUseSiteTarget extends AbstractResolveByStubTest {
|
||||
public void testAllFilesPresentInWithUseSiteTarget() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("ReceiverTarget.kt")
|
||||
public void testReceiverTarget() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget/ReceiverTarget.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/loadJava/compiledKotlin/class")
|
||||
|
||||
+7
@@ -57,6 +57,13 @@ class KotlinJavascriptAnnotationAndConstantLoader(
|
||||
return annotations.map { proto -> deserializer.deserializeAnnotation(proto, nameResolver) }
|
||||
}
|
||||
|
||||
override fun loadExtensionReceiverParameterAnnotations(
|
||||
container: ProtoContainer,
|
||||
callable: ProtoBuf.Callable,
|
||||
nameResolver: NameResolver,
|
||||
kind: AnnotatedCallableKind
|
||||
): List<AnnotationDescriptor> = emptyList()
|
||||
|
||||
override fun loadTypeAnnotations(proto: ProtoBuf.Type, nameResolver: NameResolver): List<AnnotationDescriptor> {
|
||||
val annotations = proto.getExtension(JsProtoBuf.typeAnnotation).orEmpty()
|
||||
return annotations.map { proto -> deserializer.deserializeAnnotation(proto, nameResolver) }
|
||||
|
||||
Reference in New Issue
Block a user