diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/RestrictedRetentionForExpressionAnnotationFactory.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/RestrictedRetentionForExpressionAnnotationFactory.kt index 429799cfea5..cc2b3876116 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/RestrictedRetentionForExpressionAnnotationFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/RestrictedRetentionForExpressionAnnotationFactory.kt @@ -9,9 +9,11 @@ import com.intellij.codeInsight.intention.IntentionAction import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.core.ShortenReferences +import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.containingClass @@ -28,9 +30,10 @@ object RestrictedRetentionForExpressionAnnotationFactory : KotlinIntentionAction val containingClass = annotationEntry.containingClass() ?: return emptyList() val retentionAnnotation = containingClass.annotation(KotlinBuiltIns.FQ_NAMES.retention) val targetAnnotation = containingClass.annotation(KotlinBuiltIns.FQ_NAMES.target) + val expressionTargetArgument = if (targetAnnotation != null) findExpressionTargetArgument(targetAnnotation) else null return listOfNotNull( - if (targetAnnotation != null) RemoveExpressionTargetFix(targetAnnotation) else null, + if (expressionTargetArgument != null) RemoveExpressionTargetFix(expressionTargetArgument) else null, if (retentionAnnotation == null) AddSourceRetentionFix(containingClass) else ChangeRetentionToSourceFix(retentionAnnotation) ) } @@ -42,6 +45,20 @@ object RestrictedRetentionForExpressionAnnotationFactory : KotlinIntentionAction } } + private fun findExpressionTargetArgument(targetAnnotation: KtAnnotationEntry): KtValueArgument? { + val valueArgumentList = targetAnnotation.valueArgumentList ?: return null + if (targetAnnotation.lambdaArguments.isNotEmpty()) return null + + for (valueArgument in valueArgumentList.arguments) { + val argumentExpression = valueArgument.getArgumentExpression() ?: continue + if (argumentExpression.text.contains(KotlinTarget.EXPRESSION.toString())) { + return valueArgument + } + } + + return null + } + private class AddSourceRetentionFix(element: KtClass) : KotlinQuickFixAction(element) { override fun getText() = "Add SOURCE retention" @@ -78,16 +95,23 @@ object RestrictedRetentionForExpressionAnnotationFactory : KotlinIntentionAction } } - private class RemoveExpressionTargetFix(targetAnnotation: KtAnnotationEntry) : - KotlinQuickFixAction(targetAnnotation) { + private class RemoveExpressionTargetFix(expressionTargetArgument: KtValueArgument) : + KotlinQuickFixAction(expressionTargetArgument) { override fun getText() = "Remove EXPRESSION target" override fun getFamilyName() = text override fun invoke(project: Project, editor: Editor?, file: KtFile) { - val targetAnnotation = element ?: return - targetAnnotation.delete() + val expressionTargetArgument = element ?: return + val argumentList = expressionTargetArgument.parent as? KtValueArgumentList ?: return + + if (argumentList.arguments.size == 1) { + val annotation = argumentList.parent as? KtAnnotationEntry ?: return + annotation.delete() + } else { + argumentList.removeArgument(expressionTargetArgument) + } } } } \ No newline at end of file diff --git a/idea/testData/quickfix/restrictedRetentionForExpressionAnnotation/removeExpressionTarget/multipleTargets.kt b/idea/testData/quickfix/restrictedRetentionForExpressionAnnotation/removeExpressionTarget/multipleTargets.kt new file mode 100644 index 00000000000..dbdfe2406c7 --- /dev/null +++ b/idea/testData/quickfix/restrictedRetentionForExpressionAnnotation/removeExpressionTarget/multipleTargets.kt @@ -0,0 +1,6 @@ +// "Remove EXPRESSION target" "true" +import kotlin.annotation.AnnotationTarget.* + +@Retention +@Target(FIELD, EXPRESSION, PROPERTY) +annotation class Ann \ No newline at end of file diff --git a/idea/testData/quickfix/restrictedRetentionForExpressionAnnotation/removeExpressionTarget/multipleTargets.kt.after b/idea/testData/quickfix/restrictedRetentionForExpressionAnnotation/removeExpressionTarget/multipleTargets.kt.after new file mode 100644 index 00000000000..f37692e34a2 --- /dev/null +++ b/idea/testData/quickfix/restrictedRetentionForExpressionAnnotation/removeExpressionTarget/multipleTargets.kt.after @@ -0,0 +1,6 @@ +// "Remove EXPRESSION target" "true" +import kotlin.annotation.AnnotationTarget.* + +@Retention +@Target(FIELD, PROPERTY) +annotation class Ann \ No newline at end of file diff --git a/idea/testData/quickfix/restrictedRetentionForExpressionAnnotation/removeExpressionTarget/multipleTargetsImported.kt b/idea/testData/quickfix/restrictedRetentionForExpressionAnnotation/removeExpressionTarget/multipleTargetsImported.kt new file mode 100644 index 00000000000..f61e5722e19 --- /dev/null +++ b/idea/testData/quickfix/restrictedRetentionForExpressionAnnotation/removeExpressionTarget/multipleTargetsImported.kt @@ -0,0 +1,4 @@ +// "Remove EXPRESSION target" "true" +@Retention +@Target(AnnotationTarget.FIELD, AnnotationTarget.EXPRESSION, AnnotationTarget.PROPERTY) +annotation class Ann \ No newline at end of file diff --git a/idea/testData/quickfix/restrictedRetentionForExpressionAnnotation/removeExpressionTarget/multipleTargetsImported.kt.after b/idea/testData/quickfix/restrictedRetentionForExpressionAnnotation/removeExpressionTarget/multipleTargetsImported.kt.after new file mode 100644 index 00000000000..b6bc815e4d9 --- /dev/null +++ b/idea/testData/quickfix/restrictedRetentionForExpressionAnnotation/removeExpressionTarget/multipleTargetsImported.kt.after @@ -0,0 +1,4 @@ +// "Remove EXPRESSION target" "true" +@Retention +@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY) +annotation class Ann \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 79aa624baeb..3c6fc975882 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -10970,6 +10970,16 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { runTest("idea/testData/quickfix/restrictedRetentionForExpressionAnnotation/removeExpressionTarget/emptyRetention2.kt"); } + @TestMetadata("multipleTargets.kt") + public void testMultipleTargets() throws Exception { + runTest("idea/testData/quickfix/restrictedRetentionForExpressionAnnotation/removeExpressionTarget/multipleTargets.kt"); + } + + @TestMetadata("multipleTargetsImported.kt") + public void testMultipleTargetsImported() throws Exception { + runTest("idea/testData/quickfix/restrictedRetentionForExpressionAnnotation/removeExpressionTarget/multipleTargetsImported.kt"); + } + @TestMetadata("noRetention.kt") public void testNoRetention() throws Exception { runTest("idea/testData/quickfix/restrictedRetentionForExpressionAnnotation/removeExpressionTarget/noRetention.kt");