diff --git a/java/java-analysis-api/src/com/intellij/lang/jvm/actions/ChangeParametersRequest.java b/java/java-analysis-api/src/com/intellij/lang/jvm/actions/ChangeParametersRequest.java index b9aa1f295a64..9fe148310e05 100644 --- a/java/java-analysis-api/src/com/intellij/lang/jvm/actions/ChangeParametersRequest.java +++ b/java/java-analysis-api/src/com/intellij/lang/jvm/actions/ChangeParametersRequest.java @@ -1,9 +1,41 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.lang.jvm.actions; +import com.intellij.lang.jvm.JvmParameter; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.Collections; import java.util.List; public interface ChangeParametersRequest extends ActionRequest { List getExpectedParameters(); + + class ExistingParameterWrapper implements ExpectedParameter { + + private final JvmParameter myExistingParameter; + + public ExistingParameterWrapper(@NotNull JvmParameter existingParameter) { + myExistingParameter = existingParameter; + } + + @NotNull + @Override + public List getExpectedTypes() { + return Collections.singletonList(new SimpleExpectedType(myExistingParameter.getType(), ExpectedType.Kind.EXACT)); + } + + @NotNull + @Override + public Collection getSemanticNames() { + return Collections.singletonList(myExistingParameter.getName()); + } + + @NotNull + public JvmParameter getExistingParameter() { + return myExistingParameter; + } + } + } diff --git a/java/java-analysis-api/src/com/intellij/lang/jvm/actions/ExpectedParameter.java b/java/java-analysis-api/src/com/intellij/lang/jvm/actions/ExpectedParameter.java index 04468208110e..5066a2858b4e 100644 --- a/java/java-analysis-api/src/com/intellij/lang/jvm/actions/ExpectedParameter.java +++ b/java/java-analysis-api/src/com/intellij/lang/jvm/actions/ExpectedParameter.java @@ -21,4 +21,10 @@ public interface ExpectedParameter { default Collection getSemanticNames() { return Collections.emptyList(); } + + @NotNull + default Collection getExpectedAnnotations() { + return Collections.emptyList(); + } + } diff --git a/java/java-analysis-api/src/com/intellij/lang/jvm/actions/parameters.kt b/java/java-analysis-api/src/com/intellij/lang/jvm/actions/parameters.kt index d1ff775d0acc..4b09d982f36f 100644 --- a/java/java-analysis-api/src/com/intellij/lang/jvm/actions/parameters.kt +++ b/java/java-analysis-api/src/com/intellij/lang/jvm/actions/parameters.kt @@ -19,10 +19,16 @@ fun expectedParameter(types: List, names: Collection): Exp return SimpleExpectedParameter(types, names) } +fun expectedParameter(type: JvmType, name: String, annotations: Collection): ExpectedParameter { + return SimpleExpectedParameter(listOf(expectedType(type, ExpectedType.Kind.SUPERTYPE)), listOf(name), annotations) +} + private class SimpleExpectedParameter( private val types: List, - private val names: Collection + private val names: Collection, + private val annotations: Collection = emptyList() ) : ExpectedParameter { override fun getExpectedTypes() = types override fun getSemanticNames() = names + override fun getExpectedAnnotations() = annotations } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/lang/java/actions/ChangeMethodParameters.kt b/java/java-impl/src/com/intellij/lang/java/actions/ChangeMethodParameters.kt index 3877b0cefe9b..5a2f870c1385 100644 --- a/java/java-impl/src/com/intellij/lang/java/actions/ChangeMethodParameters.kt +++ b/java/java-impl/src/com/intellij/lang/java/actions/ChangeMethodParameters.kt @@ -3,6 +3,7 @@ package com.intellij.lang.java.actions import com.intellij.codeInsight.daemon.QuickFixBundle import com.intellij.lang.jvm.actions.ChangeParametersRequest +import com.intellij.lang.jvm.actions.ExpectedParameter import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project import com.intellij.openapi.util.text.StringUtil @@ -26,17 +27,46 @@ internal class ChangeMethodParameters(target: PsiMethod, override val request: C override fun getFamilyName(): String = QuickFixBundle.message("change.method.parameters.family") override fun invoke(project: Project, editor: Editor?, file: PsiFile?) { - target.parameterList.parameters.forEach(PsiParameter::delete) val factory = PsiElementFactory.SERVICE.getInstance(project) val helper = JvmPsiConversionHelper.getInstance(target.project) - for (expectedParameter in request.expectedParameters) { - val name = expectedParameter.semanticNames.first() - val psiType = helper.convertType(expectedParameter.expectedTypes.first().theType) - target.parameterList.add(factory.createParameter(name, psiType)) + tailrec fun updateParameters(currentParameters: List, expectedParameters: List) { + + val currentHead = currentParameters.firstOrNull() + val expectedHead = expectedParameters.firstOrNull() + + if (expectedHead == null) { + currentParameters.forEach(PsiParameter::delete) + return + } + + if (expectedHead is ChangeParametersRequest.ExistingParameterWrapper) { + if (expectedHead.existingParameter == currentHead) + return updateParameters(currentParameters.subList(1, currentParameters.size), + expectedParameters.subList(1, expectedParameters.size)) + else + throw UnsupportedOperationException("processing of existing params in different order is not implemented yet") + } + + val name = expectedHead.semanticNames.first() + val psiType = helper.convertType(expectedHead.expectedTypes.first().theType) + val newParameter = factory.createParameter(name, psiType) + + for (annotationRequest in expectedHead.expectedAnnotations) { + addAnnotationToModifierList(newParameter.modifierList!!, annotationRequest) + } + + if (currentHead == null) + target.parameterList.add(newParameter) + else + target.parameterList.addBefore(newParameter, currentHead) + + updateParameters(currentParameters, expectedParameters.subList(1, expectedParameters.size)) + } + updateParameters(target.parameterList.parameters.toList(), request.expectedParameters) } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/lang/java/actions/CreateAnnotationAction.kt b/java/java-impl/src/com/intellij/lang/java/actions/CreateAnnotationAction.kt index a5363530fe25..c44c91628011 100644 --- a/java/java-impl/src/com/intellij/lang/java/actions/CreateAnnotationAction.kt +++ b/java/java-impl/src/com/intellij/lang/java/actions/CreateAnnotationAction.kt @@ -11,6 +11,7 @@ import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.util.text.StringUtilRt import com.intellij.psi.PsiElementFactory import com.intellij.psi.PsiFile +import com.intellij.psi.PsiModifierList import com.intellij.psi.PsiModifierListOwner import com.intellij.psi.codeStyle.CodeStyleManager import com.intellij.psi.codeStyle.JavaCodeStyleManager @@ -28,28 +29,30 @@ internal class CreateAnnotationAction(target: PsiModifierListOwner, override val override fun invoke(project: Project, editor: Editor?, file: PsiFile?) { val modifierList = target.modifierList ?: return - val annotation = modifierList.addAnnotation(request.qualifiedName) - - val psiElementFactory = PsiElementFactory.SERVICE.getInstance(project) - - attributes@ for ((name, value) in request.attributes) { - val memberValue = when (value) { - is AnnotationAttributeValueRequest.PrimitiveValue -> psiElementFactory - .createExpressionFromText(value.value.toString(), null) - is AnnotationAttributeValueRequest.StringValue -> psiElementFactory - .createExpressionFromText("\"" + StringUtil.escapeStringCharacters(value.value) + "\"", null) - else -> { - LOG.error("adding annotation members of ${value.javaClass} type is not implemented"); continue@attributes - } - } - annotation.setDeclaredAttributeValue(name.takeIf { name != "value" }, memberValue) - } - - val formatter = CodeStyleManager.getInstance(project) - val codeStyleManager = JavaCodeStyleManager.getInstance(project) - codeStyleManager.shortenClassReferences(formatter.reformat(annotation)) - + addAnnotationToModifierList(modifierList, request) } } +internal fun addAnnotationToModifierList(modifierList: PsiModifierList, annotationRequest: AnnotationRequest) { + val project = modifierList.project + val annotation = modifierList.addAnnotation(annotationRequest.qualifiedName) + val psiElementFactory = PsiElementFactory.SERVICE.getInstance(project) + + attributes@ for ((name, value) in annotationRequest.attributes) { + val memberValue = when (value) { + is AnnotationAttributeValueRequest.PrimitiveValue -> psiElementFactory + .createExpressionFromText(value.value.toString(), null) + is AnnotationAttributeValueRequest.StringValue -> psiElementFactory + .createExpressionFromText("\"" + StringUtil.escapeStringCharacters(value.value) + "\"", null) + else -> { + LOG.error("adding annotation members of ${value.javaClass} type is not implemented"); continue@attributes + } + } + annotation.setDeclaredAttributeValue(name.takeIf { name != "value" }, memberValue) + } + + val formatter = CodeStyleManager.getInstance(project) + val codeStyleManager = JavaCodeStyleManager.getInstance(project) + codeStyleManager.shortenClassReferences(formatter.reformat(annotation)) +} \ No newline at end of file