diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierList.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierList.kt index af55be7eb15..073c259a0bb 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierList.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierList.kt @@ -30,7 +30,9 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.isPropertyParameter import org.jetbrains.kotlin.resolve.AnnotationChecker +import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.source.getPsi abstract class KtLightModifierList>(protected val owner: T) @@ -115,8 +117,19 @@ private fun lightAnnotationsForEntries(lightModifierList: KtLightModifierList<*> } } -private fun getAnnotationDescriptors(declaration: KtDeclaration?, annotatedLightElement: KtLightElement<*, *>): List { - val descriptor = declaration?.let { LightClassGenerationSupport.getInstance(it.project).resolveToDescriptor(it) } +private fun getAnnotationDescriptors(declaration: KtDeclaration, annotatedLightElement: KtLightElement<*, *>): List { + val context = LightClassGenerationSupport.getInstance(declaration.project).analyze(declaration) + + val descriptor = if (declaration is KtParameter && declaration.isPropertyParameter()) { + if (annotatedLightElement is KtLightParameter && annotatedLightElement.method.isConstructor) + context[BindingContext.VALUE_PARAMETER, declaration] + else + context[BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, declaration] + } + else { + context[BindingContext.DECLARATION_TO_DESCRIPTOR, declaration] + } + val annotatedDescriptor = when { descriptor is ClassDescriptor && annotatedLightElement is KtLightMethod && annotatedLightElement.isConstructor -> descriptor.unsubstitutedPrimaryConstructor descriptor !is PropertyDescriptor || annotatedLightElement !is KtLightMethod -> descriptor @@ -125,9 +138,9 @@ private fun getAnnotationDescriptors(declaration: KtDeclaration?, annotatedLight else -> descriptor } ?: return emptyList() - return annotatedDescriptor.annotations.getAllAnnotations(). - filter { it.matches(annotatedLightElement) }. - map { it.annotation } + return annotatedDescriptor.annotations.getAllAnnotations() + .filter { it.matches(annotatedLightElement) } + .map { it.annotation } } private fun hasAnnotationsInSource(declaration: KtDeclaration): Boolean { @@ -143,12 +156,17 @@ private fun hasAnnotationsInSource(declaration: KtDeclaration): Boolean { } private fun AnnotationWithTarget.matches(annotated: KtLightElement<*, *>): Boolean { - if (annotated !is KtLightFieldImpl.KtLightFieldForDeclaration) return true + if (annotated is KtLightFieldImpl.KtLightFieldForDeclaration) { + if (target == AnnotationUseSiteTarget.FIELD) return true - if (target == AnnotationUseSiteTarget.FIELD) return true + if (target != null) return false - if (target != null) return false + val declarationSiteTargets = AnnotationChecker.applicableTargetSet(annotation) + return KotlinTarget.FIELD in declarationSiteTargets && KotlinTarget.PROPERTY !in declarationSiteTargets + } + else if (annotated is KtLightParameter && annotated.method.isSetter) { + return target == AnnotationUseSiteTarget.SETTER_PARAMETER + } - val declarationSiteTargets = AnnotationChecker.applicableTargetSet(annotation) - return KotlinTarget.FIELD in declarationSiteTargets && KotlinTarget.PROPERTY !in declarationSiteTargets + return true } \ No newline at end of file diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightParameter.java b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightParameter.java index 936de3408f8..70ba3b81cbf 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightParameter.java +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightParameter.java @@ -148,7 +148,8 @@ public class KtLightParameter extends LightParameter implements KtLightDeclarati @Override public String getText() { - return ""; + KtParameter origin = getKotlinOrigin(); + return origin != null ? origin.getText() : ""; } @Override diff --git a/plugins/uast-kotlin/testData/ParameterPropertyWithAnnotation.kt b/plugins/uast-kotlin/testData/ParameterPropertyWithAnnotation.kt new file mode 100644 index 00000000000..74763263e6f --- /dev/null +++ b/plugins/uast-kotlin/testData/ParameterPropertyWithAnnotation.kt @@ -0,0 +1,5 @@ +annotation class MyAnnotation + +class Test1(@MyAnnotation var bar: Int) + +class Test2(@get:MyAnnotation @set:MyAnnotation @setparam:MyAnnotation @property:MyAnnotation @field:MyAnnotation var bar: Int) \ No newline at end of file diff --git a/plugins/uast-kotlin/tests/KotlinUastApiTest.kt b/plugins/uast-kotlin/tests/KotlinUastApiTest.kt index 2075b64d6fb..0dae12ad762 100644 --- a/plugins/uast-kotlin/tests/KotlinUastApiTest.kt +++ b/plugins/uast-kotlin/tests/KotlinUastApiTest.kt @@ -7,6 +7,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getParentOfType import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase import org.jetbrains.uast.* import org.jetbrains.uast.test.env.findElementByText +import org.jetbrains.uast.visitor.UastVisitor import org.junit.Assert import org.junit.Test @@ -67,4 +68,34 @@ class KotlinUastApiTest : AbstractKotlinUastTest() { assertTrue(bar.containingFile.text!!, bar.psi.modifierList.hasModifierProperty(PsiModifier.DEFAULT)) } } + + @Test fun testParameterPropertyWithAnnotation() { + doTest("ParameterPropertyWithAnnotation") { _, file -> + val test1 = file.classes.find { it.name == "Test1" }!! + + val constructor1 = test1.methods.find { it.name == "Test1" }!! + assertTrue(constructor1.uastParameters.first().annotations.any { it.qualifiedName == "MyAnnotation" }) + + val getter1 = test1.methods.find { it.name == "getBar" }!! + assertFalse(getter1.annotations.any { it.qualifiedName == "MyAnnotation" }) + + val setter1 = test1.methods.find { it.name == "setBar" }!! + assertFalse(setter1.annotations.any { it.qualifiedName == "MyAnnotation" }) + assertFalse(setter1.uastParameters.first().annotations.any { it.qualifiedName == "MyAnnotation" }) + + + val test2 = file.classes.find { it.name == "Test2" }!! + val constructor2 = test2.methods.find { it.name == "Test2" }!! + assertFalse(constructor2.uastParameters.first().annotations.any { it.qualifiedName == "MyAnnotation" }) + + val getter2 = test2.methods.find { it.name == "getBar" }!! + getter2.annotations.single { it.qualifiedName == "MyAnnotation" } + + val setter2 = test2.methods.find { it.name == "setBar" }!! + setter2.annotations.single { it.qualifiedName == "MyAnnotation" } + setter2.uastParameters.first().annotations.single { it.qualifiedName == "MyAnnotation" } + + test2.fields.find { it.name == "bar" }!!.annotations.single { it.qualifiedName == "MyAnnotation" } + } + } }