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
This commit is contained in:
Pavel V. Talanov
2013-10-07 20:49:44 +04:00
parent 967030e7c1
commit 8c95884ad2
27 changed files with 1198 additions and 323 deletions
@@ -357,4 +357,35 @@ public class BindingContextUtils {
} }
return OverridingUtil.filterOutOverridden(result); return OverridingUtil.filterOutOverridden(result);
} }
@NotNull
public static Set<FunctionDescriptor> getDirectlyOverriddenDeclarations(@NotNull FunctionDescriptor descriptor) {
//noinspection unchecked
return (Set) getDirectlyOverriddenDeclarations((CallableMemberDescriptor) descriptor);
}
@NotNull
public static Set<PropertyDescriptor> getDirectlyOverriddenDeclarations(@NotNull PropertyDescriptor descriptor) {
//noinspection unchecked
return (Set) getDirectlyOverriddenDeclarations((CallableMemberDescriptor) descriptor);
}
@NotNull
public static Set<FunctionDescriptor> getAllOverriddenDeclarations(@NotNull FunctionDescriptor functionDescriptor) {
Set<FunctionDescriptor> 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;
}
} }
@@ -16,7 +16,6 @@
package org.jetbrains.jet.plugin.quickfix; package org.jetbrains.jet.plugin.quickfix;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement; 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.JetBundle;
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache; import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
import org.jetbrains.jet.plugin.refactoring.JetNameValidator; import org.jetbrains.jet.plugin.refactoring.JetNameValidator;
import org.jetbrains.jet.plugin.refactoring.changeSignature.JetChangeSignatureDialog; import org.jetbrains.jet.plugin.refactoring.changeSignature.*;
import org.jetbrains.jet.plugin.refactoring.changeSignature.JetFunctionPlatformDescriptorImpl;
import org.jetbrains.jet.plugin.refactoring.changeSignature.JetParameterInfo;
import org.jetbrains.jet.renderer.DescriptorRenderer; import org.jetbrains.jet.renderer.DescriptorRenderer;
import java.util.List; import java.util.List;
import static org.jetbrains.jet.plugin.refactoring.changeSignature.ChangeSignaturePackage.runChangeSignature;
public class AddFunctionParametersFix extends ChangeFunctionSignatureFix { public class AddFunctionParametersFix extends ChangeFunctionSignatureFix {
private final JetCallElement callElement; private final JetCallElement callElement;
private final boolean hasTypeMismatches; private final boolean hasTypeMismatches;
@@ -85,45 +84,43 @@ public class AddFunctionParametersFix extends ChangeFunctionSignatureFix {
@Override @Override
protected void invoke(@NotNull Project project, Editor editor, JetFile file) { protected void invoke(@NotNull Project project, Editor editor, JetFile file) {
BindingContext bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) callElement.getContainingFile()).getBindingContext(); BindingContext bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) callElement.getContainingFile()).getBindingContext();
JetFunctionPlatformDescriptorImpl platformDescriptor = new JetFunctionPlatformDescriptorImpl(functionDescriptor, element); boolean performSilently = !hasTypeMismatches && !(functionDescriptor instanceof ConstructorDescriptor) && !hasOtherUsages();
final List<ValueParameterDescriptor> parameters = functionDescriptor.getValueParameters(); runChangeSignature(project, functionDescriptor, addParameterConfiguration(), bindingContext, callElement, getText(), performSilently);
List<? extends ValueArgument> arguments = callElement.getValueArguments(); }
JetNameValidator validator = JetNameValidator.getCollectingValidator(callElement.getProject());
for (int i = 0; i < arguments.size(); i ++) { private JetChangeSignatureConfiguration addParameterConfiguration() {
ValueArgument argument = arguments.get(i); return new JetChangeSignatureConfiguration() {
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()) {
@Override @Override
protected int getSelectedIdx() { public void configure(
return parameters.size(); @NotNull JetChangeSignatureData changeSignatureData, @NotNull BindingContext bindingContext
) {
List<ValueParameterDescriptor> parameters = functionDescriptor.getValueParameters();
List<? extends ValueArgument> 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() { private boolean hasOtherUsages() {
@@ -22,15 +22,20 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetFunctionLiteral; 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.lang.types.JetType;
import org.jetbrains.jet.plugin.JetBundle; 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.JetNameSuggester;
import org.jetbrains.jet.plugin.refactoring.JetNameValidator; 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 org.jetbrains.jet.plugin.refactoring.changeSignature.JetParameterInfo;
import java.util.List; import java.util.List;
import static org.jetbrains.jet.plugin.refactoring.changeSignature.ChangeSignaturePackage.runChangeSignature;
public class ChangeFunctionLiteralSignatureFix extends ChangeFunctionSignatureFix { public class ChangeFunctionLiteralSignatureFix extends ChangeFunctionSignatureFix {
private final List<JetType> parameterTypes; private final List<JetType> parameterTypes;
@@ -49,16 +54,18 @@ public class ChangeFunctionLiteralSignatureFix extends ChangeFunctionSignatureFi
} }
@Override @Override
protected void invoke(@NotNull Project project, Editor editor, JetFile file) { protected void invoke(@NotNull final Project project, Editor editor, JetFile file) {
JetFunctionPlatformDescriptorImpl platformDescriptor = new JetFunctionPlatformDescriptorImpl(functionDescriptor, element); BindingContext bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache(file).getBindingContext();
JetNameValidator validator = JetNameValidator.getCollectingValidator(project); runChangeSignature(project, functionDescriptor, new JetChangeSignatureConfiguration() {
platformDescriptor.clearParameters(); @Override
public void configure(@NotNull JetChangeSignatureData changeSignatureData, @NotNull BindingContext bindingContext) {
for (JetType type : parameterTypes) { JetNameValidator validator = JetNameValidator.getCollectingValidator(project);
String name = JetNameSuggester.suggestNames(type, validator, "param")[0]; changeSignatureData.clearParameters();
platformDescriptor.addParameter(new JetParameterInfo(name, type)); for (JetType type : parameterTypes) {
} String name = JetNameSuggester.suggestNames(type, validator, "param")[0];
changeSignatureData.addParameter(new JetParameterInfo(name, type));
showDialog(project, platformDescriptor); }
}
}, bindingContext, context, getText(), false);
} }
} }
@@ -16,9 +16,6 @@
package org.jetbrains.jet.plugin.quickfix; 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.PsiElement;
import com.intellij.psi.PsiNameIdentifierOwner; import com.intellij.psi.PsiNameIdentifierOwner;
import com.intellij.psi.util.PsiTreeUtil; 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.project.AnalyzerFacadeWithCache;
import org.jetbrains.jet.plugin.refactoring.JetNameSuggester; import org.jetbrains.jet.plugin.refactoring.JetNameSuggester;
import org.jetbrains.jet.plugin.refactoring.JetNameValidator; 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; import java.util.List;
public abstract class ChangeFunctionSignatureFix extends JetIntentionAction<PsiElement> { public abstract class ChangeFunctionSignatureFix extends JetIntentionAction<PsiElement> {
private final PsiElement context; protected final PsiElement context;
protected final FunctionDescriptor functionDescriptor; protected final FunctionDescriptor functionDescriptor;
public ChangeFunctionSignatureFix( public ChangeFunctionSignatureFix(
@@ -70,21 +67,13 @@ public abstract class ChangeFunctionSignatureFix extends JetIntentionAction<PsiE
return false; return false;
} }
protected void showDialog(Project project, JetFunctionPlatformDescriptorImpl platformDescriptor) {
JetChangeSignatureDialog dialog = new JetChangeSignatureDialog(project, platformDescriptor, context, getText());
if (ApplicationManager.getApplication().isUnitTestMode())
performRefactoringSilently(dialog);
else
dialog.show();
}
protected static String getNewArgumentName(ValueArgument argument, JetNameValidator validator) { protected static String getNewArgumentName(ValueArgument argument, JetNameValidator validator) {
JetValueArgumentName argumentName = argument.getArgumentName(); JetValueArgumentName argumentName = argument.getArgumentName();
JetExpression expression = argument.getArgumentExpression(); JetExpression expression = argument.getArgumentExpression();
if (argumentName != null) if (argumentName != null) {
return validator.validateName(argumentName.getName()); return validator.validateName(argumentName.getName());
}
else if (expression != null) { else if (expression != null) {
return JetNameSuggester.suggestNames(expression, validator, "param")[0]; return JetNameSuggester.suggestNames(expression, validator, "param")[0];
} }
@@ -92,7 +81,11 @@ public abstract class ChangeFunctionSignatureFix extends JetIntentionAction<PsiE
return validator.validateName("param"); return validator.validateName("param");
} }
protected static JetParameterInfo getNewParameterInfo(BindingContext bindingContext, ValueArgument argument, JetNameValidator validator) { protected static JetParameterInfo getNewParameterInfo(
BindingContext bindingContext,
ValueArgument argument,
JetNameValidator validator
) {
String name = getNewArgumentName(argument, validator); String name = getNewArgumentName(argument, validator);
JetExpression expression = argument.getArgumentExpression(); JetExpression expression = argument.getArgumentExpression();
JetType type = expression != null ? bindingContext.get(BindingContext.EXPRESSION_TYPE, expression) : null; JetType type = expression != null ? bindingContext.get(BindingContext.EXPRESSION_TYPE, expression) : null;
@@ -100,32 +93,28 @@ public abstract class ChangeFunctionSignatureFix extends JetIntentionAction<PsiE
return new JetParameterInfo(name, type); return new JetParameterInfo(name, type);
} }
private static boolean hasTypeMismatches(List<ValueParameterDescriptor> parameters, List<? extends ValueArgument> arguments, BindingContext bindingContext) { private static boolean hasTypeMismatches(
List<ValueParameterDescriptor> parameters,
List<? extends ValueArgument> arguments,
BindingContext bindingContext
) {
for (int i = 0; i < parameters.size(); i++) { 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(); 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(); 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 true;
}
} }
return false; 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() { public static JetSingleIntentionActionFactory createFactory() {
return new JetSingleIntentionActionFactory() { return new JetSingleIntentionActionFactory() {
@Override @Override
@@ -134,8 +123,9 @@ public abstract class ChangeFunctionSignatureFix extends JetIntentionAction<PsiE
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
CallableDescriptor descriptor = ((DiagnosticWithParameters1<PsiElement, CallableDescriptor>) diagnostic).getA(); CallableDescriptor descriptor = ((DiagnosticWithParameters1<PsiElement, CallableDescriptor>) diagnostic).getA();
if (callElement != null) if (callElement != null) {
return createFix(callElement, callElement, descriptor); return createFix(callElement, callElement, descriptor);
}
return null; return null;
} }
@@ -150,13 +140,17 @@ public abstract class ChangeFunctionSignatureFix extends JetIntentionAction<PsiE
DiagnosticWithParameters2<JetFunctionLiteral, Integer, List<JetType>> diagnosticWithParameters = DiagnosticWithParameters2<JetFunctionLiteral, Integer, List<JetType>> diagnosticWithParameters =
(DiagnosticWithParameters2<JetFunctionLiteral, Integer, List<JetType>>) diagnostic; (DiagnosticWithParameters2<JetFunctionLiteral, Integer, List<JetType>>) diagnostic;
JetFunctionLiteral functionLiteral = diagnosticWithParameters.getPsiElement(); 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); DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, functionLiteral);
if (descriptor instanceof FunctionDescriptor) if (descriptor instanceof FunctionDescriptor) {
return new ChangeFunctionLiteralSignatureFix(functionLiteral, (FunctionDescriptor) descriptor, diagnosticWithParameters.getB()); return new ChangeFunctionLiteralSignatureFix(functionLiteral, (FunctionDescriptor) descriptor,
else diagnosticWithParameters.getB());
}
else {
return null; return null;
}
} }
}; };
} }
@@ -168,10 +162,12 @@ public abstract class ChangeFunctionSignatureFix extends JetIntentionAction<PsiE
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Object descriptor = ((DiagnosticWithParameters1<PsiNameIdentifierOwner, Object>) diagnostic).getA(); Object descriptor = ((DiagnosticWithParameters1<PsiNameIdentifierOwner, Object>) diagnostic).getA();
if (descriptor instanceof ValueParameterDescriptor) if (descriptor instanceof ValueParameterDescriptor) {
return createFix(null, diagnostic.getPsiElement(), (CallableDescriptor) descriptor); return createFix(null, diagnostic.getPsiElement(), (CallableDescriptor) descriptor);
else }
else {
return null; return null;
}
} }
}; };
} }
@@ -180,31 +176,37 @@ public abstract class ChangeFunctionSignatureFix extends JetIntentionAction<PsiE
private static ChangeFunctionSignatureFix createFix(JetCallElement callElement, PsiElement context, CallableDescriptor descriptor) { private static ChangeFunctionSignatureFix createFix(JetCallElement callElement, PsiElement context, CallableDescriptor descriptor) {
FunctionDescriptor functionDescriptor = null; FunctionDescriptor functionDescriptor = null;
if (descriptor instanceof FunctionDescriptor) if (descriptor instanceof FunctionDescriptor) {
functionDescriptor = (FunctionDescriptor) descriptor; functionDescriptor = (FunctionDescriptor) descriptor;
}
else if (descriptor instanceof ValueParameterDescriptor) { else if (descriptor instanceof ValueParameterDescriptor) {
DeclarationDescriptor containingDescriptor = descriptor.getContainingDeclaration(); DeclarationDescriptor containingDescriptor = descriptor.getContainingDeclaration();
if (containingDescriptor instanceof FunctionDescriptor) if (containingDescriptor instanceof FunctionDescriptor) {
functionDescriptor = (FunctionDescriptor) containingDescriptor; functionDescriptor = (FunctionDescriptor) containingDescriptor;
}
} }
if (functionDescriptor != null) { if (functionDescriptor == null) {
BindingContext bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) context.getContainingFile()).getBindingContext(); return null;
PsiElement declaration = BindingContextUtils.descriptorToDeclaration(bindingContext, functionDescriptor); }
BindingContext bindingContext =
AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) context.getContainingFile()).getBindingContext();
PsiElement declaration = BindingContextUtils.descriptorToDeclaration(bindingContext, functionDescriptor);
if (declaration != null) { if (declaration == null) {
if (descriptor instanceof ValueParameterDescriptor) return null;
return new RemoveFunctionParametersFix(declaration, context, functionDescriptor, (ValueParameterDescriptor) descriptor); }
else { if (descriptor instanceof ValueParameterDescriptor) {
List<ValueParameterDescriptor> parameters = functionDescriptor.getValueParameters(); return new RemoveFunctionParametersFix(declaration, context, functionDescriptor, (ValueParameterDescriptor) descriptor);
List<? extends ValueArgument> arguments = callElement.getValueArguments(); }
else {
List<ValueParameterDescriptor> parameters = functionDescriptor.getValueParameters();
List<? extends ValueArgument> arguments = callElement.getValueArguments();
if (arguments.size() > parameters.size()) { if (arguments.size() > parameters.size()) {
boolean hasTypeMismatches = hasTypeMismatches(parameters, arguments, bindingContext); boolean hasTypeMismatches = hasTypeMismatches(parameters, arguments, bindingContext);
return new AddFunctionParametersFix(declaration, callElement, functionDescriptor, hasTypeMismatches); return new AddFunctionParametersFix(declaration, callElement, functionDescriptor, hasTypeMismatches);
}
}
} }
} }
@@ -23,11 +23,16 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.psi.JetFile; 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.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 java.util.List;
import static org.jetbrains.jet.plugin.refactoring.changeSignature.ChangeSignaturePackage.runChangeSignature;
public class RemoveFunctionParametersFix extends ChangeFunctionSignatureFix { public class RemoveFunctionParametersFix extends ChangeFunctionSignatureFix {
private final ValueParameterDescriptor parameterToRemove; private final ValueParameterDescriptor parameterToRemove;
@@ -49,9 +54,15 @@ public class RemoveFunctionParametersFix extends ChangeFunctionSignatureFix {
@Override @Override
protected void invoke(@NotNull Project project, Editor editor, JetFile file) { protected void invoke(@NotNull Project project, Editor editor, JetFile file) {
JetFunctionPlatformDescriptorImpl platformDescriptor = new JetFunctionPlatformDescriptorImpl(functionDescriptor, element); BindingContext bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache(file).getBindingContext();
List<ValueParameterDescriptor> parameters = functionDescriptor.getValueParameters(); runChangeSignature(project, functionDescriptor, new JetChangeSignatureConfiguration() {
platformDescriptor.removeParameter(parameters.indexOf(parameterToRemove)); @Override
showDialog(project, platformDescriptor); public void configure(
@NotNull JetChangeSignatureData changeSignatureData, @NotNull BindingContext bindingContext
) {
List<ValueParameterDescriptor> parameters = functionDescriptor.getValueParameters();
changeSignatureData.removeParameter(parameters.indexOf(parameterToRemove));
}
}, bindingContext, context, getText(), false);
} }
} }
@@ -32,12 +32,13 @@ import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.JetLanguage; import org.jetbrains.jet.plugin.JetLanguage;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
public class JetChangeInfo implements ChangeInfo { public class JetChangeInfo implements ChangeInfo {
private final JetFunctionPlatformDescriptor oldDescriptor; private final JetMethodDescriptor oldDescriptor;
private String newName; private String newName;
private final JetType newReturnType; private final JetType newReturnType;
private String newReturnTypeText; private String newReturnTypeText;
@@ -49,7 +50,7 @@ public class JetChangeInfo implements ChangeInfo {
private Map<String, Integer> oldNameToParameterIndex; private Map<String, Integer> oldNameToParameterIndex;
public JetChangeInfo( public JetChangeInfo(
JetFunctionPlatformDescriptor oldDescriptor, JetMethodDescriptor oldDescriptor,
String newName, String newName,
JetType newReturnType, JetType newReturnType,
String newReturnTypeText, String newReturnTypeText,
@@ -215,7 +216,7 @@ public class JetChangeInfo implements ChangeInfo {
return oldDescriptor.getDescriptor(); return oldDescriptor.getDescriptor();
} }
public JetFunctionPlatformDescriptor getFunctionDescriptor() { public JetMethodDescriptor getFunctionDescriptor() {
return oldDescriptor; return oldDescriptor;
} }
@@ -259,4 +260,9 @@ public class JetChangeInfo implements ChangeInfo {
public Language getLanguage() { public Language getLanguage() {
return JetLanguage.INSTANCE; return JetLanguage.INSTANCE;
} }
@NotNull
public Collection<PsiElement> getAffectedFunctions() {
return oldDescriptor.getAffectedFunctions();
}
} }
@@ -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<JetChangeSignature>())
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<FunctionDescriptor> {
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<FunctionDescriptor> {
val overriddenDeclarations = getAllOverriddenDeclarations(functionDescriptor)
if (overriddenDeclarations.isEmpty()) {
return Collections.singleton(functionDescriptor)
}
return OverridingUtil.filterOutOverriding(overriddenDeclarations)
}
private fun showChangeSignatureDialog(descriptorsForSignatureChange: Collection<FunctionDescriptor>) {
val dialog = createChangeSignatureDialog(descriptorsForSignatureChange)
if (dialog == null) {
return
}
if (performSilently || ApplicationManager.getApplication()!!.isUnitTestMode()) {
performRefactoringSilently(dialog)
}
else {
dialog.show()
}
}
fun createChangeSignatureDialog(descriptorsForSignatureChange: Collection<FunctionDescriptor>): 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>): 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<String> {
val optionsForDialog = ArrayList<String>()
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<String>, code: Int): Boolean {
return buttonPressed(code, optionsForDialog, Messages.YES_BUTTON) || buttonPressed(code, optionsForDialog, Messages.OK_BUTTON)
}
private fun performForSelectedFunctionOnly(dialogButtons: List<String>, code: Int): Boolean {
return buttonPressed(code, dialogButtons, Messages.NO_BUTTON)
}
private fun buttonPressed(code: Int, dialogButtons: List<String>, button: String): Boolean {
return code == dialogButtons.indexOf(button) && dialogButtons.contains(button)
}
private fun showSuperFunctionWarningDialog(superFunctions: Collection<FunctionDescriptor>,
functionFromEditor: FunctionDescriptor,
options: Array<String>): 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())
}
@@ -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<JetParameterInfo> parameters;
@NotNull
private final BindingContext bindingContext;
@NotNull
private final Collection<FunctionDescriptor> descriptorsForSignatureChange;
public JetChangeSignatureData(
@NotNull FunctionDescriptor baseDescriptor,
@NotNull PsiElement baseDeclaration,
@NotNull BindingContext bindingContext,
@NotNull Collection<FunctionDescriptor> descriptorsForSignatureChange
) {
this.baseDescriptor = baseDescriptor;
this.baseDeclaration = baseDeclaration;
this.bindingContext = bindingContext;
this.descriptorsForSignatureChange = descriptorsForSignatureChange;
final List<JetParameter> valueParameters = this.baseDeclaration instanceof JetFunction
? ((JetFunction) this.baseDeclaration).getValueParameters()
: ((JetClass) this.baseDeclaration).getPrimaryConstructorParameters();
this.parameters = new ArrayList<JetParameterInfo>(
ContainerUtil.map(this.baseDescriptor.getValueParameters(), new Function<ValueParameterDescriptor, JetParameterInfo>() {
@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<JetParameterInfo> 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<PsiElement> getAffectedFunctions() {
Set<PsiElement> result = Sets.newHashSet();
for (FunctionDescriptor descriptor : descriptorsForSignatureChange) {
result.addAll(computeHierarchyFrom(descriptor));
}
return result;
}
@NotNull
private Collection<PsiElement> computeHierarchyFrom(@NotNull FunctionDescriptor baseDescriptor) {
PsiElement declaration = BindingContextUtils.callableDescriptorToDeclaration(bindingContext, baseDescriptor);
Set<PsiElement> 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<PsiMethod> overridingMethods = OverridingMethodsSearch.search(lightMethod).findAll();
List<PsiMethod> jetLightMethods = ContainerUtil.filter(overridingMethods, new Condition<PsiMethod>() {
@Override
public boolean value(PsiMethod method) {
return method instanceof JetClsMethod;
}
});
List<JetDeclaration> jetFunctions = ContainerUtil.map(jetLightMethods, new Function<PsiMethod, JetDeclaration>() {
@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;
}
}
@@ -71,7 +71,7 @@ public class JetChangeSignatureDialog extends ChangeSignatureDialogBase<
JetParameterInfo, JetParameterInfo,
PsiElement, PsiElement,
Visibility, Visibility,
JetFunctionPlatformDescriptor, JetMethodDescriptor,
ParameterTableModelItemBase<JetParameterInfo>, ParameterTableModelItemBase<JetParameterInfo>,
JetFunctionParameterTableModel JetFunctionParameterTableModel
> >
@@ -79,12 +79,8 @@ public class JetChangeSignatureDialog extends ChangeSignatureDialogBase<
private final JetGeneratedInfo generatedInfo = new JetGeneratedInfo(); private final JetGeneratedInfo generatedInfo = new JetGeneratedInfo();
private final String commandName; private final String commandName;
public JetChangeSignatureDialog(Project project, JetFunctionPlatformDescriptor descriptor, PsiElement context) { public JetChangeSignatureDialog(Project project, @NotNull JetMethodDescriptor methodDescriptor, PsiElement context, String commandName) {
this(project, descriptor, context, null); super(project, methodDescriptor, false, context);
}
public JetChangeSignatureDialog(Project project, JetFunctionPlatformDescriptor descriptor, PsiElement context, String commandName) {
super(project, descriptor, false, context);
this.commandName = commandName; this.commandName = commandName;
} }
@@ -94,7 +90,7 @@ public class JetChangeSignatureDialog extends ChangeSignatureDialogBase<
} }
@Override @Override
protected JetFunctionParameterTableModel createParametersInfoModel(JetFunctionPlatformDescriptor descriptor) { protected JetFunctionParameterTableModel createParametersInfoModel(JetMethodDescriptor descriptor) {
if (descriptor.isConstructor()) if (descriptor.isConstructor())
return new JetConstructorParameterTableModel(myDefaultValueContext); return new JetConstructorParameterTableModel(myDefaultValueContext);
else else
@@ -399,6 +395,7 @@ public class JetChangeSignatureDialog extends ChangeSignatureDialogBase<
} }
@Override @Override
@NotNull
protected BaseRefactoringProcessor createRefactoringProcessor() { protected BaseRefactoringProcessor createRefactoringProcessor() {
return new JetChangeSignatureProcessor(myProject, evaluateChangeInfo(), commandName != null ? commandName : getTitle()); 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() : ""; String returnTypeText = myReturnTypeCodeFragment != null ? myReturnTypeCodeFragment.getText().trim() : "";
return new JetChangeInfo(myMethod, getMethodName(), getReturnType(), returnTypeText, return new JetChangeInfo(myMethod, getMethodName(), getReturnType(), returnTypeText,
getVisibility(), parameters, myDefaultValueContext, generatedInfo); getVisibility(), parameters, myDefaultValueContext, generatedInfo
);
} }
} }
@@ -31,27 +31,21 @@ import com.intellij.refactoring.changeSignature.ChangeSignatureHandler;
import com.intellij.refactoring.util.CommonRefactoringUtil; import com.intellij.refactoring.util.CommonRefactoringUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; 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.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; 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.project.AnalyzerFacadeWithCache;
import org.jetbrains.jet.plugin.refactoring.JetRefactoringBundle; import org.jetbrains.jet.plugin.refactoring.JetRefactoringBundle;
import static org.jetbrains.jet.plugin.refactoring.changeSignature.ChangeSignaturePackage.runChangeSignature;
public class JetChangeSignatureHandler implements ChangeSignatureHandler { public class JetChangeSignatureHandler implements ChangeSignatureHandler {
@Nullable @Nullable
@Override public static PsiElement findTargetForRefactoring(@NotNull PsiElement element) {
public PsiElement findTargetMember(PsiFile file, Editor editor) {
return findTargetMember(file.findElementAt(editor.getCaretModel().getOffset()));
}
@Nullable
@Override
public PsiElement findTargetMember(PsiElement element) {
if (PsiTreeUtil.getParentOfType(element, JetParameterList.class) != null) { if (PsiTreeUtil.getParentOfType(element, JetParameterList.class) != null) {
return PsiTreeUtil.getParentOfType(element, JetFunction.class, JetClass.class); return PsiTreeUtil.getParentOfType(element, JetFunction.class, JetClass.class);
} }
@@ -62,35 +56,77 @@ public class JetChangeSignatureHandler implements ChangeSignatureHandler {
} }
PsiElement elementParent = element.getParent(); PsiElement elementParent = element.getParent();
if (elementParent instanceof JetNamedFunction && ((JetNamedFunction)elementParent).getNameIdentifier()==element) { if (elementParent instanceof JetNamedFunction && ((JetNamedFunction) elementParent).getNameIdentifier() == element) {
return elementParent; return elementParent;
} }
if (elementParent instanceof JetClass && ((JetClass)elementParent).getNameIdentifier()==element) { if (elementParent instanceof JetClass && ((JetClass) elementParent).getNameIdentifier() == element) {
return elementParent; return elementParent;
} }
JetCallElement call = PsiTreeUtil.getParentOfType(element, JetCallExpression.class, JetDelegatorToSuperCall.class); JetCallElement call = PsiTreeUtil.getParentOfType(element, JetCallExpression.class, JetDelegatorToSuperCall.class);
if (call != null) { if (call == null) {
JetExpression receiverExpr = call instanceof JetCallExpression ? call.getCalleeExpression() : return null;
((JetDelegatorToSuperCall)call).getCalleeExpression().getConstructorReferenceExpression(); }
JetExpression receiverExpr = call instanceof JetCallExpression ? call.getCalleeExpression() :
((JetDelegatorToSuperCall) call).getCalleeExpression().getConstructorReferenceExpression();
if (receiverExpr instanceof JetSimpleNameExpression) { if (receiverExpr instanceof JetSimpleNameExpression) {
BindingContext bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) element.getContainingFile()).getBindingContext(); BindingContext bindingContext =
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) receiverExpr); AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) element.getContainingFile()).getBindingContext();
DeclarationDescriptor descriptor =
bindingContext.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) receiverExpr);
if (descriptor != null) { if (descriptor instanceof ClassDescriptor || descriptor instanceof FunctionDescriptor) {
PsiElement declaration = BindingContextUtils.descriptorToDeclaration(bindingContext, descriptor); return receiverExpr;
if (declaration instanceof JetNamedFunction || declaration instanceof JetClass) {
return declaration;
}
}
} }
} }
return null; 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 @Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) { public void invoke(@NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) {
editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
@@ -99,12 +135,9 @@ public class JetChangeSignatureHandler implements ChangeSignatureHandler {
element = LangDataKeys.PSI_ELEMENT.getData(dataContext); element = LangDataKeys.PSI_ELEMENT.getData(dataContext);
} }
if (element != null) { PsiElement elementAtCaret = file.findElementAt(editor.getCaretModel().getOffset());
JetChangeSignatureDialog dialog = createDialog(element, file.findElementAt(editor.getCaretModel().getOffset()), project, editor); if (element != null && elementAtCaret != null) {
invokeChangeSignature(element, elementAtCaret, project, editor);
if (dialog != null) {
dialog.show();
}
} }
} }
@@ -112,32 +145,45 @@ public class JetChangeSignatureHandler implements ChangeSignatureHandler {
public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, @Nullable DataContext dataContext) { public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, @Nullable DataContext dataContext) {
if (elements.length != 1) return; if (elements.length != 1) return;
Editor editor = dataContext != null ? PlatformDataKeys.EDITOR.getData(dataContext) : null; Editor editor = dataContext != null ? PlatformDataKeys.EDITOR.getData(dataContext) : null;
JetChangeSignatureDialog dialog = createDialog(elements[0], elements[0], project, editor); invokeChangeSignature(elements[0], elements[0], project, editor);
if (dialog != null) {
dialog.show();
}
} }
@Nullable @Nullable
public static JetChangeSignatureDialog createDialog(@NotNull PsiElement element, PsiElement context, Project project, Editor editor) { @Override
if (!CommonRefactoringUtil.checkReadOnlyStatus(project, element)) return null; public String getTargetNotFoundMessage() {
BindingContext bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile)element.getContainingFile()).getBindingContext(); return JetRefactoringBundle.message("error.wrong.caret.position.function.or.constructor.name");
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element); }
@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) { if (descriptor instanceof ClassDescriptor) {
descriptor = ((ClassDescriptor) descriptor).getUnsubstitutedPrimaryConstructor(); descriptor = ((ClassDescriptor) descriptor).getUnsubstitutedPrimaryConstructor();
} }
if (descriptor instanceof FunctionDescriptorImpl) { if (descriptor instanceof FunctionDescriptor) {
for (ValueParameterDescriptor parameter : ((FunctionDescriptor) descriptor).getValueParameters()) { for (ValueParameterDescriptor parameter : ((FunctionDescriptor) descriptor).getValueParameters()) {
if (parameter.getVarargElementType() != null) { if (parameter.getVarargElementType() != null) {
String message = JetRefactoringBundle.message("error.cant.refactor.vararg.functions"); 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 null;
} }
} }
return new JetChangeSignatureDialog(project, new JetFunctionPlatformDescriptorImpl((FunctionDescriptor) descriptor, element), context); return (FunctionDescriptor) descriptor;
} }
else { else {
String message = RefactoringBundle.getCannotRefactorMessage(JetRefactoringBundle.message( String message = RefactoringBundle.getCannotRefactorMessage(JetRefactoringBundle.message(
@@ -146,10 +192,4 @@ public class JetChangeSignatureHandler implements ChangeSignatureHandler {
return null; return null;
} }
} }
@Nullable
@Override
public String getTargetNotFoundMessage() {
return JetRefactoringBundle.message("error.wrong.caret.position.function.or.constructor.name");
}
} }
@@ -66,12 +66,9 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
} }
private static void findAllMethodUsages(JetChangeInfo changeInfo, Set<UsageInfo> result) { private static void findAllMethodUsages(JetChangeInfo changeInfo, Set<UsageInfo> result) {
PsiElement method = changeInfo.getMethod(); for (PsiElement affectedFunction : changeInfo.getAffectedFunctions()) {
findOneMethodUsages(affectedFunction, changeInfo, result, false);
if (method != null) }
findOneMethodUsages(method, changeInfo, result, false);
//TODO overridden methods, tests for different parameter names in overridden methods
} }
private static void findOneMethodUsages(@NotNull PsiElement functionPsi, JetChangeInfo changeInfo, private static void findOneMethodUsages(@NotNull PsiElement functionPsi, JetChangeInfo changeInfo,
@@ -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<JetParameterInfo> parameters;
public JetFunctionPlatformDescriptorImpl(FunctionDescriptor descriptor, PsiElement element) {
funDescriptor = descriptor;
funElement = element;
final List<JetParameter> valueParameters = funElement instanceof JetFunction
? ((JetFunction) funElement).getValueParameters()
: ((JetClass) funElement).getPrimaryConstructorParameters();
parameters = new ArrayList<JetParameterInfo>(ContainerUtil.map(funDescriptor.getValueParameters(), new Function<ValueParameterDescriptor, JetParameterInfo>() {
@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<JetParameterInfo> 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;
}
}
@@ -23,7 +23,12 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.Visibility; import org.jetbrains.jet.lang.descriptors.Visibility;
public interface JetFunctionPlatformDescriptor extends MethodDescriptor<JetParameterInfo, Visibility> { import java.util.Collection;
public interface JetMethodDescriptor extends MethodDescriptor<JetParameterInfo, Visibility> {
@NotNull
Collection<PsiElement> getAffectedFunctions();
boolean isConstructor(); boolean isConstructor();
@Nullable @Nullable
@@ -76,7 +76,7 @@ public class JetParameterInfo implements ParameterInfo {
return name; 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)) if (!(inheritedFunction instanceof JetFunction))
return name; return name;
@@ -165,7 +165,7 @@ public class JetParameterInfo implements ParameterInfo {
this.valOrVar = valOrVar; 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(); StringBuilder buffer = new StringBuilder();
JetValVar valVar = getValOrVar(); JetValVar valVar = getValOrVar();
@@ -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)
}
@@ -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()
}
@@ -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")
}
@@ -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)
}
@@ -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, <caret>12)
}
fun usage(o: OOO) {
o.f(3)
}
fun usage(o: OOOA) {
o.f(3)
}
fun usage(o: OOOB) {
o.f(3)
}
@@ -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(<caret>)
}
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)
}
@@ -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, <caret>"asdv")
}
@@ -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, <caret>12)
}
fun usage(o: OOO) {
o.f(3)
}
@@ -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()
}
@@ -0,0 +1,15 @@
trait A {
fun f() {}
}
trait B {
fun f() {}
}
trait C : A, B {
}
fun usage(c: C) {
c.<caret>f()
}
@@ -0,0 +1,11 @@
class A {
fun f(param: Int)
}
trait B {
fun f(p: Int)
}
class C : A, B {
override fun <caret>f(p: Int) {}
}
@@ -389,6 +389,26 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
doTest("idea/testData/quickfix/changeSignature/beforeChangeFunctionLiteralParameters2.kt"); 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") @TestMetadata("beforeRemoveConstructorParameter.kt")
public void testRemoveConstructorParameter() throws Exception { public void testRemoveConstructorParameter() throws Exception {
doTest("idea/testData/quickfix/changeSignature/beforeRemoveConstructorParameter.kt"); doTest("idea/testData/quickfix/changeSignature/beforeRemoveConstructorParameter.kt");
@@ -17,6 +17,7 @@
package org.jetbrains.jet.plugin.refactoring.changeSignature; package org.jetbrains.jet.plugin.refactoring.changeSignature;
import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
@@ -25,16 +26,22 @@ import com.intellij.refactoring.BaseRefactoringProcessor;
import com.intellij.refactoring.util.CommonRefactoringUtil; import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.testFramework.LightCodeInsightTestCase; import com.intellij.testFramework.LightCodeInsightTestCase;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.Visibilities; 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.psi.JetPsiFactory;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.plugin.PluginTestCaseBase; import org.jetbrains.jet.plugin.PluginTestCaseBase;
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import static org.jetbrains.jet.plugin.refactoring.changeSignature.ChangeSignaturePackage.getChangeSignatureDialog;
public class JetChangeSignatureTest extends LightCodeInsightTestCase { public class JetChangeSignatureTest extends LightCodeInsightTestCase {
public void testBadSelection() throws Exception { public void testBadSelection() throws Exception {
configureByFile(getTestName(false) + "Before.kt"); configureByFile(getTestName(false) + "Before.kt");
@@ -73,6 +80,11 @@ public class JetChangeSignatureTest extends LightCodeInsightTestCase {
doTest(changeInfo); doTest(changeInfo);
} }
public void testPreferContainedInClass() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
assertEquals("param", changeInfo.getNewParameters()[0].getName());
}
public void testAddConstructorVisibility() throws Exception { public void testAddConstructorVisibility() throws Exception {
JetChangeInfo changeInfo = getChangeInfo(); JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setNewVisibility(Visibilities.PROTECTED); changeInfo.setNewVisibility(Visibilities.PROTECTED);
@@ -134,6 +146,13 @@ public class JetChangeSignatureTest extends LightCodeInsightTestCase {
doTest(changeInfo); 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 { public void testFunctionLiteral() throws Exception {
JetChangeInfo changeInfo = getChangeInfo(); JetChangeInfo changeInfo = getChangeInfo();
changeInfo.getNewParameters()[1].setName("y1"); changeInfo.getNewParameters()[1].setName("y1");
@@ -194,8 +213,15 @@ public class JetChangeSignatureTest extends LightCodeInsightTestCase {
PsiFile file = getFile(); PsiFile file = getFile();
PsiElement element = new JetChangeSignatureHandler().findTargetMember(file, editor); PsiElement element = new JetChangeSignatureHandler().findTargetMember(file, editor);
assertNotNull("Target element is null", element); assertNotNull("Target element is null", element);
JetChangeSignatureDialog dialog = Project project = getProject();
JetChangeSignatureHandler.createDialog(element, file.findElementAt(editor.getCaretModel().getOffset()), getProject(), editor); 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); assertNotNull(dialog);
dialog.canRun(); dialog.canRun();
Disposer.register(getTestRootDisposable(), dialog.getDisposable()); Disposer.register(getTestRootDisposable(), dialog.getDisposable());