From 8c95884ad2c522e46b0656e9e8dd3d8212eb4ef2 Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Mon, 7 Oct 2013 20:49:44 +0400 Subject: [PATCH] Add new functionality to "Change signature" refactoring Extract single point of entry for all change signature refactorings and fixes (remove parameter, add parameter) Change signature now affects overriding functions as well Ask the user whether he wants to refactor base function(s) or the selected one if appropiate Fix a problem with descriptorToDeclaration in JetChangeSignatureHandler Rename: JetFunctionPlatformDescriptor -> JetMethodDescriptor --- .../jet/lang/resolve/BindingContextUtils.java | 31 +++ .../quickfix/AddFunctionParametersFix.java | 75 +++--- .../ChangeFunctionLiteralSignatureFix.java | 31 ++- .../quickfix/ChangeFunctionSignatureFix.java | 112 ++++----- .../quickfix/RemoveFunctionParametersFix.java | 21 +- .../changeSignature/JetChangeInfo.java | 12 +- .../changeSignature/JetChangeSignature.kt | 206 +++++++++++++++++ .../JetChangeSignatureData.java | 213 ++++++++++++++++++ .../JetChangeSignatureDialog.java | 16 +- .../JetChangeSignatureHandler.java | 138 ++++++++---- .../JetChangeSignatureUsageProcessor.java | 9 +- .../JetFunctionPlatformDescriptorImpl.java | 140 ------------ ...scriptor.java => JetMethodDescriptor.java} | 7 +- .../changeSignature/JetParameterInfo.java | 4 +- .../changeSignature/afterComplexHierarchy.kt | 65 ++++++ .../afterComplexHierarchyHead.kt | 58 +++++ .../afterComplexHierarchyTail.kt | 65 ++++++ .../changeSignature/afterLinearHierarchy.kt | 28 +++ .../changeSignature/beforeComplexHierarchy.kt | 58 +++++ .../beforeComplexHierarchyHead.kt | 58 +++++ .../beforeComplexHierarchyTail.kt | 58 +++++ .../changeSignature/beforeLinearHierarchy.kt | 25 ++ .../changeSignature/FakeOverrideAfter.kt | 15 ++ .../changeSignature/FakeOverrideBefore.kt | 15 ++ .../PreferContainedInClassBefore.kt | 11 + .../quickfix/QuickFixTestGenerated.java | 20 ++ .../JetChangeSignatureTest.java | 30 ++- 27 files changed, 1198 insertions(+), 323 deletions(-) create mode 100644 idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignature.kt create mode 100644 idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureData.java delete mode 100644 idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetFunctionPlatformDescriptorImpl.java rename idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/{JetFunctionPlatformDescriptor.java => JetMethodDescriptor.java} (85%) create mode 100644 idea/testData/quickfix/changeSignature/afterComplexHierarchy.kt create mode 100644 idea/testData/quickfix/changeSignature/afterComplexHierarchyHead.kt create mode 100644 idea/testData/quickfix/changeSignature/afterComplexHierarchyTail.kt create mode 100644 idea/testData/quickfix/changeSignature/afterLinearHierarchy.kt create mode 100644 idea/testData/quickfix/changeSignature/beforeComplexHierarchy.kt create mode 100644 idea/testData/quickfix/changeSignature/beforeComplexHierarchyHead.kt create mode 100644 idea/testData/quickfix/changeSignature/beforeComplexHierarchyTail.kt create mode 100644 idea/testData/quickfix/changeSignature/beforeLinearHierarchy.kt create mode 100644 idea/testData/refactoring/changeSignature/FakeOverrideAfter.kt create mode 100644 idea/testData/refactoring/changeSignature/FakeOverrideBefore.kt create mode 100644 idea/testData/refactoring/changeSignature/PreferContainedInClassBefore.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java index 448c22e447b..3cbc5eb985f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java @@ -357,4 +357,35 @@ public class BindingContextUtils { } return OverridingUtil.filterOutOverridden(result); } + + @NotNull + public static Set getDirectlyOverriddenDeclarations(@NotNull FunctionDescriptor descriptor) { + //noinspection unchecked + return (Set) getDirectlyOverriddenDeclarations((CallableMemberDescriptor) descriptor); + } + + @NotNull + public static Set getDirectlyOverriddenDeclarations(@NotNull PropertyDescriptor descriptor) { + //noinspection unchecked + return (Set) getDirectlyOverriddenDeclarations((CallableMemberDescriptor) descriptor); + } + + @NotNull + public static Set getAllOverriddenDeclarations(@NotNull FunctionDescriptor functionDescriptor) { + Set result = Sets.newHashSet(); + for (FunctionDescriptor overriddenDeclaration : functionDescriptor.getOverriddenDescriptors()) { + CallableMemberDescriptor.Kind kind = overriddenDeclaration.getKind(); + if (kind == DECLARATION) { + result.add(overriddenDeclaration); + } + else if (kind == DELEGATION || kind == FAKE_OVERRIDE || kind == SYNTHESIZED) { + //do nothing + } + else { + throw new AssertionError("Unexpected callable kind " + kind); + } + result.addAll(getAllOverriddenDeclarations(overriddenDeclaration)); + } + return result; + } } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/AddFunctionParametersFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/AddFunctionParametersFix.java index 2e2e8b4c1f8..3e6596c87d1 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/AddFunctionParametersFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/AddFunctionParametersFix.java @@ -16,7 +16,6 @@ package org.jetbrains.jet.plugin.quickfix; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; @@ -33,13 +32,13 @@ import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.plugin.JetBundle; import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache; import org.jetbrains.jet.plugin.refactoring.JetNameValidator; -import org.jetbrains.jet.plugin.refactoring.changeSignature.JetChangeSignatureDialog; -import org.jetbrains.jet.plugin.refactoring.changeSignature.JetFunctionPlatformDescriptorImpl; -import org.jetbrains.jet.plugin.refactoring.changeSignature.JetParameterInfo; +import org.jetbrains.jet.plugin.refactoring.changeSignature.*; import org.jetbrains.jet.renderer.DescriptorRenderer; import java.util.List; +import static org.jetbrains.jet.plugin.refactoring.changeSignature.ChangeSignaturePackage.runChangeSignature; + public class AddFunctionParametersFix extends ChangeFunctionSignatureFix { private final JetCallElement callElement; private final boolean hasTypeMismatches; @@ -85,45 +84,43 @@ public class AddFunctionParametersFix extends ChangeFunctionSignatureFix { @Override protected void invoke(@NotNull Project project, Editor editor, JetFile file) { BindingContext bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) callElement.getContainingFile()).getBindingContext(); - JetFunctionPlatformDescriptorImpl platformDescriptor = new JetFunctionPlatformDescriptorImpl(functionDescriptor, element); - final List parameters = functionDescriptor.getValueParameters(); - List arguments = callElement.getValueArguments(); - JetNameValidator validator = JetNameValidator.getCollectingValidator(callElement.getProject()); + boolean performSilently = !hasTypeMismatches && !(functionDescriptor instanceof ConstructorDescriptor) && !hasOtherUsages(); + runChangeSignature(project, functionDescriptor, addParameterConfiguration(), bindingContext, callElement, getText(), performSilently); + } - for (int i = 0; i < arguments.size(); i ++) { - ValueArgument argument = arguments.get(i); - JetExpression expression = argument.getArgumentExpression(); - - if (i < parameters.size()) { - validator.validateName(parameters.get(i).getName().asString()); - JetType argumentType = expression != null ? bindingContext.get(BindingContext.EXPRESSION_TYPE, expression) : null; - JetType parameterType = parameters.get(i).getType(); - - if (argumentType != null && !JetTypeChecker.INSTANCE.isSubtypeOf(argumentType, parameterType)) - platformDescriptor.getParameters().get(i).setTypeText(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(argumentType)); - } - else { - JetParameterInfo parameterInfo = getNewParameterInfo(bindingContext, argument, validator); - - if (expression != null) - parameterInfo.setDefaultValueText(expression.getText()); - - platformDescriptor.addParameter(parameterInfo); - } - } - - JetChangeSignatureDialog dialog = new JetChangeSignatureDialog(project, platformDescriptor, callElement, getText()) { + private JetChangeSignatureConfiguration addParameterConfiguration() { + return new JetChangeSignatureConfiguration() { @Override - protected int getSelectedIdx() { - return parameters.size(); + public void configure( + @NotNull JetChangeSignatureData changeSignatureData, @NotNull BindingContext bindingContext + ) { + List parameters = functionDescriptor.getValueParameters(); + List arguments = callElement.getValueArguments(); + JetNameValidator validator = JetNameValidator.getCollectingValidator(callElement.getProject()); + + for (int i = 0; i < arguments.size(); i ++) { + ValueArgument argument = arguments.get(i); + JetExpression expression = argument.getArgumentExpression(); + + if (i < parameters.size()) { + validator.validateName(parameters.get(i).getName().asString()); + JetType argumentType = expression != null ? bindingContext.get(BindingContext.EXPRESSION_TYPE, expression) : null; + JetType parameterType = parameters.get(i).getType(); + + if (argumentType != null && !JetTypeChecker.INSTANCE.isSubtypeOf(argumentType, parameterType)) + changeSignatureData.getParameters().get(i).setTypeText(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(argumentType)); + } + else { + JetParameterInfo parameterInfo = getNewParameterInfo(bindingContext, argument, validator); + + if (expression != null) + parameterInfo.setDefaultValueText(expression.getText()); + + changeSignatureData.addParameter(parameterInfo); + } + } } }; - - if (ApplicationManager.getApplication().isUnitTestMode() || - !hasTypeMismatches && !(functionDescriptor instanceof ConstructorDescriptor) && !hasOtherUsages()) - performRefactoringSilently(dialog); - else - dialog.show(); } private boolean hasOtherUsages() { diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeFunctionLiteralSignatureFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeFunctionLiteralSignatureFix.java index ace4c72e126..48ff9816eae 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeFunctionLiteralSignatureFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeFunctionLiteralSignatureFix.java @@ -22,15 +22,20 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetFunctionLiteral; +import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.plugin.JetBundle; +import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache; import org.jetbrains.jet.plugin.refactoring.JetNameSuggester; import org.jetbrains.jet.plugin.refactoring.JetNameValidator; -import org.jetbrains.jet.plugin.refactoring.changeSignature.JetFunctionPlatformDescriptorImpl; +import org.jetbrains.jet.plugin.refactoring.changeSignature.JetChangeSignatureConfiguration; +import org.jetbrains.jet.plugin.refactoring.changeSignature.JetChangeSignatureData; import org.jetbrains.jet.plugin.refactoring.changeSignature.JetParameterInfo; import java.util.List; +import static org.jetbrains.jet.plugin.refactoring.changeSignature.ChangeSignaturePackage.runChangeSignature; + public class ChangeFunctionLiteralSignatureFix extends ChangeFunctionSignatureFix { private final List parameterTypes; @@ -49,16 +54,18 @@ public class ChangeFunctionLiteralSignatureFix extends ChangeFunctionSignatureFi } @Override - protected void invoke(@NotNull Project project, Editor editor, JetFile file) { - JetFunctionPlatformDescriptorImpl platformDescriptor = new JetFunctionPlatformDescriptorImpl(functionDescriptor, element); - JetNameValidator validator = JetNameValidator.getCollectingValidator(project); - platformDescriptor.clearParameters(); - - for (JetType type : parameterTypes) { - String name = JetNameSuggester.suggestNames(type, validator, "param")[0]; - platformDescriptor.addParameter(new JetParameterInfo(name, type)); - } - - showDialog(project, platformDescriptor); + protected void invoke(@NotNull final Project project, Editor editor, JetFile file) { + BindingContext bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache(file).getBindingContext(); + runChangeSignature(project, functionDescriptor, new JetChangeSignatureConfiguration() { + @Override + public void configure(@NotNull JetChangeSignatureData changeSignatureData, @NotNull BindingContext bindingContext) { + JetNameValidator validator = JetNameValidator.getCollectingValidator(project); + changeSignatureData.clearParameters(); + for (JetType type : parameterTypes) { + String name = JetNameSuggester.suggestNames(type, validator, "param")[0]; + changeSignatureData.addParameter(new JetParameterInfo(name, type)); + } + } + }, bindingContext, context, getText(), false); } } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeFunctionSignatureFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeFunctionSignatureFix.java index 56a76689437..b86e5105035 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeFunctionSignatureFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeFunctionSignatureFix.java @@ -16,9 +16,6 @@ package org.jetbrains.jet.plugin.quickfix; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Disposer; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiNameIdentifierOwner; import com.intellij.psi.util.PsiTreeUtil; @@ -41,12 +38,12 @@ import org.jetbrains.jet.plugin.JetBundle; import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache; import org.jetbrains.jet.plugin.refactoring.JetNameSuggester; import org.jetbrains.jet.plugin.refactoring.JetNameValidator; -import org.jetbrains.jet.plugin.refactoring.changeSignature.*; +import org.jetbrains.jet.plugin.refactoring.changeSignature.JetParameterInfo; import java.util.List; public abstract class ChangeFunctionSignatureFix extends JetIntentionAction { - private final PsiElement context; + protected final PsiElement context; protected final FunctionDescriptor functionDescriptor; public ChangeFunctionSignatureFix( @@ -70,21 +67,13 @@ public abstract class ChangeFunctionSignatureFix extends JetIntentionAction parameters, List arguments, BindingContext bindingContext) { + private static boolean hasTypeMismatches( + List parameters, + List arguments, + BindingContext bindingContext + ) { for (int i = 0; i < parameters.size(); i++) { - assert i < arguments.size(); // number of parameters must not be greater than the number of arguments (it's called only for TOO_MANY_ARGUMENTS error) + assert i < + arguments + .size(); // number of parameters must not be greater than the number of arguments (it's called only for TOO_MANY_ARGUMENTS error) JetExpression argumentExpression = arguments.get(i).getArgumentExpression(); - JetType argumentType = argumentExpression != null ? bindingContext.get(BindingContext.EXPRESSION_TYPE, argumentExpression) : null; + JetType argumentType = + argumentExpression != null ? bindingContext.get(BindingContext.EXPRESSION_TYPE, argumentExpression) : null; JetType parameterType = parameters.get(i).getType(); - if (argumentType == null || !JetTypeChecker.INSTANCE.isSubtypeOf(argumentType, parameterType)) + if (argumentType == null || !JetTypeChecker.INSTANCE.isSubtypeOf(argumentType, parameterType)) { return true; + } } return false; } - protected void performRefactoringSilently(final JetChangeSignatureDialog dialog) { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - JetChangeInfo changeInfo = dialog.evaluateChangeInfo(); - JetChangeSignatureProcessor processor = new JetChangeSignatureProcessor(element.getProject(), changeInfo, getText()); - processor.run(); - Disposer.dispose(dialog.getDisposable()); - } - }); - } - public static JetSingleIntentionActionFactory createFactory() { return new JetSingleIntentionActionFactory() { @Override @@ -134,8 +123,9 @@ public abstract class ChangeFunctionSignatureFix extends JetIntentionAction) diagnostic).getA(); - if (callElement != null) + if (callElement != null) { return createFix(callElement, callElement, descriptor); + } return null; } @@ -150,13 +140,17 @@ public abstract class ChangeFunctionSignatureFix extends JetIntentionAction> diagnosticWithParameters = (DiagnosticWithParameters2>) diagnostic; JetFunctionLiteral functionLiteral = diagnosticWithParameters.getPsiElement(); - BindingContext bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) functionLiteral.getContainingFile()).getBindingContext(); + BindingContext bindingContext = + AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) functionLiteral.getContainingFile()).getBindingContext(); DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, functionLiteral); - if (descriptor instanceof FunctionDescriptor) - return new ChangeFunctionLiteralSignatureFix(functionLiteral, (FunctionDescriptor) descriptor, diagnosticWithParameters.getB()); - else + if (descriptor instanceof FunctionDescriptor) { + return new ChangeFunctionLiteralSignatureFix(functionLiteral, (FunctionDescriptor) descriptor, + diagnosticWithParameters.getB()); + } + else { return null; + } } }; } @@ -168,10 +162,12 @@ public abstract class ChangeFunctionSignatureFix extends JetIntentionAction) diagnostic).getA(); - if (descriptor instanceof ValueParameterDescriptor) + if (descriptor instanceof ValueParameterDescriptor) { return createFix(null, diagnostic.getPsiElement(), (CallableDescriptor) descriptor); - else + } + else { return null; + } } }; } @@ -180,31 +176,37 @@ public abstract class ChangeFunctionSignatureFix extends JetIntentionAction parameters = functionDescriptor.getValueParameters(); - List arguments = callElement.getValueArguments(); + if (declaration == null) { + return null; + } + if (descriptor instanceof ValueParameterDescriptor) { + return new RemoveFunctionParametersFix(declaration, context, functionDescriptor, (ValueParameterDescriptor) descriptor); + } + else { + List parameters = functionDescriptor.getValueParameters(); + List arguments = callElement.getValueArguments(); - if (arguments.size() > parameters.size()) { - boolean hasTypeMismatches = hasTypeMismatches(parameters, arguments, bindingContext); - return new AddFunctionParametersFix(declaration, callElement, functionDescriptor, hasTypeMismatches); - } - } + if (arguments.size() > parameters.size()) { + boolean hasTypeMismatches = hasTypeMismatches(parameters, arguments, bindingContext); + return new AddFunctionParametersFix(declaration, callElement, functionDescriptor, hasTypeMismatches); } } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/RemoveFunctionParametersFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/RemoveFunctionParametersFix.java index 94c116d31c4..4948b589a4b 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/RemoveFunctionParametersFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/RemoveFunctionParametersFix.java @@ -23,11 +23,16 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.plugin.JetBundle; -import org.jetbrains.jet.plugin.refactoring.changeSignature.JetFunctionPlatformDescriptorImpl; +import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache; +import org.jetbrains.jet.plugin.refactoring.changeSignature.JetChangeSignatureConfiguration; +import org.jetbrains.jet.plugin.refactoring.changeSignature.JetChangeSignatureData; import java.util.List; +import static org.jetbrains.jet.plugin.refactoring.changeSignature.ChangeSignaturePackage.runChangeSignature; + public class RemoveFunctionParametersFix extends ChangeFunctionSignatureFix { private final ValueParameterDescriptor parameterToRemove; @@ -49,9 +54,15 @@ public class RemoveFunctionParametersFix extends ChangeFunctionSignatureFix { @Override protected void invoke(@NotNull Project project, Editor editor, JetFile file) { - JetFunctionPlatformDescriptorImpl platformDescriptor = new JetFunctionPlatformDescriptorImpl(functionDescriptor, element); - List parameters = functionDescriptor.getValueParameters(); - platformDescriptor.removeParameter(parameters.indexOf(parameterToRemove)); - showDialog(project, platformDescriptor); + BindingContext bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache(file).getBindingContext(); + runChangeSignature(project, functionDescriptor, new JetChangeSignatureConfiguration() { + @Override + public void configure( + @NotNull JetChangeSignatureData changeSignatureData, @NotNull BindingContext bindingContext + ) { + List parameters = functionDescriptor.getValueParameters(); + changeSignatureData.removeParameter(parameters.indexOf(parameterToRemove)); + } + }, bindingContext, context, getText(), false); } } diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeInfo.java b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeInfo.java index af2f35d2aff..d307e86576c 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeInfo.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeInfo.java @@ -32,12 +32,13 @@ import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.plugin.JetLanguage; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; public class JetChangeInfo implements ChangeInfo { - private final JetFunctionPlatformDescriptor oldDescriptor; + private final JetMethodDescriptor oldDescriptor; private String newName; private final JetType newReturnType; private String newReturnTypeText; @@ -49,7 +50,7 @@ public class JetChangeInfo implements ChangeInfo { private Map oldNameToParameterIndex; public JetChangeInfo( - JetFunctionPlatformDescriptor oldDescriptor, + JetMethodDescriptor oldDescriptor, String newName, JetType newReturnType, String newReturnTypeText, @@ -215,7 +216,7 @@ public class JetChangeInfo implements ChangeInfo { return oldDescriptor.getDescriptor(); } - public JetFunctionPlatformDescriptor getFunctionDescriptor() { + public JetMethodDescriptor getFunctionDescriptor() { return oldDescriptor; } @@ -259,4 +260,9 @@ public class JetChangeInfo implements ChangeInfo { public Language getLanguage() { return JetLanguage.INSTANCE; } + + @NotNull + public Collection getAffectedFunctions() { + return oldDescriptor.getAffectedFunctions(); + } } diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignature.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignature.kt new file mode 100644 index 00000000000..aab38b6b008 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignature.kt @@ -0,0 +1,206 @@ +/* + * Copyright 2010-2013 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.jet.plugin.refactoring.changeSignature + +import com.intellij.ide.IdeBundle +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.Messages +import com.intellij.openapi.util.Disposer +import com.intellij.psi.PsiElement +import org.jetbrains.jet.lang.descriptors.* +import org.jetbrains.jet.lang.resolve.BindingContext +import org.jetbrains.jet.lang.resolve.OverridingUtil +import org.jetbrains.jet.plugin.JetBundle +import org.jetbrains.jet.renderer.DescriptorRenderer +import java.util.* +import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor.Kind.* +import org.jetbrains.jet.lang.resolve.BindingContextUtils.* +import org.jetbrains.annotations.TestOnly + +public trait JetChangeSignatureConfiguration { + fun configure(changeSignatureData: JetChangeSignatureData, bindingContext: BindingContext) +} + +public fun runChangeSignature(project: Project, + functionDescriptor: FunctionDescriptor, + configuration: JetChangeSignatureConfiguration, + bindingContext: BindingContext, + defaultValueContext: PsiElement, + commandName: String? = null, + performSilently: Boolean = false): Unit { + JetChangeSignature(project, functionDescriptor, configuration, bindingContext, defaultValueContext, commandName, performSilently).run() +} + +public class JetChangeSignature(val project: Project, + val functionDescriptor: FunctionDescriptor, + val configuration: JetChangeSignatureConfiguration, + val bindingContext: BindingContext, + val defaultValueContext: PsiElement, + val commandName: String?, + val performSilently: Boolean) { + + private val LOG = Logger.getInstance(javaClass()) + + public fun run() { + if (functionDescriptor.getKind() == SYNTHESIZED) { + LOG.error("Change signature refactoring should not be called for synthesized member " + functionDescriptor) + return + } + + val closestModifiableDescriptors = getClosestModifiableDescriptors() + assert(!closestModifiableDescriptors.isEmpty()) { "Should contain functionDescriptor itself or some of its super declarations" } + val deepestSuperDeclarations = getDeepestSuperDeclarations() + if (ApplicationManager.getApplication()!!.isUnitTestMode()) { + showChangeSignatureDialog(deepestSuperDeclarations) + return + } + + if ((closestModifiableDescriptors.size()) == 1 && deepestSuperDeclarations.equals(closestModifiableDescriptors)) { + showChangeSignatureDialog(closestModifiableDescriptors) + return + } + + val isSingleFunctionSelected = closestModifiableDescriptors.size() == 1 + val selectedFunction = if (isSingleFunctionSelected) closestModifiableDescriptors.first() else functionDescriptor + val optionsForDialog = buildDialogOptions(isSingleFunctionSelected) + val code = showSuperFunctionWarningDialog(deepestSuperDeclarations, selectedFunction, optionsForDialog.copyToArray()) + when { + performForWholeHierarchy(optionsForDialog, code) -> { + showChangeSignatureDialog(deepestSuperDeclarations) + } + performForSelectedFunctionOnly(optionsForDialog, code) -> { + showChangeSignatureDialog(closestModifiableDescriptors) + } + else -> { + //do nothing + } + } + } + + private fun getClosestModifiableDescriptors(): Set { + val kind = functionDescriptor.getKind() + if (kind == DELEGATION || kind == FAKE_OVERRIDE) { + return getDirectlyOverriddenDeclarations(functionDescriptor) + } + + assert(kind == DECLARATION) { "Unexpected callable kind: " + kind } + return Collections.singleton(functionDescriptor) + } + + fun getDeepestSuperDeclarations(): Set { + val overriddenDeclarations = getAllOverriddenDeclarations(functionDescriptor) + if (overriddenDeclarations.isEmpty()) { + return Collections.singleton(functionDescriptor) + } + + return OverridingUtil.filterOutOverriding(overriddenDeclarations) + } + + private fun showChangeSignatureDialog(descriptorsForSignatureChange: Collection) { + val dialog = createChangeSignatureDialog(descriptorsForSignatureChange) + if (dialog == null) { + return + } + + if (performSilently || ApplicationManager.getApplication()!!.isUnitTestMode()) { + performRefactoringSilently(dialog) + } + else { + dialog.show() + } + } + + fun createChangeSignatureDialog(descriptorsForSignatureChange: Collection): JetChangeSignatureDialog? { + val baseDescriptor = preferContainedInClass(descriptorsForSignatureChange) + val functionDeclaration = callableDescriptorToDeclaration(bindingContext, baseDescriptor) + if (functionDeclaration == null) { + LOG.error("Could not find declaration for " + baseDescriptor) + return null + } + + val changeSignatureData = JetChangeSignatureData(baseDescriptor, functionDeclaration, bindingContext, descriptorsForSignatureChange) + configuration.configure(changeSignatureData, bindingContext) + return JetChangeSignatureDialog(project, changeSignatureData, defaultValueContext, commandName) + } + + private fun performRefactoringSilently(dialog: JetChangeSignatureDialog) { + ApplicationManager.getApplication()!!.runWriteAction { + dialog.createRefactoringProcessor().run() + Disposer.dispose(dialog.getDisposable()!!) + } + } + + private fun preferContainedInClass(descriptorsForSignatureChange: Collection): FunctionDescriptor { + for (descriptor in descriptorsForSignatureChange) { + val containingDeclaration = descriptor.getContainingDeclaration() + if (containingDeclaration is ClassDescriptor && containingDeclaration.getKind() != ClassKind.TRAIT) { + return descriptor + } + + } + //choose at random + return descriptorsForSignatureChange.first() + } + + private fun buildDialogOptions(isSingleFunctionSelected: Boolean): List { + val optionsForDialog = ArrayList() + optionsForDialog.add(if (isSingleFunctionSelected) Messages.YES_BUTTON else Messages.OK_BUTTON) + if (isSingleFunctionSelected) { + optionsForDialog.add(Messages.NO_BUTTON) + } + optionsForDialog.add(Messages.CANCEL_BUTTON) + return optionsForDialog + } + + private fun performForWholeHierarchy(optionsForDialog: List, code: Int): Boolean { + return buttonPressed(code, optionsForDialog, Messages.YES_BUTTON) || buttonPressed(code, optionsForDialog, Messages.OK_BUTTON) + } + + private fun performForSelectedFunctionOnly(dialogButtons: List, code: Int): Boolean { + return buttonPressed(code, dialogButtons, Messages.NO_BUTTON) + } + + private fun buttonPressed(code: Int, dialogButtons: List, button: String): Boolean { + return code == dialogButtons.indexOf(button) && dialogButtons.contains(button) + } + + private fun showSuperFunctionWarningDialog(superFunctions: Collection, + functionFromEditor: FunctionDescriptor, + options: Array): Int { + val superString = superFunctions.map { + it.getContainingDeclaration().getName().asString() + }.makeString(prefix = "\n ", separator = ",\n ", postfix = ".\n\n") + val message = JetBundle.message("x.overrides.y.in.class.list", + DescriptorRenderer.COMPACT.render(functionFromEditor), + functionFromEditor.getContainingDeclaration().getName().asString(), superString, + "refactor") + val title = IdeBundle.message("title.warning") + val icon = Messages.getQuestionIcon() + return Messages.showDialog(message, title!!, options, 0, icon!!) + } +} + +TestOnly public fun getChangeSignatureDialog(project: Project, + functionDescriptor: FunctionDescriptor, + configuration: JetChangeSignatureConfiguration, + bindingContext: BindingContext, + defaultValueContext: PsiElement): JetChangeSignatureDialog? { + val jetChangeSignature = JetChangeSignature(project, functionDescriptor, configuration, bindingContext, defaultValueContext, null, true) + return jetChangeSignature.createChangeSignatureDialog(jetChangeSignature.getDeepestSuperDeclarations()) +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureData.java b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureData.java new file mode 100644 index 00000000000..18657576da7 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureData.java @@ -0,0 +1,213 @@ +/* + * Copyright 2010-2013 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.jet.plugin.refactoring.changeSignature; + +import com.google.common.collect.Sets; +import com.intellij.openapi.util.Condition; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.search.searches.OverridingMethodsSearch; +import com.intellij.refactoring.changeSignature.MethodDescriptor; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.asJava.LightClassUtil; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor; +import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.BindingContextUtils; +import org.jetbrains.jet.lang.resolve.java.jetAsJava.JetClsMethod; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.renderer.DescriptorRenderer; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +public final class JetChangeSignatureData implements JetMethodDescriptor { + @NotNull + private final FunctionDescriptor baseDescriptor; + @NotNull + private final PsiElement baseDeclaration; + @NotNull + private final List parameters; + @NotNull + private final BindingContext bindingContext; + @NotNull + private final Collection descriptorsForSignatureChange; + + public JetChangeSignatureData( + @NotNull FunctionDescriptor baseDescriptor, + @NotNull PsiElement baseDeclaration, + @NotNull BindingContext bindingContext, + @NotNull Collection descriptorsForSignatureChange + ) { + this.baseDescriptor = baseDescriptor; + this.baseDeclaration = baseDeclaration; + this.bindingContext = bindingContext; + this.descriptorsForSignatureChange = descriptorsForSignatureChange; + final List valueParameters = this.baseDeclaration instanceof JetFunction + ? ((JetFunction) this.baseDeclaration).getValueParameters() + : ((JetClass) this.baseDeclaration).getPrimaryConstructorParameters(); + this.parameters = new ArrayList( + ContainerUtil.map(this.baseDescriptor.getValueParameters(), new Function() { + @Override + public JetParameterInfo fun(ValueParameterDescriptor param) { + JetParameter parameter = valueParameters.get(param.getIndex()); + return new JetParameterInfo(param.getIndex(), param.getName().asString(), param.getType(), + parameter.getDefaultValue(), parameter.getValOrVarNode()); + } + })); + } + + @Override + @NotNull + public List getParameters() { + return parameters; + } + + public void addParameter(JetParameterInfo parameter) { + parameters.add(parameter); + } + + public void removeParameter(int index) { + parameters.remove(index); + } + + public void clearParameters() { + parameters.clear(); + } + + @Override + @NotNull + public Collection getAffectedFunctions() { + Set result = Sets.newHashSet(); + for (FunctionDescriptor descriptor : descriptorsForSignatureChange) { + result.addAll(computeHierarchyFrom(descriptor)); + } + return result; + } + + @NotNull + private Collection computeHierarchyFrom(@NotNull FunctionDescriptor baseDescriptor) { + PsiElement declaration = BindingContextUtils.callableDescriptorToDeclaration(bindingContext, baseDescriptor); + Set result = Sets.newHashSet(); + result.add(declaration); + if (!(declaration instanceof JetNamedFunction)) { + return result; + } + PsiMethod lightMethod = LightClassUtil.getLightClassMethod((JetNamedFunction) declaration); + // there are valid situations when light method is null: local functions and literals + if (lightMethod == null) { + return result; + } + Collection overridingMethods = OverridingMethodsSearch.search(lightMethod).findAll(); + List jetLightMethods = ContainerUtil.filter(overridingMethods, new Condition() { + @Override + public boolean value(PsiMethod method) { + return method instanceof JetClsMethod; + } + }); + List jetFunctions = ContainerUtil.map(jetLightMethods, new Function() { + @Override + public JetDeclaration fun(PsiMethod method) { + return ((JetClsMethod) method).getOrigin(); + } + }); + result.addAll(jetFunctions); + return result; + } + + + @Override + public String getName() { + if (baseDescriptor instanceof ConstructorDescriptor) { + return baseDescriptor.getContainingDeclaration().getName().asString(); + } + else if (baseDescriptor instanceof AnonymousFunctionDescriptor) { + return ""; + } + else { + return baseDescriptor.getName().asString(); + } + } + + @Override + public int getParametersCount() { + return baseDescriptor.getValueParameters().size(); + } + + @Override + public Visibility getVisibility() { + return baseDescriptor.getVisibility(); + } + + @Override + public PsiElement getMethod() { + return baseDeclaration; + } + + @Override + public boolean canChangeVisibility() { + DeclarationDescriptor parent = baseDescriptor.getContainingDeclaration(); + return !(baseDescriptor instanceof AnonymousFunctionDescriptor || + parent instanceof ClassDescriptor && ((ClassDescriptor) parent).getKind() == ClassKind.TRAIT); + } + + @Override + public boolean canChangeParameters() { + return true; + } + + @Override + public boolean canChangeName() { + return !(baseDescriptor instanceof ConstructorDescriptor || + baseDescriptor instanceof AnonymousFunctionDescriptor); + } + + @Override + public MethodDescriptor.ReadWriteOption canChangeReturnType() { + return baseDescriptor instanceof ConstructorDescriptor ? ReadWriteOption.None : ReadWriteOption.ReadWrite; + } + + @Override + public boolean isConstructor() { + return baseDescriptor instanceof ConstructorDescriptor; + } + + @NotNull + @Override + public PsiElement getContext() { + return baseDeclaration; + } + + @Nullable + @Override + public FunctionDescriptor getDescriptor() { + return baseDescriptor; + } + + @Override + @Nullable + public String getReturnTypeText() { + JetType returnType = baseDescriptor.getReturnType(); + return returnType != null ? DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(returnType) : null; + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureDialog.java b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureDialog.java index 9f62cac39e0..f9f0e1d9b96 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureDialog.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureDialog.java @@ -71,7 +71,7 @@ public class JetChangeSignatureDialog extends ChangeSignatureDialogBase< JetParameterInfo, PsiElement, Visibility, - JetFunctionPlatformDescriptor, + JetMethodDescriptor, ParameterTableModelItemBase, JetFunctionParameterTableModel > @@ -79,12 +79,8 @@ public class JetChangeSignatureDialog extends ChangeSignatureDialogBase< private final JetGeneratedInfo generatedInfo = new JetGeneratedInfo(); private final String commandName; - public JetChangeSignatureDialog(Project project, JetFunctionPlatformDescriptor descriptor, PsiElement context) { - this(project, descriptor, context, null); - } - - public JetChangeSignatureDialog(Project project, JetFunctionPlatformDescriptor descriptor, PsiElement context, String commandName) { - super(project, descriptor, false, context); + public JetChangeSignatureDialog(Project project, @NotNull JetMethodDescriptor methodDescriptor, PsiElement context, String commandName) { + super(project, methodDescriptor, false, context); this.commandName = commandName; } @@ -94,7 +90,7 @@ public class JetChangeSignatureDialog extends ChangeSignatureDialogBase< } @Override - protected JetFunctionParameterTableModel createParametersInfoModel(JetFunctionPlatformDescriptor descriptor) { + protected JetFunctionParameterTableModel createParametersInfoModel(JetMethodDescriptor descriptor) { if (descriptor.isConstructor()) return new JetConstructorParameterTableModel(myDefaultValueContext); else @@ -399,6 +395,7 @@ public class JetChangeSignatureDialog extends ChangeSignatureDialogBase< } @Override + @NotNull protected BaseRefactoringProcessor createRefactoringProcessor() { return new JetChangeSignatureProcessor(myProject, evaluateChangeInfo(), commandName != null ? commandName : getTitle()); } @@ -414,6 +411,7 @@ public class JetChangeSignatureDialog extends ChangeSignatureDialogBase< String returnTypeText = myReturnTypeCodeFragment != null ? myReturnTypeCodeFragment.getText().trim() : ""; return new JetChangeInfo(myMethod, getMethodName(), getReturnType(), returnTypeText, - getVisibility(), parameters, myDefaultValueContext, generatedInfo); + getVisibility(), parameters, myDefaultValueContext, generatedInfo + ); } } diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureHandler.java b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureHandler.java index ecd274ba08f..28d9d861582 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureHandler.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureHandler.java @@ -31,27 +31,21 @@ import com.intellij.refactoring.changeSignature.ChangeSignatureHandler; import com.intellij.refactoring.util.CommonRefactoringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; -import org.jetbrains.jet.lang.descriptors.impl.FunctionDescriptorImpl; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache; import org.jetbrains.jet.plugin.refactoring.JetRefactoringBundle; +import static org.jetbrains.jet.plugin.refactoring.changeSignature.ChangeSignaturePackage.runChangeSignature; + public class JetChangeSignatureHandler implements ChangeSignatureHandler { @Nullable - @Override - public PsiElement findTargetMember(PsiFile file, Editor editor) { - return findTargetMember(file.findElementAt(editor.getCaretModel().getOffset())); - } - - @Nullable - @Override - public PsiElement findTargetMember(PsiElement element) { + public static PsiElement findTargetForRefactoring(@NotNull PsiElement element) { if (PsiTreeUtil.getParentOfType(element, JetParameterList.class) != null) { return PsiTreeUtil.getParentOfType(element, JetFunction.class, JetClass.class); } @@ -62,35 +56,77 @@ public class JetChangeSignatureHandler implements ChangeSignatureHandler { } PsiElement elementParent = element.getParent(); - if (elementParent instanceof JetNamedFunction && ((JetNamedFunction)elementParent).getNameIdentifier()==element) { + if (elementParent instanceof JetNamedFunction && ((JetNamedFunction) elementParent).getNameIdentifier() == element) { return elementParent; } - if (elementParent instanceof JetClass && ((JetClass)elementParent).getNameIdentifier()==element) { + if (elementParent instanceof JetClass && ((JetClass) elementParent).getNameIdentifier() == element) { return elementParent; } JetCallElement call = PsiTreeUtil.getParentOfType(element, JetCallExpression.class, JetDelegatorToSuperCall.class); - if (call != null) { - JetExpression receiverExpr = call instanceof JetCallExpression ? call.getCalleeExpression() : - ((JetDelegatorToSuperCall)call).getCalleeExpression().getConstructorReferenceExpression(); + if (call == null) { + return null; + } + JetExpression receiverExpr = call instanceof JetCallExpression ? call.getCalleeExpression() : + ((JetDelegatorToSuperCall) call).getCalleeExpression().getConstructorReferenceExpression(); - if (receiverExpr instanceof JetSimpleNameExpression) { - BindingContext bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) element.getContainingFile()).getBindingContext(); - DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) receiverExpr); + if (receiverExpr instanceof JetSimpleNameExpression) { + BindingContext bindingContext = + AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) element.getContainingFile()).getBindingContext(); + DeclarationDescriptor descriptor = + bindingContext.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) receiverExpr); - if (descriptor != null) { - PsiElement declaration = BindingContextUtils.descriptorToDeclaration(bindingContext, descriptor); - - if (declaration instanceof JetNamedFunction || declaration instanceof JetClass) { - return declaration; - } - } + if (descriptor instanceof ClassDescriptor || descriptor instanceof FunctionDescriptor) { + return receiverExpr; } } return null; } + public static void invokeChangeSignature( + @NotNull PsiElement element, + @NotNull PsiElement context, + @NotNull Project project, + @Nullable Editor editor + ) { + BindingContext bindingContext = + AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) element.getContainingFile()).getBindingContext(); + FunctionDescriptor functionDescriptor = findDescriptor(element, project, editor, bindingContext); + if (functionDescriptor == null) { + return; + } + runChangeSignature(project, functionDescriptor, emptyConfiguration(), bindingContext, context, null, false); + } + + @TestOnly + public static JetChangeSignatureConfiguration getConfiguration() { + return emptyConfiguration(); + } + + private static JetChangeSignatureConfiguration emptyConfiguration() { + return new JetChangeSignatureConfiguration() { + @Override + public void configure( + @NotNull JetChangeSignatureData changeSignatureData, @NotNull BindingContext bindingContext + ) { + //do nothing + } + }; + } + + @Nullable + @Override + public PsiElement findTargetMember(PsiFile file, Editor editor) { + return findTargetMember(file.findElementAt(editor.getCaretModel().getOffset())); + } + + @Nullable + @Override + public PsiElement findTargetMember(PsiElement element) { + return findTargetForRefactoring(element); + } + @Override public void invoke(@NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) { editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); @@ -99,12 +135,9 @@ public class JetChangeSignatureHandler implements ChangeSignatureHandler { element = LangDataKeys.PSI_ELEMENT.getData(dataContext); } - if (element != null) { - JetChangeSignatureDialog dialog = createDialog(element, file.findElementAt(editor.getCaretModel().getOffset()), project, editor); - - if (dialog != null) { - dialog.show(); - } + PsiElement elementAtCaret = file.findElementAt(editor.getCaretModel().getOffset()); + if (element != null && elementAtCaret != null) { + invokeChangeSignature(element, elementAtCaret, project, editor); } } @@ -112,32 +145,45 @@ public class JetChangeSignatureHandler implements ChangeSignatureHandler { public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, @Nullable DataContext dataContext) { if (elements.length != 1) return; Editor editor = dataContext != null ? PlatformDataKeys.EDITOR.getData(dataContext) : null; - JetChangeSignatureDialog dialog = createDialog(elements[0], elements[0], project, editor); - - if (dialog != null) { - dialog.show(); - } + invokeChangeSignature(elements[0], elements[0], project, editor); } @Nullable - public static JetChangeSignatureDialog createDialog(@NotNull PsiElement element, PsiElement context, Project project, Editor editor) { - if (!CommonRefactoringUtil.checkReadOnlyStatus(project, element)) return null; - BindingContext bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile)element.getContainingFile()).getBindingContext(); - DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element); + @Override + public String getTargetNotFoundMessage() { + return JetRefactoringBundle.message("error.wrong.caret.position.function.or.constructor.name"); + } + @Nullable + public static FunctionDescriptor findDescriptor( + @NotNull PsiElement element, + @NotNull Project project, + @Nullable Editor editor, + BindingContext bindingContext + ) { + if (!CommonRefactoringUtil.checkReadOnlyStatus(project, element)) return null; + + DeclarationDescriptor descriptor; + if (element instanceof JetSimpleNameExpression) { + descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, (JetReferenceExpression) element); + } else { + descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element); + } if (descriptor instanceof ClassDescriptor) { descriptor = ((ClassDescriptor) descriptor).getUnsubstitutedPrimaryConstructor(); } - if (descriptor instanceof FunctionDescriptorImpl) { + if (descriptor instanceof FunctionDescriptor) { for (ValueParameterDescriptor parameter : ((FunctionDescriptor) descriptor).getValueParameters()) { if (parameter.getVarargElementType() != null) { String message = JetRefactoringBundle.message("error.cant.refactor.vararg.functions"); - CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.CHANGE_SIGNATURE); + CommonRefactoringUtil.showErrorHint(project, editor, message, + REFACTORING_NAME, + HelpID.CHANGE_SIGNATURE); return null; } } - return new JetChangeSignatureDialog(project, new JetFunctionPlatformDescriptorImpl((FunctionDescriptor) descriptor, element), context); + return (FunctionDescriptor) descriptor; } else { String message = RefactoringBundle.getCannotRefactorMessage(JetRefactoringBundle.message( @@ -146,10 +192,4 @@ public class JetChangeSignatureHandler implements ChangeSignatureHandler { return null; } } - - @Nullable - @Override - public String getTargetNotFoundMessage() { - return JetRefactoringBundle.message("error.wrong.caret.position.function.or.constructor.name"); - } } diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java index f093570c377..2d24c02d9b0 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java @@ -66,12 +66,9 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro } private static void findAllMethodUsages(JetChangeInfo changeInfo, Set result) { - PsiElement method = changeInfo.getMethod(); - - if (method != null) - findOneMethodUsages(method, changeInfo, result, false); - - //TODO overridden methods, tests for different parameter names in overridden methods + for (PsiElement affectedFunction : changeInfo.getAffectedFunctions()) { + findOneMethodUsages(affectedFunction, changeInfo, result, false); + } } private static void findOneMethodUsages(@NotNull PsiElement functionPsi, JetChangeInfo changeInfo, diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetFunctionPlatformDescriptorImpl.java b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetFunctionPlatformDescriptorImpl.java deleted file mode 100644 index 1a2fa088e39..00000000000 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetFunctionPlatformDescriptorImpl.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2010-2013 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.jet.plugin.refactoring.changeSignature; - -import com.intellij.psi.PsiElement; -import com.intellij.util.Function; -import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.descriptors.*; -import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor; -import org.jetbrains.jet.lang.psi.JetClass; -import org.jetbrains.jet.lang.psi.JetFunction; -import org.jetbrains.jet.lang.psi.JetParameter; -import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.jet.renderer.DescriptorRenderer; - -import java.util.ArrayList; -import java.util.List; - -public class JetFunctionPlatformDescriptorImpl implements JetFunctionPlatformDescriptor { - private final FunctionDescriptor funDescriptor; - private final PsiElement funElement; - private final List parameters; - - public JetFunctionPlatformDescriptorImpl(FunctionDescriptor descriptor, PsiElement element) { - funDescriptor = descriptor; - funElement = element; - final List valueParameters = funElement instanceof JetFunction - ? ((JetFunction) funElement).getValueParameters() - : ((JetClass) funElement).getPrimaryConstructorParameters(); - parameters = new ArrayList(ContainerUtil.map(funDescriptor.getValueParameters(), new Function() { - @Override - public JetParameterInfo fun(ValueParameterDescriptor param) { - JetParameter parameter = valueParameters.get(param.getIndex()); - return new JetParameterInfo(param.getIndex(), param.getName().asString(), param.getType(), parameter.getDefaultValue(), parameter.getValOrVarNode()); - } - })); - } - - @Override - public String getName() { - if (funDescriptor instanceof ConstructorDescriptor) - return funDescriptor.getContainingDeclaration().getName().asString(); - else if (funDescriptor instanceof AnonymousFunctionDescriptor) - return ""; - else - return funDescriptor.getName().asString(); - } - - @Override - public List getParameters() { - return parameters; - } - - public void addParameter(JetParameterInfo parameter) { - parameters.add(parameter); - } - - public void removeParameter(int index) { - parameters.remove(index); - } - - public void clearParameters() { - parameters.clear(); - } - - @Override - public int getParametersCount() { - return funDescriptor.getValueParameters().size(); - } - - @Override - public Visibility getVisibility() { - return funDescriptor.getVisibility(); - } - - @Override - public PsiElement getMethod() { - return funElement; - } - - @NotNull - @Override - public PsiElement getContext() { - return funElement; - } - - @Override - public boolean isConstructor() { - return funDescriptor instanceof ConstructorDescriptor; - } - - @Override - public boolean canChangeVisibility() { - DeclarationDescriptor parent = funDescriptor.getContainingDeclaration(); - return !(funDescriptor instanceof AnonymousFunctionDescriptor || parent instanceof ClassDescriptor && ((ClassDescriptor) parent).getKind() == ClassKind.TRAIT); - } - - @Override - public boolean canChangeParameters() { - return true; - } - - @Override - public boolean canChangeName() { - return !(funDescriptor instanceof ConstructorDescriptor || funDescriptor instanceof AnonymousFunctionDescriptor); - } - - @Override - public ReadWriteOption canChangeReturnType() { - return isConstructor() ? ReadWriteOption.None : ReadWriteOption.ReadWrite; - } - - @Override - public FunctionDescriptor getDescriptor() { - return funDescriptor; - } - - @Override - @Nullable - public String getReturnTypeText() { - JetType returnType = funDescriptor.getReturnType(); - return returnType != null ? DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(returnType) : null; - } -} diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetFunctionPlatformDescriptor.java b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetMethodDescriptor.java similarity index 85% rename from idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetFunctionPlatformDescriptor.java rename to idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetMethodDescriptor.java index 04fabe267e5..34a6d298557 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetFunctionPlatformDescriptor.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetMethodDescriptor.java @@ -23,7 +23,12 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.Visibility; -public interface JetFunctionPlatformDescriptor extends MethodDescriptor { +import java.util.Collection; + +public interface JetMethodDescriptor extends MethodDescriptor { + @NotNull + Collection getAffectedFunctions(); + boolean isConstructor(); @Nullable diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetParameterInfo.java b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetParameterInfo.java index 55f21bbc1c2..46442389988 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetParameterInfo.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/changeSignature/JetParameterInfo.java @@ -76,7 +76,7 @@ public class JetParameterInfo implements ParameterInfo { return name; } - public String getInheritedName(boolean isInherited, @Nullable PsiElement inheritedFunction, @NotNull JetFunctionPlatformDescriptor baseFunction) { + public String getInheritedName(boolean isInherited, @Nullable PsiElement inheritedFunction, @NotNull JetMethodDescriptor baseFunction) { if (!(inheritedFunction instanceof JetFunction)) return name; @@ -165,7 +165,7 @@ public class JetParameterInfo implements ParameterInfo { this.valOrVar = valOrVar; } - public String getDeclarationSignature(boolean isInherited, PsiElement inheritedFunction, JetFunctionPlatformDescriptor baseFunction) { + public String getDeclarationSignature(boolean isInherited, PsiElement inheritedFunction, JetMethodDescriptor baseFunction) { StringBuilder buffer = new StringBuilder(); JetValVar valVar = getValOrVar(); diff --git a/idea/testData/quickfix/changeSignature/afterComplexHierarchy.kt b/idea/testData/quickfix/changeSignature/afterComplexHierarchy.kt new file mode 100644 index 00000000000..98d0f98547b --- /dev/null +++ b/idea/testData/quickfix/changeSignature/afterComplexHierarchy.kt @@ -0,0 +1,65 @@ +// "Add parameter to function 'f'" "true" +trait OA { + fun f(a: Int, + i: Int) +} + +trait OB { + fun f(a: Int, + i: Int) +} + +trait O : OA, OB { + override fun f(a: Int, + i: Int) +} + +trait OO : O { + override fun f(a: Int, + i: Int) { + } +} + +trait OOO : OO { + override fun f(a: Int, + i: Int) {} +} + +trait OOOA : OOO { + override fun f(a: Int, + i: Int) { + } +} + +trait OOOB : OOO { + override fun f(a: Int, + i: Int) { + } +} + +fun usage(o: OA) { + o.f(1, 12) +} +fun usage(o: OB) { + o.f(1, 12) +} + +fun usage(o: O) { + o.f(1, 12) +} + +fun usage(o: OO) { + o.f(13, 12) +} + +fun usage(o: OOO) { + o.f(3, 12) +} + +fun usage(o: OOOA) { + o.f(3, 12) +} + +fun usage(o: OOOB) { + o.f(3, 12) +} diff --git a/idea/testData/quickfix/changeSignature/afterComplexHierarchyHead.kt b/idea/testData/quickfix/changeSignature/afterComplexHierarchyHead.kt new file mode 100644 index 00000000000..df449ddbf11 --- /dev/null +++ b/idea/testData/quickfix/changeSignature/afterComplexHierarchyHead.kt @@ -0,0 +1,58 @@ +// "Remove parameter 'a'" "true" +trait OA { + fun f() +} + +trait OB { + fun f(a: Int) +} + +trait O : OA, OB { + override fun f() +} + +trait OO : O { + override fun f() { + } +} + +trait OOO : OO { + override fun f() {} +} + +trait OOOA : OOO { + override fun f() { + } +} + +trait OOOB : OOO { + override fun f() { + } +} + +fun usage(o: OA) { + o.f() +} +fun usage(o: OB) { + o.f(1) +} + +fun usage(o: O) { + o.f() +} + +fun usage(o: OO) { + o.f() +} + +fun usage(o: OOO) { + o.f() +} + +fun usage(o: OOOA) { + o.f() +} + +fun usage(o: OOOB) { + o.f() +} diff --git a/idea/testData/quickfix/changeSignature/afterComplexHierarchyTail.kt b/idea/testData/quickfix/changeSignature/afterComplexHierarchyTail.kt new file mode 100644 index 00000000000..adc9d53c20c --- /dev/null +++ b/idea/testData/quickfix/changeSignature/afterComplexHierarchyTail.kt @@ -0,0 +1,65 @@ +// "Add parameter to function 'f'" "true" +trait OA { + fun f(a: Int, + s: String) +} + +trait OB { + fun f(a: Int, + s: String) +} + +trait O : OA, OB { + override fun f(a: Int, + s: String) +} + +trait OO : O { + override fun f(a: Int, + s: String) { + } +} + +trait OOO : OO { + override fun f(a: Int, + s: String) {} +} + +trait OOOA : OOO { + override fun f(a: Int, + s: String) { + } +} + +trait OOOB : OOO { + override fun f(a: Int, + s: String) { + } +} + +fun usage(o: OA) { + o.f(1, "asdv") +} +fun usage(o: OB) { + o.f(1, "asdv") +} + +fun usage(o: O) { + o.f(1, "asdv") +} + +fun usage(o: OO) { + o.f(13, "asdv") +} + +fun usage(o: OOO) { + o.f(3, "asdv") +} + +fun usage(o: OOOA) { + o.f(3, "asdv") +} + +fun usage(o: OOOB) { + o.f(3, "asdv") +} diff --git a/idea/testData/quickfix/changeSignature/afterLinearHierarchy.kt b/idea/testData/quickfix/changeSignature/afterLinearHierarchy.kt new file mode 100644 index 00000000000..d4388e53e1f --- /dev/null +++ b/idea/testData/quickfix/changeSignature/afterLinearHierarchy.kt @@ -0,0 +1,28 @@ +// "Add parameter to function 'f'" "true" +trait O { + fun f(a: Int, + i: Int) +} + +trait OO : O { + override fun f(a: Int, + i: Int) { + } +} + +trait OOO : OO { + override fun f(a: Int, + i: Int) {} +} + +fun usage(o: O) { + o.f(1, 12) +} + +fun usage(o: OO) { + o.f(13, 12) +} + +fun usage(o: OOO) { + o.f(3, 12) +} diff --git a/idea/testData/quickfix/changeSignature/beforeComplexHierarchy.kt b/idea/testData/quickfix/changeSignature/beforeComplexHierarchy.kt new file mode 100644 index 00000000000..24d994f9799 --- /dev/null +++ b/idea/testData/quickfix/changeSignature/beforeComplexHierarchy.kt @@ -0,0 +1,58 @@ +// "Add parameter to function 'f'" "true" +trait OA { + fun f(a: Int) +} + +trait OB { + fun f(a: Int) +} + +trait O : OA, OB { + override fun f(a: Int) +} + +trait OO : O { + override fun f(a: Int) { + } +} + +trait OOO : OO { + override fun f(a: Int) {} +} + +trait OOOA : OOO { + override fun f(a: Int) { + } +} + +trait OOOB : OOO { + override fun f(a: Int) { + } +} + +fun usage(o: OA) { + o.f(1) +} +fun usage(o: OB) { + o.f(1) +} + +fun usage(o: O) { + o.f(1) +} + +fun usage(o: OO) { + o.f(13, 12) +} + +fun usage(o: OOO) { + o.f(3) +} + +fun usage(o: OOOA) { + o.f(3) +} + +fun usage(o: OOOB) { + o.f(3) +} diff --git a/idea/testData/quickfix/changeSignature/beforeComplexHierarchyHead.kt b/idea/testData/quickfix/changeSignature/beforeComplexHierarchyHead.kt new file mode 100644 index 00000000000..48f5b9a4311 --- /dev/null +++ b/idea/testData/quickfix/changeSignature/beforeComplexHierarchyHead.kt @@ -0,0 +1,58 @@ +// "Remove parameter 'a'" "true" +trait OA { + fun f(a: Int) +} + +trait OB { + fun f(a: Int) +} + +trait O : OA, OB { + override fun f(a: Int) +} + +trait OO : O { + override fun f(a: Int) { + } +} + +trait OOO : OO { + override fun f(a: Int) {} +} + +trait OOOA : OOO { + override fun f(a: Int) { + } +} + +trait OOOB : OOO { + override fun f(a: Int) { + } +} + +fun usage(o: OA) { + o.f() +} +fun usage(o: OB) { + o.f(1) +} + +fun usage(o: O) { + o.f(1) +} + +fun usage(o: OO) { + o.f(13) +} + +fun usage(o: OOO) { + o.f(3) +} + +fun usage(o: OOOA) { + o.f(3) +} + +fun usage(o: OOOB) { + o.f(3) +} diff --git a/idea/testData/quickfix/changeSignature/beforeComplexHierarchyTail.kt b/idea/testData/quickfix/changeSignature/beforeComplexHierarchyTail.kt new file mode 100644 index 00000000000..5b242589c7b --- /dev/null +++ b/idea/testData/quickfix/changeSignature/beforeComplexHierarchyTail.kt @@ -0,0 +1,58 @@ +// "Add parameter to function 'f'" "true" +trait OA { + fun f(a: Int) +} + +trait OB { + fun f(a: Int) +} + +trait O : OA, OB { + override fun f(a: Int) +} + +trait OO : O { + override fun f(a: Int) { + } +} + +trait OOO : OO { + override fun f(a: Int) {} +} + +trait OOOA : OOO { + override fun f(a: Int) { + } +} + +trait OOOB : OOO { + override fun f(a: Int) { + } +} + +fun usage(o: OA) { + o.f(1) +} +fun usage(o: OB) { + o.f(1) +} + +fun usage(o: O) { + o.f(1) +} + +fun usage(o: OO) { + o.f(13) +} + +fun usage(o: OOO) { + o.f(3) +} + +fun usage(o: OOOA) { + o.f(3) +} + +fun usage(o: OOOB) { + o.f(3, "asdv") +} diff --git a/idea/testData/quickfix/changeSignature/beforeLinearHierarchy.kt b/idea/testData/quickfix/changeSignature/beforeLinearHierarchy.kt new file mode 100644 index 00000000000..27f2c643e93 --- /dev/null +++ b/idea/testData/quickfix/changeSignature/beforeLinearHierarchy.kt @@ -0,0 +1,25 @@ +// "Add parameter to function 'f'" "true" +trait O { + fun f(a: Int) +} + +trait OO : O { + override fun f(a: Int) { + } +} + +trait OOO : OO { + override fun f(a: Int) {} +} + +fun usage(o: O) { + o.f(1) +} + +fun usage(o: OO) { + o.f(13, 12) +} + +fun usage(o: OOO) { + o.f(3) +} diff --git a/idea/testData/refactoring/changeSignature/FakeOverrideAfter.kt b/idea/testData/refactoring/changeSignature/FakeOverrideAfter.kt new file mode 100644 index 00000000000..c280c658565 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/FakeOverrideAfter.kt @@ -0,0 +1,15 @@ +trait A { + fun f(i: Int) {} +} + +trait B { + fun f(i: Int) {} +} + +trait C : A, B { + +} + +fun usage(c: C) { + c.f() +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/FakeOverrideBefore.kt b/idea/testData/refactoring/changeSignature/FakeOverrideBefore.kt new file mode 100644 index 00000000000..be1c46463a8 --- /dev/null +++ b/idea/testData/refactoring/changeSignature/FakeOverrideBefore.kt @@ -0,0 +1,15 @@ +trait A { + fun f() {} +} + +trait B { + fun f() {} +} + +trait C : A, B { + +} + +fun usage(c: C) { + c.f() +} \ No newline at end of file diff --git a/idea/testData/refactoring/changeSignature/PreferContainedInClassBefore.kt b/idea/testData/refactoring/changeSignature/PreferContainedInClassBefore.kt new file mode 100644 index 00000000000..91a361b51aa --- /dev/null +++ b/idea/testData/refactoring/changeSignature/PreferContainedInClassBefore.kt @@ -0,0 +1,11 @@ +class A { + fun f(param: Int) +} + +trait B { + fun f(p: Int) +} + +class C : A, B { + override fun f(p: Int) {} +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java index c89a4b16171..89427027c53 100644 --- a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java @@ -389,6 +389,26 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest("idea/testData/quickfix/changeSignature/beforeChangeFunctionLiteralParameters2.kt"); } + @TestMetadata("beforeComplexHierarchy.kt") + public void testComplexHierarchy() throws Exception { + doTest("idea/testData/quickfix/changeSignature/beforeComplexHierarchy.kt"); + } + + @TestMetadata("beforeComplexHierarchyHead.kt") + public void testComplexHierarchyHead() throws Exception { + doTest("idea/testData/quickfix/changeSignature/beforeComplexHierarchyHead.kt"); + } + + @TestMetadata("beforeComplexHierarchyTail.kt") + public void testComplexHierarchyTail() throws Exception { + doTest("idea/testData/quickfix/changeSignature/beforeComplexHierarchyTail.kt"); + } + + @TestMetadata("beforeLinearHierarchy.kt") + public void testLinearHierarchy() throws Exception { + doTest("idea/testData/quickfix/changeSignature/beforeLinearHierarchy.kt"); + } + @TestMetadata("beforeRemoveConstructorParameter.kt") public void testRemoveConstructorParameter() throws Exception { doTest("idea/testData/quickfix/changeSignature/beforeRemoveConstructorParameter.kt"); diff --git a/idea/tests/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureTest.java b/idea/tests/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureTest.java index da04b47cd20..9812d8c20a5 100644 --- a/idea/tests/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/refactoring/changeSignature/JetChangeSignatureTest.java @@ -17,6 +17,7 @@ package org.jetbrains.jet.plugin.refactoring.changeSignature; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; @@ -25,16 +26,22 @@ import com.intellij.refactoring.BaseRefactoringProcessor; import com.intellij.refactoring.util.CommonRefactoringUtil; import com.intellij.testFramework.LightCodeInsightTestCase; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.Visibilities; +import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetPsiFactory; +import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.plugin.PluginTestCaseBase; +import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import static org.jetbrains.jet.plugin.refactoring.changeSignature.ChangeSignaturePackage.getChangeSignatureDialog; + public class JetChangeSignatureTest extends LightCodeInsightTestCase { public void testBadSelection() throws Exception { configureByFile(getTestName(false) + "Before.kt"); @@ -73,6 +80,11 @@ public class JetChangeSignatureTest extends LightCodeInsightTestCase { doTest(changeInfo); } + public void testPreferContainedInClass() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + assertEquals("param", changeInfo.getNewParameters()[0].getName()); + } + public void testAddConstructorVisibility() throws Exception { JetChangeInfo changeInfo = getChangeInfo(); changeInfo.setNewVisibility(Visibilities.PROTECTED); @@ -134,6 +146,13 @@ public class JetChangeSignatureTest extends LightCodeInsightTestCase { doTest(changeInfo); } + public void testFakeOverride() throws Exception { + JetChangeInfo changeInfo = getChangeInfo(); + JetParameterInfo newParameter = new JetParameterInfo("i", KotlinBuiltIns.getInstance().getIntType()); + changeInfo.addParameter(newParameter); + doTest(changeInfo); + } + public void testFunctionLiteral() throws Exception { JetChangeInfo changeInfo = getChangeInfo(); changeInfo.getNewParameters()[1].setName("y1"); @@ -194,8 +213,15 @@ public class JetChangeSignatureTest extends LightCodeInsightTestCase { PsiFile file = getFile(); PsiElement element = new JetChangeSignatureHandler().findTargetMember(file, editor); assertNotNull("Target element is null", element); - JetChangeSignatureDialog dialog = - JetChangeSignatureHandler.createDialog(element, file.findElementAt(editor.getCaretModel().getOffset()), getProject(), editor); + Project project = getProject(); + BindingContext bindingContext = + AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) element.getContainingFile()).getBindingContext(); + PsiElement context = file.findElementAt(editor.getCaretModel().getOffset()); + assertNotNull(context); + FunctionDescriptor functionDescriptor = JetChangeSignatureHandler.findDescriptor(element, project, editor, bindingContext); + assertNotNull(functionDescriptor); + JetChangeSignatureDialog dialog = getChangeSignatureDialog(project, functionDescriptor, + JetChangeSignatureHandler.getConfiguration(), bindingContext, context); assertNotNull(dialog); dialog.canRun(); Disposer.register(getTestRootDisposable(), dialog.getDisposable());