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());