diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/MovePropertyToConstructorIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/MovePropertyToConstructorIntention.kt index f27555d66c2..55d26094a7a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/MovePropertyToConstructorIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/MovePropertyToConstructorIntention.kt @@ -76,12 +76,9 @@ class MovePropertyToConstructorIntention : val commentSaver = CommentSaver(element) + val context = element.analyze(BodyResolveMode.PARTIAL) val propertyAnnotationsText = element.modifierList?.annotationEntries?.joinToString(separator = " ") { - if (it.isApplicableToConstructorParameter()) { - it.getTextWithUseSiteIfMissing(AnnotationUseSiteTarget.FIELD.renderName) - } else { - it.text - } + it.getTextWithUseSite(context) } if (constructorParameter != null) { @@ -129,19 +126,24 @@ class MovePropertyToConstructorIntention : return parameterDescriptor.source.getPsi() as? KtParameter } - private fun KtAnnotationEntry.isApplicableToConstructorParameter(): Boolean { - val context = analyze(BodyResolveMode.PARTIAL) - val descriptor = context[BindingContext.ANNOTATION, this] ?: return false + private fun KtAnnotationEntry.getTextWithUseSite(context: BindingContext): String { + if (useSiteTarget != null) return text + val typeReference = this.typeReference?.text ?: return text + val descriptor = context[BindingContext.ANNOTATION, this] ?: return text val applicableTargets = AnnotationChecker.applicableTargetSet(descriptor) - return applicableTargets.contains(KotlinTarget.VALUE_PARAMETER) + val valueArgumentList = valueArgumentList?.text.orEmpty() + return when { + KotlinTarget.VALUE_PARAMETER !in applicableTargets -> + text + KotlinTarget.PROPERTY in applicableTargets -> + "@${AnnotationUseSiteTarget.PROPERTY.renderName}:$typeReference$valueArgumentList" + KotlinTarget.FIELD in applicableTargets -> + "@${AnnotationUseSiteTarget.FIELD.renderName}:$typeReference$valueArgumentList" + else -> + text + } } - private fun KtAnnotationEntry.getTextWithUseSiteIfMissing(useSite: String) = - if (useSiteTarget == null) - "@$useSite:${typeReference?.text.orEmpty()}${valueArgumentList?.text.orEmpty()}" - else - text - private fun KotlinType.render() = IdeDescriptorRenderers.SOURCE_CODE.renderType(this) private fun KtModifierList.getModifiersText() = getModifiers().joinToString(separator = " ") { it.text } diff --git a/idea/testData/intentions/movePropertyToConstructor/annotationTarget.kt b/idea/testData/intentions/movePropertyToConstructor/annotationTarget.kt new file mode 100644 index 00000000000..8529cce0c8d --- /dev/null +++ b/idea/testData/intentions/movePropertyToConstructor/annotationTarget.kt @@ -0,0 +1,23 @@ +annotation class Ann1(val i: Int, val j: Int) + +@Target(AnnotationTarget.PROPERTY) +annotation class Ann2(val i: Int, val j: Int) + +@Target(AnnotationTarget.FIELD) +annotation class Ann3(val i: Int, val j: Int) + +@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD, AnnotationTarget.PROPERTY) +annotation class Ann4(val i: Int, val j: Int) + +@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD) +annotation class Ann5(val i: Int, val j: Int) + +class Test { + @get:Ann1(0, 0) + @Ann1(1, 11) + @Ann2(2, 22) + @Ann3(3, 33) + @Ann4(4, 44) + @Ann5(5, 55) + val foo = "" +} \ No newline at end of file diff --git a/idea/testData/intentions/movePropertyToConstructor/annotationTarget.kt.after b/idea/testData/intentions/movePropertyToConstructor/annotationTarget.kt.after new file mode 100644 index 00000000000..db80f2a6c17 --- /dev/null +++ b/idea/testData/intentions/movePropertyToConstructor/annotationTarget.kt.after @@ -0,0 +1,16 @@ +annotation class Ann1(val i: Int, val j: Int) + +@Target(AnnotationTarget.PROPERTY) +annotation class Ann2(val i: Int, val j: Int) + +@Target(AnnotationTarget.FIELD) +annotation class Ann3(val i: Int, val j: Int) + +@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD, AnnotationTarget.PROPERTY) +annotation class Ann4(val i: Int, val j: Int) + +@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD) +annotation class Ann5(val i: Int, val j: Int) + +class Test(@get:Ann1(0, 0) @property:Ann1(1, 11) @Ann2(2, 22) @Ann3(3, 33) @property:Ann4(4, 44) @field:Ann5(5, 55) val foo: String = "") { +} \ No newline at end of file diff --git a/idea/testData/intentions/movePropertyToConstructor/annotationWithUseSite.kt b/idea/testData/intentions/movePropertyToConstructor/annotationWithUseSite.kt index 113f247c93b..c5416db290a 100644 --- a/idea/testData/intentions/movePropertyToConstructor/annotationWithUseSite.kt +++ b/idea/testData/intentions/movePropertyToConstructor/annotationWithUseSite.kt @@ -4,5 +4,5 @@ annotation class Annotation3(val a: Int = 0) class TestClass(@Annotation1(42) @Annotation3(42) initialText: String = "LoremIpsum") { - private @Annotation1(42) @property:Annotation2(42) val text = initialText + private @Annotation1(42) @field:Annotation2(42) val text = initialText } \ No newline at end of file diff --git a/idea/testData/intentions/movePropertyToConstructor/annotationWithUseSite.kt.after b/idea/testData/intentions/movePropertyToConstructor/annotationWithUseSite.kt.after index f1505435a54..709fa1a04a8 100644 --- a/idea/testData/intentions/movePropertyToConstructor/annotationWithUseSite.kt.after +++ b/idea/testData/intentions/movePropertyToConstructor/annotationWithUseSite.kt.after @@ -3,5 +3,5 @@ annotation class Annotation2(val a: Int = 0) annotation class Annotation3(val a: Int = 0) -class TestClass(private @field:Annotation1(42) @property:Annotation2(42) @Annotation1(42) @Annotation3(42) val text: String = "LoremIpsum") { +class TestClass(private @property:Annotation1(42) @field:Annotation2(42) @Annotation1(42) @Annotation3(42) val text: String = "LoremIpsum") { } \ No newline at end of file diff --git a/idea/testData/intentions/movePropertyToConstructor/javaAnnotation.1.java b/idea/testData/intentions/movePropertyToConstructor/javaAnnotation.1.java new file mode 100644 index 00000000000..a06c7a58d52 --- /dev/null +++ b/idea/testData/intentions/movePropertyToConstructor/javaAnnotation.1.java @@ -0,0 +1 @@ +public @interface JavaAnn { } diff --git a/idea/testData/intentions/movePropertyToConstructor/javaAnnotation.1.java.after b/idea/testData/intentions/movePropertyToConstructor/javaAnnotation.1.java.after new file mode 100644 index 00000000000..a06c7a58d52 --- /dev/null +++ b/idea/testData/intentions/movePropertyToConstructor/javaAnnotation.1.java.after @@ -0,0 +1 @@ +public @interface JavaAnn { } diff --git a/idea/testData/intentions/movePropertyToConstructor/javaAnnotation.2.java b/idea/testData/intentions/movePropertyToConstructor/javaAnnotation.2.java new file mode 100644 index 00000000000..0b00349f313 --- /dev/null +++ b/idea/testData/intentions/movePropertyToConstructor/javaAnnotation.2.java @@ -0,0 +1,7 @@ +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; + +@Target({FIELD}) +public @interface JavaFieldAnn { +} \ No newline at end of file diff --git a/idea/testData/intentions/movePropertyToConstructor/javaAnnotation.2.java.after b/idea/testData/intentions/movePropertyToConstructor/javaAnnotation.2.java.after new file mode 100644 index 00000000000..0b00349f313 --- /dev/null +++ b/idea/testData/intentions/movePropertyToConstructor/javaAnnotation.2.java.after @@ -0,0 +1,7 @@ +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; + +@Target({FIELD}) +public @interface JavaFieldAnn { +} \ No newline at end of file diff --git a/idea/testData/intentions/movePropertyToConstructor/javaAnnotation.kt b/idea/testData/intentions/movePropertyToConstructor/javaAnnotation.kt new file mode 100644 index 00000000000..48439c84cf7 --- /dev/null +++ b/idea/testData/intentions/movePropertyToConstructor/javaAnnotation.kt @@ -0,0 +1,5 @@ +class Test { + @JavaAnn + @JavaFieldAnn + val foo = "" +} \ No newline at end of file diff --git a/idea/testData/intentions/movePropertyToConstructor/javaAnnotation.kt.after b/idea/testData/intentions/movePropertyToConstructor/javaAnnotation.kt.after new file mode 100644 index 00000000000..7a7fe3546fd --- /dev/null +++ b/idea/testData/intentions/movePropertyToConstructor/javaAnnotation.kt.after @@ -0,0 +1,2 @@ +class Test(@property:JavaAnn @JavaFieldAnn val foo: String = "") { +} \ No newline at end of file diff --git a/idea/testData/intentions/movePropertyToConstructor/simpleAnnotation.kt.after b/idea/testData/intentions/movePropertyToConstructor/simpleAnnotation.kt.after index 26c0cee5e88..e04169ff64b 100644 --- a/idea/testData/intentions/movePropertyToConstructor/simpleAnnotation.kt.after +++ b/idea/testData/intentions/movePropertyToConstructor/simpleAnnotation.kt.after @@ -1,4 +1,4 @@ annotation class SuperAnnotation -class TestClass(@field:SuperAnnotation val text: String) { +class TestClass(@property:SuperAnnotation val text: String) { } \ No newline at end of file diff --git a/idea/testData/intentions/movePropertyToConstructor/withoutMatchingParameter.kt b/idea/testData/intentions/movePropertyToConstructor/withoutMatchingParameter.kt index 5d6350bbe2b..9709fe7ea4b 100644 --- a/idea/testData/intentions/movePropertyToConstructor/withoutMatchingParameter.kt +++ b/idea/testData/intentions/movePropertyToConstructor/withoutMatchingParameter.kt @@ -4,5 +4,5 @@ annotation class Annotation3(val a: Int = 0) class TestClass(@Annotation1(42) @Annotation3(42) initialText: String = "LoremIpsum") { - private @Annotation1(42) @property:Annotation2(42) val text = "dolor sit amet" + private @Annotation1(42) @field:Annotation2(42) val text = "dolor sit amet" } \ No newline at end of file diff --git a/idea/testData/intentions/movePropertyToConstructor/withoutMatchingParameter.kt.after b/idea/testData/intentions/movePropertyToConstructor/withoutMatchingParameter.kt.after index c6cc01a819a..e310a176513 100644 --- a/idea/testData/intentions/movePropertyToConstructor/withoutMatchingParameter.kt.after +++ b/idea/testData/intentions/movePropertyToConstructor/withoutMatchingParameter.kt.after @@ -3,5 +3,5 @@ annotation class Annotation2(val a: Int = 0) annotation class Annotation3(val a: Int = 0) -class TestClass(@Annotation1(42) @Annotation3(42) initialText: String = "LoremIpsum", private @field:Annotation1(42) @property:Annotation2(42) val text: String = "dolor sit amet") { +class TestClass(@Annotation1(42) @Annotation3(42) initialText: String = "LoremIpsum", private @property:Annotation1(42) @field:Annotation2(42) val text: String = "dolor sit amet") { } \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index 3d5cb6ea31f..1547a6d3641 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -11825,6 +11825,11 @@ public class IntentionTestGenerated extends AbstractIntentionTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/movePropertyToConstructor"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true); } + @TestMetadata("annotationTarget.kt") + public void testAnnotationTarget() throws Exception { + runTest("idea/testData/intentions/movePropertyToConstructor/annotationTarget.kt"); + } + @TestMetadata("annotationWithUseSite.kt") public void testAnnotationWithUseSite() throws Exception { runTest("idea/testData/intentions/movePropertyToConstructor/annotationWithUseSite.kt"); @@ -11850,6 +11855,11 @@ public class IntentionTestGenerated extends AbstractIntentionTest { runTest("idea/testData/intentions/movePropertyToConstructor/getter.kt"); } + @TestMetadata("javaAnnotation.kt") + public void testJavaAnnotation() throws Exception { + runTest("idea/testData/intentions/movePropertyToConstructor/javaAnnotation.kt"); + } + @TestMetadata("lambda.kt") public void testLambda() throws Exception { runTest("idea/testData/intentions/movePropertyToConstructor/lambda.kt");