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 commentSaver = CommentSaver(element)
|
||||||
|
|
||||||
|
val context = element.analyze(BodyResolveMode.PARTIAL)
|
||||||
val propertyAnnotationsText = element.modifierList?.annotationEntries?.joinToString(separator = " ") {
|
val propertyAnnotationsText = element.modifierList?.annotationEntries?.joinToString(separator = " ") {
|
||||||
if (it.isApplicableToConstructorParameter()) {
|
it.getTextWithUseSite(context)
|
||||||
it.getTextWithUseSiteIfMissing(AnnotationUseSiteTarget.FIELD.renderName)
|
|
||||||
} else {
|
|
||||||
it.text
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (constructorParameter != null) {
|
if (constructorParameter != null) {
|
||||||
@@ -129,19 +126,24 @@ class MovePropertyToConstructorIntention :
|
|||||||
return parameterDescriptor.source.getPsi() as? KtParameter
|
return parameterDescriptor.source.getPsi() as? KtParameter
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KtAnnotationEntry.isApplicableToConstructorParameter(): Boolean {
|
private fun KtAnnotationEntry.getTextWithUseSite(context: BindingContext): String {
|
||||||
val context = analyze(BodyResolveMode.PARTIAL)
|
if (useSiteTarget != null) return text
|
||||||
val descriptor = context[BindingContext.ANNOTATION, this] ?: return false
|
val typeReference = this.typeReference?.text ?: return text
|
||||||
|
val descriptor = context[BindingContext.ANNOTATION, this] ?: return text
|
||||||
val applicableTargets = AnnotationChecker.applicableTargetSet(descriptor)
|
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 KotlinType.render() = IdeDescriptorRenderers.SOURCE_CODE.renderType(this)
|
||||||
|
|
||||||
private fun KtModifierList.getModifiersText() = getModifiers().joinToString(separator = " ") { it.text }
|
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") {
|
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)
|
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
|
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") {
|
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)
|
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);
|
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")
|
@TestMetadata("annotationWithUseSite.kt")
|
||||||
public void testAnnotationWithUseSite() throws Exception {
|
public void testAnnotationWithUseSite() throws Exception {
|
||||||
runTest("idea/testData/intentions/movePropertyToConstructor/annotationWithUseSite.kt");
|
runTest("idea/testData/intentions/movePropertyToConstructor/annotationWithUseSite.kt");
|
||||||
@@ -11850,6 +11855,11 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
|||||||
runTest("idea/testData/intentions/movePropertyToConstructor/getter.kt");
|
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")
|
@TestMetadata("lambda.kt")
|
||||||
public void testLambda() throws Exception {
|
public void testLambda() throws Exception {
|
||||||
runTest("idea/testData/intentions/movePropertyToConstructor/lambda.kt");
|
runTest("idea/testData/intentions/movePropertyToConstructor/lambda.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user