Move to constructor: choose property use-site target more precisely
#KT-26015 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
29390dab42
commit
de6fdc5733
+17
-15
@@ -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 }
|
||||
|
||||
@@ -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 <caret>foo = ""
|
||||
}
|
||||
@@ -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 = "") {
|
||||
}
|
||||
+1
-1
@@ -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 <caret>text = initialText
|
||||
private @Annotation1(42) @field:Annotation2(42) val <caret>text = initialText
|
||||
}
|
||||
+1
-1
@@ -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") {
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
public @interface JavaAnn { }
|
||||
+1
@@ -0,0 +1 @@
|
||||
public @interface JavaAnn { }
|
||||
@@ -0,0 +1,7 @@
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
|
||||
@Target({FIELD})
|
||||
public @interface JavaFieldAnn {
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
|
||||
@Target({FIELD})
|
||||
public @interface JavaFieldAnn {
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
class Test {
|
||||
@JavaAnn
|
||||
@JavaFieldAnn
|
||||
val <caret>foo = ""
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
class Test(@property:JavaAnn @JavaFieldAnn val foo: String = "") {
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
annotation class SuperAnnotation
|
||||
|
||||
class TestClass(@field:SuperAnnotation val text: String) {
|
||||
class TestClass(@property:SuperAnnotation val text: String) {
|
||||
}
|
||||
+1
-1
@@ -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 <caret>text = "dolor sit amet"
|
||||
private @Annotation1(42) @field:Annotation2(42) val <caret>text = "dolor sit amet"
|
||||
}
|
||||
+1
-1
@@ -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") {
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user