diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index c9e13e9909a..8a2dc760437 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -312,6 +312,9 @@
+
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java
index 0d304958d26..81ed3c045ed 100644
--- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java
@@ -54,6 +54,7 @@ import org.jetbrains.kotlin.idea.core.refactoring.RefactoringPackage;
import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.*;
import org.jetbrains.kotlin.idea.references.JetSimpleNameReference;
import org.jetbrains.kotlin.idea.search.usagesSearch.UsagesSearchPackage;
+import org.jetbrains.kotlin.kdoc.psi.impl.KDocName;
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*;
@@ -73,7 +74,10 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.TypeUtils;
-import java.util.*;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsageProcessor {
@Override
@@ -172,11 +176,11 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
for (PsiReference reference : ReferencesSearch.search(oldParam, oldParam.getUseScope())) {
PsiElement element = reference.getElement();
- if (element instanceof JetSimpleNameExpression &&
+ if ((element instanceof JetSimpleNameExpression || element instanceof KDocName) &&
!(element.getParent() instanceof JetValueArgumentName)) // Usages in named arguments of the calls usage will be changed when the function call is changed
{
JetParameterUsage parameterUsage =
- new JetParameterUsage((JetSimpleNameExpression) element, parameterInfo, functionUsageInfo);
+ new JetParameterUsage((JetElement) element, parameterInfo, functionUsageInfo);
result.add(parameterUsage);
}
}
@@ -446,6 +450,8 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
String newExprText = ((JetParameterUsage) usageInfo).getReplacementText(changeInfo);
if (!newExprText.startsWith("this@")) continue;
+ if (usageInfo.getElement() instanceof KDocName) continue; // TODO support converting parameter to receiver in KDoc
+
JetExpression originalExpr = (JetExpression) usageInfo.getElement();
JetScope scope = ResolvePackage.analyze(originalExpr, BodyResolveMode.FULL)
.get(BindingContext.RESOLUTION_SCOPE, originalExpr);
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetMutableMethodDescriptor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetMutableMethodDescriptor.kt
index d489c882943..30529227ac2 100644
--- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetMutableMethodDescriptor.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetMutableMethodDescriptor.kt
@@ -37,6 +37,10 @@ public class JetMutableMethodDescriptor(val original: JetMethodDescriptor): JetM
parameters.remove(index)
}
+ public fun renameParameter(index: Int, newName: String) {
+ parameters[index].setName(newName)
+ }
+
public fun clearParameters() {
parameters.clear()
receiver = null
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetParameterUsage.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetParameterUsage.kt
index 8661ed8f788..cb98aea4bbb 100644
--- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetParameterUsage.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetParameterUsage.kt
@@ -43,10 +43,10 @@ public abstract class JetExplicitReferenceUsage(element: T) : Jet
}
public class JetParameterUsage(
- element: JetSimpleNameExpression,
+ element: JetElement,
private val parameterInfo: JetParameterInfo,
val containingFunction: JetFunctionDefinitionUsage<*>
-) : JetExplicitReferenceUsage(element) {
+) : JetExplicitReferenceUsage(element) {
override fun processReplacedElement(element: JetElement) {
val qualifiedExpression = element.getParent() as? JetQualifiedExpression
val elementToShorten = if (qualifiedExpression?.getReceiverExpression() == element) qualifiedExpression!! else element
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/RenameKotlinParameterProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/RenameKotlinParameterProcessor.kt
new file mode 100644
index 00000000000..97d401e9f8e
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/RenameKotlinParameterProcessor.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2010-2015 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.idea.refactoring.rename
+
+import com.intellij.psi.PsiElement
+import com.intellij.refactoring.listeners.RefactoringElementListener
+import com.intellij.usageView.UsageInfo
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
+import org.jetbrains.kotlin.idea.caches.resolve.analyze
+import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeSignatureConfiguration
+import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetMethodDescriptor
+import org.jetbrains.kotlin.idea.refactoring.changeSignature.modify
+import org.jetbrains.kotlin.idea.refactoring.changeSignature.runChangeSignature
+import org.jetbrains.kotlin.psi.JetNamedFunction
+import org.jetbrains.kotlin.psi.JetParameter
+import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
+import org.jetbrains.kotlin.resolve.BindingContext
+
+public class RenameKotlinParameterProcessor : RenameKotlinPsiProcessor() {
+ override fun canProcessElement(element: PsiElement): Boolean {
+ return element is JetParameter && element.getParent().getParent() is JetNamedFunction
+ }
+
+ override fun renameElement(element: PsiElement, newName: String, usages: Array, listener: RefactoringElementListener?) {
+ val function = (element as JetParameter).getParent().getParent() as JetNamedFunction
+ val paramIndex = function.getValueParameters().indexOf(element)
+ assert(paramIndex != -1, { "couldn't find parameter in parent ${element.getElementTextWithContext()}" })
+
+ val context = function.analyze()
+ val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, function] as? FunctionDescriptor ?: return
+
+ val changeSignatureConfiguration = object : JetChangeSignatureConfiguration {
+ override fun configure(originalDescriptor: JetMethodDescriptor, bindingContext: BindingContext): JetMethodDescriptor {
+ return originalDescriptor.modify { renameParameter(paramIndex, newName) }
+ }
+
+ override fun performSilently(affectedFunctions: Collection) = true
+ }
+
+ runChangeSignature(element.getProject(), descriptor, changeSignatureConfiguration, context, element, "Rename parameter")
+ }
+}
diff --git a/idea/testData/refactoring/rename/automaticRenamerParameter/after/JavaSub.java b/idea/testData/refactoring/rename/automaticRenamerParameter/after/JavaSub.java
new file mode 100644
index 00000000000..de19f2acd7b
--- /dev/null
+++ b/idea/testData/refactoring/rename/automaticRenamerParameter/after/JavaSub.java
@@ -0,0 +1,4 @@
+class JavaSub extends testing.Middle {
+ void foo(int aa, String b) {
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/refactoring/rename/automaticRenamerParameter/after/main.kt b/idea/testData/refactoring/rename/automaticRenamerParameter/after/main.kt
new file mode 100644
index 00000000000..d74c10cf373
--- /dev/null
+++ b/idea/testData/refactoring/rename/automaticRenamerParameter/after/main.kt
@@ -0,0 +1,21 @@
+package testing
+
+trait Trait {
+ open fun foo(aa: Int, b: String) {
+ }
+}
+
+open class Super {
+ open fun foo(aa: Int, b: String) {
+ }
+}
+
+open class Middle : Super(), Trait {
+ override fun foo(/*rename*/aa: Int, b: String) {
+ }
+}
+
+class Sub : Middle() {
+ override fun foo(aa: Int, b: String) {
+ }
+}
diff --git a/idea/testData/refactoring/rename/automaticRenamerParameter/before/JavaSub.java b/idea/testData/refactoring/rename/automaticRenamerParameter/before/JavaSub.java
new file mode 100644
index 00000000000..5d4de8e9d5d
--- /dev/null
+++ b/idea/testData/refactoring/rename/automaticRenamerParameter/before/JavaSub.java
@@ -0,0 +1,4 @@
+class JavaSub extends testing.Middle {
+ void foo(int a, String b) {
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/refactoring/rename/automaticRenamerParameter/before/main.kt b/idea/testData/refactoring/rename/automaticRenamerParameter/before/main.kt
new file mode 100644
index 00000000000..4bdaae4e277
--- /dev/null
+++ b/idea/testData/refactoring/rename/automaticRenamerParameter/before/main.kt
@@ -0,0 +1,21 @@
+package testing
+
+trait Trait {
+ open fun foo(a: Int, b: String) {
+ }
+}
+
+open class Super {
+ open fun foo(a: Int, b: String) {
+ }
+}
+
+open class Middle : Super(), Trait {
+ override fun foo(/*rename*/a: Int, b: String) {
+ }
+}
+
+class Sub : Middle() {
+ override fun foo(a: Int, b: String) {
+ }
+}
diff --git a/idea/testData/refactoring/rename/automaticRenamerParameter/parameter.test b/idea/testData/refactoring/rename/automaticRenamerParameter/parameter.test
new file mode 100644
index 00000000000..13a6d7a6494
--- /dev/null
+++ b/idea/testData/refactoring/rename/automaticRenamerParameter/parameter.test
@@ -0,0 +1,5 @@
+{
+ "type": "MARKED_ELEMENT",
+ "newName": "aa",
+ "mainFile": "main.kt"
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/kdoc/KdocRenameTest.java b/idea/tests/org/jetbrains/kotlin/idea/kdoc/KdocRenameTest.java
index 00f3363b1cb..a7f62c4e114 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/kdoc/KdocRenameTest.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/kdoc/KdocRenameTest.java
@@ -17,6 +17,8 @@
package org.jetbrains.kotlin.idea.kdoc;
import com.intellij.codeInsight.TargetElementUtilBase;
+import com.intellij.ide.startup.impl.StartupManagerImpl;
+import com.intellij.openapi.startup.StartupManager;
import com.intellij.psi.PsiElement;
import com.intellij.refactoring.rename.RenameProcessor;
import com.intellij.testFramework.LightCodeInsightTestCase;
@@ -38,6 +40,12 @@ public class KdocRenameTest extends LightCodeInsightTestCase {
doTest("xyzzy");
}
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ ((StartupManagerImpl) StartupManager.getInstance(getProject())).runPostStartupActivities();
+ }
+
private void doTest(String newName) throws Exception {
configureByFile(getTestName(false) + ".kt");
PsiElement element = TargetElementUtilBase
diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/rename/AbstractRenameTest.kt b/idea/tests/org/jetbrains/kotlin/idea/refactoring/rename/AbstractRenameTest.kt
index 0cf8396a1f3..6a53891063a 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/rename/AbstractRenameTest.kt
+++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/rename/AbstractRenameTest.kt
@@ -24,10 +24,9 @@ import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.util.text.StringUtil
+import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.vfs.VirtualFile
-import com.intellij.psi.JavaPsiFacade
-import com.intellij.psi.PsiDocumentManager
-import com.intellij.psi.PsiElement
+import com.intellij.psi.*
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.refactoring.BaseRefactoringProcessor.ConflictsInTestsException
import com.intellij.refactoring.rename.RenameProcessor
@@ -44,6 +43,9 @@ import org.jetbrains.kotlin.idea.test.KotlinMultiFileTestCase
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
import org.jetbrains.kotlin.name.*
import org.jetbrains.kotlin.psi.JetFile
+import org.jetbrains.kotlin.psi.JetNamedDeclaration
+import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
+import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.scopes.JetScope
import org.jetbrains.kotlin.serialization.deserialization.findClassAcrossModuleDependencies
@@ -57,6 +59,7 @@ private enum class RenameType {
KOTLIN_FUNCTION,
KOTLIN_PROPERTY,
KOTLIN_PACKAGE
+ MARKED_ELEMENT
}
public abstract class AbstractRenameTest : KotlinMultiFileTestCase() {
@@ -85,6 +88,7 @@ public abstract class AbstractRenameTest : KotlinMultiFileTestCase() {
RenameType.KOTLIN_FUNCTION -> renameKotlinFunctionTest(renameObject, context)
RenameType.KOTLIN_PROPERTY -> renameKotlinPropertyTest(renameObject, context)
RenameType.KOTLIN_PACKAGE -> renameKotlinPackageTest(renameObject, context)
+ RenameType.MARKED_ELEMENT -> renameMarkedElement(renameObject, context)
}
if (hintDirective != null) {
@@ -104,6 +108,25 @@ public abstract class AbstractRenameTest : KotlinMultiFileTestCase() {
}
}
+ private fun renameMarkedElement(renameParamsObject: JsonObject, context: TestContext) {
+ val mainFilePath = renameParamsObject.getString("mainFile")
+ val newName = renameParamsObject.getString("newName")
+
+ doTestCommittingDocuments { rootDir, rootAfter ->
+ val mainFile = rootDir.findChild(mainFilePath)!!
+ val psiFile = PsiManager.getInstance(context.project).findFile(mainFile)!!
+
+ val MARKER_TEXT = "/*rename*/"
+ val marker = psiFile.getText().indexOf(MARKER_TEXT)
+ assert(marker != -1)
+
+ val toRename = psiFile.findElementAt(marker + MARKER_TEXT.length())!!.getNonStrictParentOfType()!!
+ val substitution = RenamePsiElementProcessor.forElement(toRename).substituteElementToRename(toRename, null)
+
+ runRenameProcessor(context, newName, substitution, true, true)
+ }
+ }
+
private fun renameJavaClassTest(renameParamsObject: JsonObject, context: TestContext) {
val classFQN = renameParamsObject.getString("classId").toClassId().asSingleFqName().asString()
val newName = renameParamsObject.getString("newName")
diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/rename/RenameTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/rename/RenameTestGenerated.java
index 08a592326b9..314efadff37 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/rename/RenameTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/rename/RenameTestGenerated.java
@@ -71,6 +71,12 @@ public class RenameTestGenerated extends AbstractRenameTest {
doTest(fileName);
}
+ @TestMetadata("automaticRenamerParameter/parameter.test")
+ public void testAutomaticRenamerParameter_Parameter() throws Exception {
+ String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/rename/automaticRenamerParameter/parameter.test");
+ doTest(fileName);
+ }
+
@TestMetadata("defaultObject/defaultObject.test")
public void testDefaultObject_DefaultObject() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/rename/defaultObject/defaultObject.test");