From 1669b6aa9f980bbcc80c12c4221e3d54c9f9c834 Mon Sep 17 00:00:00 2001 From: Nicolay Mitropolsky Date: Tue, 19 Mar 2019 15:36:32 +0300 Subject: [PATCH] 192: KotlinElementActionsFactory: changing parameters could add annotations --- .../ChangeMethodParameters.kt.192 | 6 ++ .../KotlinElementActionsFactory.kt | 92 ++++++++++--------- ...ommonIntentionActionsParametersTest.kt.192 | 15 +-- 3 files changed, 66 insertions(+), 47 deletions(-) diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/crossLanguage/ChangeMethodParameters.kt.192 b/idea/src/org/jetbrains/kotlin/idea/quickfix/crossLanguage/ChangeMethodParameters.kt.192 index 6e7aa53fb4c..bc3f66720df 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/crossLanguage/ChangeMethodParameters.kt.192 +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/crossLanguage/ChangeMethodParameters.kt.192 @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.idea.quickfix.crossLanguage import com.intellij.codeInsight.daemon.QuickFixBundle +import com.intellij.lang.jvm.actions.AnnotationRequest import com.intellij.lang.jvm.actions.ChangeParametersRequest import com.intellij.lang.jvm.actions.ExpectedParameter import com.intellij.openapi.diagnostic.Logger @@ -65,6 +66,7 @@ internal class ChangeMethodParameters( data class Add( val name: String, val ktType: KotlinType, + val expectedAnnotations: Collection, val beforeAnchor: KtParameter? ) : ParameterModification() } @@ -115,6 +117,7 @@ internal class ChangeMethodParameters( collected + ParameterModification.Add( expectedHead.semanticNames.firstOrNull() ?: "param$index", kotlinType, + expectedHead.expectedAnnotations, currentParameters.firstOrNull { anchor -> expectedParameters.any { it is ChangeParametersRequest.ExistingParameterWrapper && it.existingKtParameter == anchor @@ -144,6 +147,9 @@ internal class ChangeMethodParameters( when (action) { is ParameterModification.Add -> { val parameter = parametersGenerated.getValue(action) + for (expectedAnnotation in action.expectedAnnotations) { + addAnnotationEntry(parameter, expectedAnnotation, null) + } val anchor = action.beforeAnchor if (anchor != null) { target.valueParameterList!!.addParameterBefore(parameter, anchor) diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/crossLanguage/KotlinElementActionsFactory.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/crossLanguage/KotlinElementActionsFactory.kt index e5d4cd5c4f0..dbf09308628 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/crossLanguage/KotlinElementActionsFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/crossLanguage/KotlinElementActionsFactory.kt @@ -437,57 +437,67 @@ class KotlinElementActionsFactory : JvmElementActionsFactory() { override fun invoke(project: Project, editor: Editor?, file: PsiFile?) { val target = pointer.element ?: return - val annotationClass = JavaPsiFacade.getInstance(project).findClass(request.qualifiedName, target.resolveScope) - - val kotlinAnnotation = annotationClass?.language == KotlinLanguage.INSTANCE - - val annotationUseSiteTargetPrefix = run prefixEvaluation@{ - if (annotationTarget == null) return@prefixEvaluation "" - - val moduleDescriptor = (target as? KtDeclaration)?.resolveToDescriptorIfAny()?.module ?: return@prefixEvaluation "" - val annotationClassDescriptor = moduleDescriptor.resolveClassByFqName( - FqName(request.qualifiedName), NoLookupLocation.FROM_IDE - ) ?: return@prefixEvaluation "" - - val applicableTargetSet = - AnnotationChecker.applicableTargetSet(annotationClassDescriptor) ?: KotlinTarget.DEFAULT_TARGET_SET - - if (KotlinTarget.PROPERTY !in applicableTargetSet) return@prefixEvaluation "" - - "${annotationTarget.renderName}:" - } - - val entry = target.addAnnotationEntry( - KtPsiFactory(target) - .createAnnotationEntry( - "@$annotationUseSiteTargetPrefix${request.qualifiedName}${ - request.attributes.mapIndexed { i, p -> - if (!kotlinAnnotation && i == 0 && p.name == "value") - renderAttributeValue(p.value).toString() - else - "${p.name} = ${renderAttributeValue(p.value)}" - }.joinToString(", ", "(", ")") - }" - ) - ) - + val entry = addAnnotationEntry(target, request, annotationTarget) ShortenReferences.DEFAULT.process(entry) } - private fun renderAttributeValue(annotationAttributeRequest: AnnotationAttributeValueRequest) = - when (annotationAttributeRequest) { - is AnnotationAttributeValueRequest.PrimitiveValue -> annotationAttributeRequest.value - is AnnotationAttributeValueRequest.StringValue -> "\"" + annotationAttributeRequest.value + "\"" - } - } override fun createChangeParametersActions(target: JvmMethod, request: ChangeParametersRequest): List { val ktNamedFunction = (target as? KtLightElement<*, *>)?.kotlinOrigin as? KtNamedFunction ?: return emptyList() - return listOfNotNull(ChangeMethodParameters.create(ktNamedFunction,request )) + return listOfNotNull(ChangeMethodParameters.create(ktNamedFunction, request)) } } +internal fun addAnnotationEntry( + target: KtModifierListOwner, + request: AnnotationRequest, + annotationTarget: AnnotationUseSiteTarget? +): KtAnnotationEntry { + val annotationClass = JavaPsiFacade.getInstance(target.project).findClass(request.qualifiedName, target.resolveScope) + + val kotlinAnnotation = annotationClass?.language == KotlinLanguage.INSTANCE + + val annotationUseSiteTargetPrefix = run prefixEvaluation@{ + if (annotationTarget == null) return@prefixEvaluation "" + + val moduleDescriptor = (target as? KtDeclaration)?.resolveToDescriptorIfAny()?.module ?: return@prefixEvaluation "" + val annotationClassDescriptor = moduleDescriptor.resolveClassByFqName( + FqName(request.qualifiedName), NoLookupLocation.FROM_IDE + ) ?: return@prefixEvaluation "" + + val applicableTargetSet = + AnnotationChecker.applicableTargetSet(annotationClassDescriptor) ?: KotlinTarget.DEFAULT_TARGET_SET + + if (KotlinTarget.PROPERTY !in applicableTargetSet) return@prefixEvaluation "" + + "${annotationTarget.renderName}:" + } + + // could be generated via descriptor when KT-30478 is fixed + val entry = target.addAnnotationEntry( + KtPsiFactory(target) + .createAnnotationEntry( + "@$annotationUseSiteTargetPrefix${request.qualifiedName}${ + request.attributes.mapIndexed { i, p -> + if (!kotlinAnnotation && i == 0 && p.name == "value") + renderAttributeValue(p.value).toString() + else + "${p.name} = ${renderAttributeValue(p.value)}" + }.joinToString(", ", "(", ")") + }" + ) + ) + return entry +} + +private fun renderAttributeValue(annotationAttributeRequest: AnnotationAttributeValueRequest) = + when (annotationAttributeRequest) { + is AnnotationAttributeValueRequest.PrimitiveValue -> annotationAttributeRequest.value + is AnnotationAttributeValueRequest.StringValue -> "\"" + annotationAttributeRequest.value + "\"" + } + + private fun PsiType.collectTypeParameters(): List { val results = ArrayList() accept( diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/CommonIntentionActionsParametersTest.kt.192 b/idea/tests/org/jetbrains/kotlin/idea/quickfix/CommonIntentionActionsParametersTest.kt.192 index f8c0c52cf65..55a2283c2da 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/CommonIntentionActionsParametersTest.kt.192 +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/CommonIntentionActionsParametersTest.kt.192 @@ -67,7 +67,8 @@ class CommonIntentionActionsParametersTest : LightPlatformCodeInsightFixtureTest runParametersTransformation("Change method parameters to '(a: Int, file: File)'") { currentParameters -> currentParameters + expectedParameter( - PsiType.getTypeByName("java.io.File", project, myFixture.file.resolveScope), "file" + PsiType.getTypeByName("java.io.File", project, myFixture.file.resolveScope), "file", + listOf(annotationRequest("Anno", intAttribute("i", 8))) ) } @@ -76,7 +77,7 @@ class CommonIntentionActionsParametersTest : LightPlatformCodeInsightFixtureTest import java.io.File class Foo { - fun bar(@Anno(3) a: Int, file: File) {} + fun bar(@Anno(3) a: Int, @Anno(i = 8) file: File) {} } """.trimIndent(), true ) @@ -96,7 +97,8 @@ class CommonIntentionActionsParametersTest : LightPlatformCodeInsightFixtureTest runParametersTransformation("Change method parameters to '(file: File, a: Int)'") { currentParameters -> listOf( expectedParameter( - PsiType.getTypeByName("java.io.File", project, myFixture.file.resolveScope), "file" + PsiType.getTypeByName("java.io.File", project, myFixture.file.resolveScope), "file", + listOf(annotationRequest("Anno", intAttribute("i", 8))) ) ) + currentParameters } @@ -106,7 +108,7 @@ class CommonIntentionActionsParametersTest : LightPlatformCodeInsightFixtureTest import java.io.File class Foo { - fun bar(file: File, @Anno(3) a: Int) {} + fun bar(@Anno(i = 8) file: File, @Anno(3) a: Int) {} } """.trimIndent(), true ) @@ -125,7 +127,8 @@ class CommonIntentionActionsParametersTest : LightPlatformCodeInsightFixtureTest runParametersTransformation("Change method parameters to '(a: Int, file: File, c: Int)'") { currentParameters -> ArrayList(currentParameters).apply { this[1] = expectedParameter( - PsiType.getTypeByName("java.io.File", project, myFixture.file.resolveScope), "file" + PsiType.getTypeByName("java.io.File", project, myFixture.file.resolveScope), "file", + listOf(annotationRequest("Anno", intAttribute("i", 8))) ) } } @@ -135,7 +138,7 @@ class CommonIntentionActionsParametersTest : LightPlatformCodeInsightFixtureTest import java.io.File class Foo { - fun bar(@Anno(1) a: Int, file: File, @Anno(3) c: Int) {} + fun bar(@Anno(1) a: Int, @Anno(i = 8) file: File, @Anno(3) c: Int) {} } """.trimIndent(), true )