[jvm + devKit] Add action to change annotation attribute and use it in MismatchedLightServiceLevelAndCtorInspection

IJ-CR-102194

GitOrigin-RevId: bdef6309bfcaf710db8bdcc773ac43757856e8f1
This commit is contained in:
Andrey Cherkasov
2023-03-13 12:53:51 +00:00
committed by intellij-monorepo-bot
parent adf527e2e0
commit 8e56c5dcf2
20 changed files with 203 additions and 55 deletions
@@ -2,10 +2,7 @@
package com.intellij.lang.jvm.actions
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.lang.jvm.JvmClass
import com.intellij.lang.jvm.JvmMethod
import com.intellij.lang.jvm.JvmModifiersOwner
import com.intellij.lang.jvm.JvmParameter
import com.intellij.lang.jvm.*
/**
* This extension point provides language-abstracted code modifications for JVM-based languages.
@@ -24,6 +21,10 @@ abstract class JvmElementActionsFactory {
open fun createAddAnnotationActions(target: JvmModifiersOwner, request: AnnotationRequest): List<IntentionAction> = emptyList()
open fun createChangeAnnotationAttributeActions(annotation: JvmAnnotation,
attributeIndex: Int,
request: AnnotationAttributeRequest): List<IntentionAction> = emptyList()
open fun createAddFieldActions(targetClass: JvmClass, request: CreateFieldRequest): List<IntentionAction> = emptyList()
open fun createAddMethodActions(targetClass: JvmClass, request: CreateMethodRequest): List<IntentionAction> = emptyList()
@@ -4,10 +4,7 @@
package com.intellij.lang.jvm.actions
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.lang.jvm.JvmClass
import com.intellij.lang.jvm.JvmMethod
import com.intellij.lang.jvm.JvmModifiersOwner
import com.intellij.lang.jvm.JvmParameter
import com.intellij.lang.jvm.*
import com.intellij.openapi.extensions.ExtensionPointName
val EP_NAME: ExtensionPointName<JvmElementActionsFactory> = ExtensionPointName.create(
@@ -38,6 +35,14 @@ fun createAddAnnotationActions(target: JvmModifiersOwner, request: AnnotationReq
}
}
fun createChangeAnnotationAttributeActions(annotation: JvmAnnotation,
attributeIndex: Int,
request: AnnotationAttributeRequest): List<IntentionAction> {
return createActions {
it.createChangeAnnotationAttributeActions(annotation, attributeIndex, request)
}
}
fun createModifierActions(target: JvmModifiersOwner, request: ChangeModifierRequest): List<IntentionAction> {
return createActions {
it.createChangeModifierActions(target, request)
@@ -35,6 +35,9 @@ import org.jetbrains.annotations.Nullable;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
import static com.intellij.codeInsight.AnnotationUtil.CHECK_EXTERNAL;
import static com.intellij.codeInsight.AnnotationUtil.CHECK_TYPE;
public class AddAnnotationPsiFix extends LocalQuickFixOnPsiElement implements LocalQuickFix {
protected final String myAnnotation;
final String[] myAnnotationsToRemove;
@@ -166,7 +169,8 @@ public class AddAnnotationPsiFix extends LocalQuickFixOnPsiElement implements Lo
PsiModifierList modifierList = modifierListOwner.getModifierList();
return modifierList != null
&& !(modifierList instanceof LightElement)
&& !(modifierListOwner instanceof LightElement);
&& !(modifierListOwner instanceof LightElement)
&& !AnnotationUtil.isAnnotated(modifierListOwner, annotationFQN, CHECK_EXTERNAL | CHECK_TYPE);
}
@Override
@@ -448,4 +448,7 @@ qualify.method.call.fix=Qualify the call with ''{0}''
qualify.method.call.family=Qualify method call
remove.redundant.nested.patterns.fix.text=Remove redundant nested pattern{0, choice, 1#|2#s}
add.missing.nested.patterns.fix.text=Add missing nested pattern{0, choice, 1#|2#s}
add.missing.nested.patterns.fix.text=Add missing nested pattern{0, choice, 1#|2#s}
change.annotation.attribute.value.family=Change annotation attribute
change.annotation.attribute.value.text=Change ''{0}'' annotation attribute
@@ -85,6 +85,14 @@ class JavaElementActionsFactory : JvmElementActionsFactory() {
return listOf(CreateAnnotationAction(declaration, request))
}
override fun createChangeAnnotationAttributeActions(annotation: JvmAnnotation,
attributeIndex: Int,
request: AnnotationAttributeRequest): List<IntentionAction> {
val psiAnnotation = annotation as? PsiAnnotation ?: return emptyList()
if (psiAnnotation.language != JavaLanguage.INSTANCE) return emptyList()
return listOf(ChangeAnnotationAttributeAction(psiAnnotation, request))
}
override fun createAddFieldActions(targetClass: JvmClass, request: CreateFieldRequest): List<IntentionAction> {
val javaClass = targetClass.toJavaClassOrNull() ?: return emptyList()
@@ -0,0 +1,40 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.lang.java.actions
import com.intellij.codeInsight.daemon.QuickFixBundle
import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo
import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement
import com.intellij.lang.jvm.actions.AnnotationAttributeRequest
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiAnnotation
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementFactory
import com.intellij.psi.PsiFile
import com.intellij.psi.util.PsiTreeUtil
internal class ChangeAnnotationAttributeAction(annotation: PsiAnnotation, val request: AnnotationAttributeRequest) :
LocalQuickFixAndIntentionActionOnPsiElement(annotation) {
override fun startInWriteAction(): Boolean = true
override fun getFamilyName(): String = QuickFixBundle.message("change.annotation.attribute.value.family")
override fun getText(): String = QuickFixBundle.message("change.annotation.attribute.value.text", request.name)
override fun generatePreview(project: Project, editor: Editor, file: PsiFile): IntentionPreviewInfo {
val copy = PsiTreeUtil.findSameElementInCopy(startElement as PsiAnnotation, file)
invokeImpl(copy, project)
return IntentionPreviewInfo.DIFF
}
override fun invoke(project: Project, file: PsiFile, editor: Editor?, startElement: PsiElement, endElement: PsiElement) {
invokeImpl(startElement as PsiAnnotation, project)
}
private fun invokeImpl(annotation: PsiAnnotation, project: Project) {
val factory = PsiElementFactory.getInstance(project)
val value = CreateAnnotationAction.attributeRequestToValue(request.value, factory, null)
annotation.setDeclaredAttributeValue(request.name, value)
}
}
@@ -69,15 +69,14 @@ internal class CreateAnnotationAction(target: PsiModifierListOwner, override val
psiElementFactory: PsiElementFactory,
context: PsiElement?) {
for ((name, value) in annotationRequest.attributes) {
val memberValue = attributeRequestToValue(value, psiElementFactory, context, annotationRequest)
annotation.setDeclaredAttributeValue(name.takeIf { name != "value" }, memberValue)
val memberValue = attributeRequestToValue(value, psiElementFactory, context)
annotation.setDeclaredAttributeValue(name.takeIf { name != PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME }, memberValue)
}
}
private fun attributeRequestToValue(value: AnnotationAttributeValueRequest,
psiElementFactory: PsiElementFactory,
context: PsiElement?,
annotationRequest: AnnotationRequest): PsiAnnotationMemberValue? = when (value) {
internal fun attributeRequestToValue(value: AnnotationAttributeValueRequest,
psiElementFactory: PsiElementFactory,
context: PsiElement?): PsiAnnotationMemberValue? = when (value) {
is AnnotationAttributeValueRequest.PrimitiveValue -> psiElementFactory
.createExpressionFromText(value.value.toString(), null)
is AnnotationAttributeValueRequest.StringValue -> psiElementFactory
@@ -92,7 +91,7 @@ internal class CreateAnnotationAction(target: PsiModifierListOwner, override val
}
is AnnotationAttributeValueRequest.ArrayValue -> {
val arrayExpressionText = value.members.joinToString {
attributeRequestToValue(it, psiElementFactory, context, annotationRequest)?.text ?: ""
attributeRequestToValue(it, psiElementFactory, context)?.text ?: ""
}
val dummyAnnotation = psiElementFactory.createAnnotationFromText("@dummy({$arrayExpressionText})", context)
dummyAnnotation.findAttributeValue(null)
@@ -9,6 +9,7 @@ import com.intellij.lang.jvm.annotation.JvmAnnotationConstantValue
import com.intellij.lang.jvm.annotation.JvmAnnotationEnumFieldValue
import com.intellij.openapi.components.Service
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiAnnotation
import com.intellij.psi.PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME
import com.intellij.psi.PsiElementFactory
import com.intellij.psi.PsiFile
@@ -27,17 +28,20 @@ internal class MismatchedLightServiceLevelAndCtorInspection : DevKitJvmInspectio
if (!method.isConstructor) return true
val file: PsiFile = method.sourceElement?.containingFile ?: return true
val containingClass = method.containingClass ?: return true
val serviceAnnotation = containingClass.annotations.find { it.qualifiedName == Service::class.java.canonicalName } ?: return true
val level = getLevel(serviceAnnotation)
if (level !in listOf(Level.PROJECT, Level.APP_AND_PROJECT)) {
val annotation = containingClass.annotations.find { it.qualifiedName == Service::class.java.canonicalName } ?: return true
val annotationName = (annotation as? PsiAnnotation)?.nameReferenceElement
val level = getLevel(annotation)
if (annotationName != null && level !in listOf(Level.PROJECT, Level.APP_AND_PROJECT)) {
val isProjectParamCtor = (method.parameters.singleOrNull()?.type as? PsiType)?.canonicalText == Project::class.java.canonicalName
if (isProjectParamCtor) {
val projectLevelFqn = "${Service.Level::class.java.canonicalName}.${Service.Level.PROJECT}"
val request = annotationRequest(Service::class.java.canonicalName,
constantAttribute(DEFAULT_REFERENCED_METHOD_NAME, projectLevelFqn))
val actions = createAddAnnotationActions(containingClass, request)
val request = constantAttribute(DEFAULT_REFERENCED_METHOD_NAME, projectLevelFqn)
val actions = createChangeAnnotationAttributeActions(annotation, 0, request)
val fixes = IntentionWrapper.wrapToQuickFixes(actions.toTypedArray(), file)
sink.highlight(DevKitBundle.message("inspection.mismatched.light.service.level.and.ctor.project.level.required"), *fixes)
val holder = (sink as HighlightSinkImpl).holder
holder.registerProblem(annotationName,
DevKitBundle.message("inspection.mismatched.light.service.level.and.ctor.project.level.required"),
*fixes)
}
}
if (level == Level.APP || level == Level.APP_AND_PROJECT) {
@@ -1,7 +1,7 @@
import com.intellij.openapi.components.Service;
import com.intellij.openapi.project.Project;
@Service(Service.Level.APP)
@<warning descr="If constructor takes Project, Service.Level.PROJECT is required">Service</warning>(Service.Level.APP)
final class MyService {
private <warning descr="Application level service requires no-arg constructor or constructor taking Coroutine"><warning descr="If constructor takes Project, Service.Level.PROJECT is required">MyService<caret></warning></warning>(Project project) {}
private <warning descr="Application level service requires no-arg constructor or constructor taking Coroutine">MyService<caret></warning>(Project project) {}
}
@@ -1,11 +1,11 @@
import com.intellij.openapi.components.Service;
import com.intellij.openapi.project.Project;
@Service
@<warning descr="If constructor takes Project, Service.Level.PROJECT is required">Service<caret></warning>
final class MyService {
private final Project myProject;
public <warning descr="If constructor takes Project, Service.Level.PROJECT is required">MyService<caret></warning>(Project project) {
public MyService(Project project) {
myProject = project;
}
}
@@ -1,11 +1,11 @@
import com.intellij.openapi.components.Service;
import com.intellij.openapi.project.Project;
@Service({})
@<warning descr="If constructor takes Project, Service.Level.PROJECT is required">Service<caret></warning>({})
final class MyService {
private final Project myProject;
public <warning descr="If constructor takes Project, Service.Level.PROJECT is required">MyService<caret></warning>(Project project) {
public MyService(Project project) {
myProject = project;
}
}
@@ -1,7 +1,7 @@
import com.intellij.openapi.components.Service;
import com.intellij.openapi.project.Project;
@Service(Service.Level.APP)
@<warning descr="If constructor takes Project, Service.Level.PROJECT is required">Service</warning>(Service.Level.APP)
final class MyService {
private <warning descr="Application level service requires no-arg constructor or constructor taking Coroutine"><warning descr="If constructor takes Project, Service.Level.PROJECT is required">MyService<caret></warning></warning>(Project project) {}
private <warning descr="Application level service requires no-arg constructor or constructor taking Coroutine">MyService<caret></warning>(Project project) {}
}
@@ -1,6 +1,7 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.idea.devkit.inspections
import com.intellij.codeInsight.daemon.QuickFixBundle
import com.intellij.testFramework.TestDataPath
import org.jetbrains.idea.devkit.DevkitJavaTestsUtil
import org.jetbrains.idea.devkit.inspections.quickfix.MismatchedLightServiceLevelAndCtorInspectionTestBase
@@ -8,25 +9,26 @@ import org.jetbrains.idea.devkit.inspections.quickfix.MismatchedLightServiceLeve
@TestDataPath("\$CONTENT_ROOT/testData/inspections/mismatchedLightServiceLevelAndCtor")
class MismatchedLightServiceLevelAndCtorInspectionTest : MismatchedLightServiceLevelAndCtorInspectionTestBase() {
private val ANNOTATE_AS_SERVICE_FIX_NAME = "Annotate class 'MyService' as '@Service'"
private val NO_ARG_CTOR_FIX_NAME = QuickFixBundle.message("change.method.parameters.text", "()")
private val COROUTINE_SCOPE_PARAM_CTOR_FIX_NAME = QuickFixBundle.message("change.method.parameters.text", "(CoroutineScope scope)")
override fun getBasePath() = DevkitJavaTestsUtil.TESTDATA_PATH + "inspections/mismatchedLightServiceLevelAndCtor/"
override fun getFileExtension() = "java"
fun testMakeProjectLevel1() {
doTest(ANNOTATE_AS_SERVICE_FIX_NAME)
doTest(annotateAsServiceFixName)
}
fun testMakeProjectLevel2() {
doTest(ANNOTATE_AS_SERVICE_FIX_NAME)
doTest(annotateAsServiceFixName)
}
fun testRemoveProjectParam() {
doTest("Change method parameters to '()'")
doTest(NO_ARG_CTOR_FIX_NAME)
}
fun testChangeParamToCoroutineScope() {
doTest("Change method parameters to '(CoroutineScope scope)'")
doTest(COROUTINE_SCOPE_PARAM_CTOR_FIX_NAME)
}
}
@@ -1,5 +1,5 @@
import com.intellij.openapi.components.Service
import com.intellij.openapi.project.Project
@Service(Service.Level.APP)
class <warning descr="Application level service requires no-arg constructor or constructor taking Coroutine"><warning descr="If constructor takes Project, Service.Level.PROJECT is required">MyService<caret></warning></warning>(val project: Project)
<warning descr="If constructor takes Project, Service.Level.PROJECT is required">@Service(Service.Level.APP)</warning>
class <warning descr="Application level service requires no-arg constructor or constructor taking Coroutine">MyService<caret></warning>(val project: Project)
@@ -1,5 +1,5 @@
import com.intellij.openapi.components.Service
import com.intellij.openapi.project.Project
@Service
class <warning descr="If constructor takes Project, Service.Level.PROJECT is required">MyService<caret></warning>(val project: Project)
<warning descr="If constructor takes Project, Service.Level.PROJECT is required">@Service<caret></warning>
class MyService(val project: Project)
@@ -1,5 +1,5 @@
import com.intellij.openapi.components.Service
import com.intellij.openapi.project.Project
@Service(*[])
class <warning descr="If constructor takes Project, Service.Level.PROJECT is required">MyService<caret></warning>(val project: Project)
<warning descr="If constructor takes Project, Service.Level.PROJECT is required">@Service<caret>(*[])</warning>
class MyService(val project: Project)
@@ -1,5 +1,5 @@
import com.intellij.openapi.components.Service
import com.intellij.openapi.project.Project
@Service(Service.Level.APP)
class <warning descr="Application level service requires no-arg constructor or constructor taking Coroutine"><warning descr="If constructor takes Project, Service.Level.PROJECT is required">MyService<caret></warning></warning>(val project: Project)
<warning descr="If constructor takes Project, Service.Level.PROJECT is required">@Service(Service.Level.APP)</warning>
class <warning descr="Application level service requires no-arg constructor or constructor taking Coroutine">MyService<caret></warning>(val project: Project)
@@ -1,7 +1,10 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.idea.devkit.kotlin.inspections
import com.intellij.codeInsight.daemon.QuickFixBundle
import com.intellij.openapi.project.Project
import com.intellij.testFramework.TestDataPath
import kotlinx.coroutines.CoroutineScope
import org.jetbrains.idea.devkit.inspections.quickfix.MismatchedLightServiceLevelAndCtorInspectionTestBase
import org.jetbrains.idea.devkit.kotlin.DevkitKtTestsUtil
@@ -13,18 +16,20 @@ class KtMismatchedLightServiceLevelAndCtorInspectionTest : MismatchedLightServic
override fun getFileExtension() = "kt"
fun testMakeProjectLevel1() {
doTest("Annotate as @Service")
doTest(annotateAsServiceFixName)
}
fun testMakeProjectLevel2() {
doTest("Annotate as @Service")
doTest(annotateAsServiceFixName)
}
fun testRemoveProjectParam() {
doTest("Remove 1st parameter from constructor 'MyService'")
doTest(QuickFixBundle.message("remove.parameter.from.usage.text", 1, "parameter", "constructor", "MyService"))
}
fun testChangeParamToCoroutineScope() {
doTest("Change 1st parameter of constructor 'MyService' from 'Project' to 'CoroutineScope'")
doTest(
QuickFixBundle.message("change.parameter.from.usage.text", 1, "parameter", "constructor", "MyService", Project::class.java.simpleName,
CoroutineScope::class.java.simpleName))
}
}
@@ -1,10 +1,15 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.idea.devkit.inspections.quickfix
import com.intellij.codeInsight.daemon.QuickFixBundle
import com.intellij.psi.PsiAnnotation
import org.jetbrains.idea.devkit.inspections.MismatchedLightServiceLevelAndCtorInspection
abstract class MismatchedLightServiceLevelAndCtorInspectionTestBase : LightDevKitInspectionFixTestBase() {
protected val annotateAsServiceFixName = QuickFixBundle.message("change.annotation.attribute.value.text",
PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME)
override fun setUp() {
super.setUp()
myFixture.enableInspections(MismatchedLightServiceLevelAndCtorInspection())
@@ -21,6 +21,7 @@ import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.asJava.toLightAnnotation
import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.descriptors.CallableDescriptor
@@ -40,7 +41,6 @@ import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeIn
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.CommentSaver
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.findAnnotation
import org.jetbrains.kotlin.idea.util.resolveToKotlinType
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
@@ -416,6 +416,82 @@ class KotlinElementActionsFactory : JvmElementActionsFactory() {
}
}
override fun createChangeAnnotationAttributeActions(annotation: JvmAnnotation,
attributeIndex: Int,
request: AnnotationAttributeRequest): List<IntentionAction> {
val annotationEntry = annotation.safeAs<KtLightElement<*, *>>()?.kotlinOrigin.safeAs<KtAnnotationEntry>().takeIf {
it?.language == KotlinLanguage.INSTANCE
} ?: return emptyList()
return listOf(ChangeAnnotationAction(annotationEntry, attributeIndex, request))
}
private class ChangeAnnotationAction(annotationEntry: KtAnnotationEntry,
private val attributeIndex: Int,
private val request: AnnotationAttributeRequest) : IntentionAction {
private val pointer: SmartPsiElementPointer<KtAnnotationEntry>
private val qualifiedName: String
override fun startInWriteAction(): Boolean = true
override fun getFamilyName(): String = QuickFixBundle.message("change.annotation.attribute.value.family")
override fun getText(): String = QuickFixBundle.message("change.annotation.attribute.value.text", request.name)
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile?): Boolean = pointer.element != null
override fun generatePreview(project: Project, editor: Editor, file: PsiFile): IntentionPreviewInfo {
invokeImpl(PsiTreeUtil.findSameElementInCopy(pointer.element, file), project)
return IntentionPreviewInfo.DIFF
}
override fun invoke(project: Project, editor: Editor?, file: PsiFile) {
val annotationEntry = pointer.element ?: return
invokeImpl(annotationEntry, project)
}
private fun invokeImpl(annotationEntry: KtAnnotationEntry, project: Project) {
val facade = JavaPsiFacade.getInstance(annotationEntry.project)
val isKotlinAnnotation = facade.findClass(qualifiedName, annotationEntry.resolveScope)?.language == KotlinLanguage.INSTANCE
val dummyAnnotationRequest = annotationRequest(qualifiedName, request)
val psiFactory = KtPsiFactory(project)
val annotationText = '@' + renderAnnotation(dummyAnnotationRequest, psiFactory) { isKotlinAnnotation }
val dummyArgumentList = psiFactory.createAnnotationEntry(annotationText).valueArgumentList!!
val argumentList = annotationEntry.valueArgumentList
if (argumentList == null) {
annotationEntry.add(dummyArgumentList)
}
else {
val dummyArgument = dummyArgumentList.arguments[0]
val attribute = findAttribute(annotationEntry, request.name, attributeIndex)
if (attribute != null) {
argumentList.addArgumentBefore(dummyArgument, attribute.value)
argumentList.removeArgument(attribute.index + 1)
}
else {
argumentList.addArgument(dummyArgument)
}
}
ShortenReferences.DEFAULT.process(annotationEntry)
}
private fun findAttribute(annotationEntry: KtAnnotationEntry, name: String, index: Int): IndexedValue<KtValueArgument>? {
val arguments = annotationEntry.valueArgumentList?.arguments ?: return null
arguments.withIndex().find { (_, argument) ->
argument.getArgumentName()?.asName?.identifier == name
}?.let {
return it
}
val valueArgument = arguments.getOrNull(index) ?: return null
return IndexedValue(index, valueArgument)
}
init {
pointer = annotationEntry.createSmartPointer()
qualifiedName = annotationEntry.toLightAnnotation()?.qualifiedName ?: throw IllegalStateException("r")
}
}
override fun createChangeParametersActions(target: JvmMethod, request: ChangeParametersRequest): List<IntentionAction> {
return when (val kotlinOrigin = (target as? KtLightElement<*, *>)?.kotlinOrigin) {
is KtNamedFunction -> listOfNotNull(ChangeMethodParameters.create(kotlinOrigin, request))
@@ -554,11 +630,7 @@ internal fun addAnnotationEntry(
val psiFactory = KtPsiFactory(target.project)
// could be generated via descriptor when KT-30478 is fixed
val annotationText = '@' + annotationUseSiteTargetPrefix + renderAnnotation(target, request, psiFactory)
val annotationEntry = psiFactory.createAnnotationEntry(annotationText)
target.findAnnotation(FqName(request.qualifiedName))?.let {
return it.replace(annotationEntry) as KtAnnotationEntry
}
return target.addAnnotationEntry(annotationEntry)
return target.addAnnotationEntry(psiFactory.createAnnotationEntry(annotationText))
}
private fun renderAnnotation(target: PsiElement, request: AnnotationRequest, psiFactory: KtPsiFactory): String {