Implemented "Change signature" refactoring

This commit is contained in:
Alexander Kirillin
2013-04-25 20:45:35 +04:00
parent 500a165191
commit 0a597e563a
62 changed files with 2671 additions and 45 deletions
@@ -45,6 +45,10 @@ public class JetPsiFactory {
return property.getValOrVarNode();
}
public static ASTNode createValOrVarNode(Project project, String text) {
return createParameterList(project, "(" + text + " int x)").getParameters().get(0).getValOrVarNode();
}
public static JetExpression createExpression(Project project, String text) {
JetProperty property = createProperty(project, "val x = " + text);
return property.getInitializer();
@@ -158,16 +162,25 @@ public class JetPsiFactory {
return (JetSimpleNameExpression) createProperty(project, name, null, false, name).getInitializer();
}
public static PsiElement createIdentifier(Project project, String name) {
return createSimpleName(project, name).getIdentifier();
}
public static JetNamedFunction createFunction(Project project, String funDecl) {
return createDeclaration(project, funDecl, JetNamedFunction.class);
}
public static JetModifierList createModifier(Project project, JetKeywordToken modifier) {
public static JetModifierList createModifierList(Project project, JetKeywordToken modifier) {
String text = modifier.getValue() + " val x";
JetProperty property = createProperty(project, text);
return property.getModifierList();
}
public static JetModifierList createConstructorModifierList(Project project, JetKeywordToken modifier) {
JetClass aClass = createClass(project, "class C " + modifier.getValue() + " (){}");
return aClass.getPrimaryConstructorModifierList();
}
public static JetExpression createEmptyBody(Project project) {
JetNamedFunction function = createFunction(project, "fun foo() {}");
return function.getBodyExpression();
@@ -183,6 +196,11 @@ public class JetPsiFactory {
return function.getValueParameters().get(0);
}
public static JetParameterList createParameterList(Project project, String text) {
JetNamedFunction function = createFunction(project, "fun foo" + text + "{}");
return function.getValueParameterList();
}
@NotNull
public static JetWhenEntry createWhenEntry(@NotNull Project project, @NotNull String entryText) {
JetNamedFunction function = createFunction(project, "fun foo() { when(12) { " + entryText + " } }");
@@ -36,7 +36,7 @@ abstract class JetTypeParameterListOwnerStub<T extends NamedStub> extends JetNam
}
@Nullable
JetTypeParameterList getTypeParameterList() {
public JetTypeParameterList getTypeParameterList() {
return (JetTypeParameterList) findChildByType(JetNodeTypes.TYPE_PARAMETER_LIST);
}
+1
View File
@@ -127,6 +127,7 @@
<quoteHandler fileType="Kotlin" className="org.jetbrains.jet.plugin.editor.KotlinQuoteHandler"/>
<refactoring.moveHandler implementation="org.jetbrains.jet.plugin.refactoring.move.JetMoveFilesOrDirectoriesHandler"/>
<refactoring.copyHandler implementation="org.jetbrains.jet.plugin.refactoring.copy.JetCopyClassHandler"/>
<refactoring.changeSignatureUsageProcessor implementation="org.jetbrains.jet.plugin.refactoring.changeSignature.JetChangeSignatureUsageProcessor"/>
<treeStructureProvider implementation="org.jetbrains.jet.plugin.projectView.JetProjectViewProvider"/>
<colorSettingsPage implementation="org.jetbrains.jet.plugin.highlighter.JetColorSettingsPage"/>
@@ -49,7 +49,10 @@ import org.jetbrains.jet.plugin.codeInsight.ReferenceToClassesShortening;
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
import org.jetbrains.jet.renderer.DescriptorRenderer;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
public class SpecifyTypeExplicitlyAction extends PsiElementBaseIntentionAction {
@NotNull
@@ -187,14 +190,24 @@ public class SpecifyTypeExplicitlyAction extends PsiElementBaseIntentionAction {
addTypeAnnotation(project, editor, property, anchor, exprType);
}
public static void addTypeAnnotation(Project project, Editor editor, JetFunction function, @NotNull JetType exprType) {
public static void addTypeAnnotation(Project project, @Nullable Editor editor, JetFunction function, @NotNull JetType exprType) {
JetParameterList valueParameterList = function.getValueParameterList();
assert valueParameterList != null;
addTypeAnnotation(project, editor, function, valueParameterList, exprType);
if (editor != null) {
addTypeAnnotation(project, editor, function, valueParameterList, exprType);
}
else {
addTypeAnnotationSilently(project, function, valueParameterList);
}
}
public static void addTypeAnnotation(Project project, Editor editor, JetParameter parameter, @NotNull JetType exprType) {
addTypeAnnotation(project, editor, parameter, parameter.getNameIdentifier(), exprType);
public static void addTypeAnnotation(Project project, @Nullable Editor editor, JetParameter parameter, @NotNull JetType exprType) {
if (editor != null) {
addTypeAnnotation(project, editor, parameter, parameter.getNameIdentifier(), exprType);
}
else {
addTypeAnnotationSilently(project, parameter, parameter.getNameIdentifier());
}
}
private static void addTypeAnnotation(
@@ -227,10 +240,7 @@ public class SpecifyTypeExplicitlyAction extends PsiElementBaseIntentionAction {
}
};
JetTypeReference typeReference = JetPsiFactory.createType(project, "Any");
namedDeclaration.addAfter(typeReference, anchor);
Pair<PsiElement, PsiElement> colon = JetPsiFactory.createColonAndWhiteSpaces(project);
namedDeclaration.addRangeAfter(colon.getFirst(), colon.getSecond(), anchor);
addTypeAnnotationSilently(project, namedDeclaration, anchor);
PsiDocumentManager.getInstance(project).commitAllDocuments();
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument());
@@ -250,6 +260,13 @@ public class SpecifyTypeExplicitlyAction extends PsiElementBaseIntentionAction {
});
}
private static void addTypeAnnotationSilently(Project project, JetNamedDeclaration namedDeclaration, PsiElement anchor) {
JetTypeReference typeReference = JetPsiFactory.createType(project, "Any");
namedDeclaration.addAfter(typeReference, anchor);
Pair<PsiElement, PsiElement> colon = JetPsiFactory.createColonAndWhiteSpaces(project);
namedDeclaration.addRangeAfter(colon.getFirst(), colon.getSecond(), anchor);
}
@Nullable
private static JetTypeReference getTypeRef(@NotNull JetNamedDeclaration namedDeclaration) {
if (namedDeclaration instanceof JetProperty) {
@@ -26,7 +26,10 @@ import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.psi.JetModifierList;
import org.jetbrains.jet.lang.psi.JetModifierListOwner;
import org.jetbrains.jet.lang.psi.JetPropertyAccessor;
import org.jetbrains.jet.lang.psi.JetPsiFactory;
import org.jetbrains.jet.lexer.JetKeywordToken;
import org.jetbrains.jet.lexer.JetToken;
import org.jetbrains.jet.lexer.JetTokens;
@@ -88,14 +91,29 @@ public class AddModifierFix extends JetIntentionAction<JetModifierListOwner> {
@NotNull
/*package*/ static JetModifierListOwner addModifier(@NotNull PsiElement element, @NotNull JetKeywordToken modifier, @Nullable JetToken[] modifiersThatCanBeReplaced, @NotNull Project project, boolean toBeginning) {
JetModifierListOwner newElement = (JetModifierListOwner) (element.copy());
changeModifier(newElement, newElement.getModifierList(), newElement.getFirstChild(),
modifiersThatCanBeReplaced, project, toBeginning, JetPsiFactory.createModifierList(project, modifier));
return newElement;
}
JetModifierList modifierList = newElement.getModifierList();
JetModifierList listWithModifier = JetPsiFactory.createModifier(project, modifier);
public static void changeModifier(
PsiElement element, @Nullable JetModifierList modifierList, @Nullable PsiElement insertAnchor,
JetToken[] modifiersThatCanBeReplaced, Project project, boolean toBeginning, JetModifierList listWithModifier
) {
PsiElement whiteSpace = JetPsiFactory.createWhiteSpace(project);
if (modifierList == null) {
PsiElement firstChild = newElement.getFirstChild();
newElement.addBefore(listWithModifier, firstChild);
newElement.addBefore(whiteSpace, firstChild);
if (listWithModifier != null) {
if (insertAnchor != null) {
listWithModifier = (JetModifierList) element.addBefore(listWithModifier, insertAnchor);
element.addBefore(whiteSpace, insertAnchor);
element.addBefore(whiteSpace, listWithModifier);
}
else {
PsiElement firstChild = element.getFirstChild();
element.addBefore(listWithModifier, firstChild);
element.addBefore(whiteSpace, firstChild);
}
}
}
else {
boolean replaced = false;
@@ -106,7 +124,7 @@ public class AddModifierFix extends JetIntentionAction<JetModifierListOwner> {
if (modifierList.hasModifier(modifierThatCanBeReplaced)) {
PsiElement modifierElement = modifierList.getModifierNode(modifierThatCanBeReplaced).getPsi();
assert modifierElement != null;
if (!replaced) {
if (!replaced && listWithModifier != null) {
toBeReplaced = modifierElement;
toReplace = listWithModifier.getFirstChild();
//modifierElement.replace(listWithModifier.getFirstChild());
@@ -121,7 +139,7 @@ public class AddModifierFix extends JetIntentionAction<JetModifierListOwner> {
toBeReplaced.replace(toReplace);
}
}
if (!replaced) {
if (!replaced && listWithModifier != null) {
if (toBeginning) {
PsiElement firstChild = modifierList.getFirstChild();
modifierList.addBefore(listWithModifier.getFirstChild(), firstChild);
@@ -134,7 +152,6 @@ public class AddModifierFix extends JetIntentionAction<JetModifierListOwner> {
}
}
}
return newElement;
}
@NotNull
@@ -77,21 +77,25 @@ public class ChangeFunctionReturnTypeFix extends JetIntentionAction<JetNamedFunc
}
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
public void invoke(@NotNull Project project, @Nullable Editor editor, @Nullable PsiFile file) throws IncorrectOperationException {
SpecifyTypeExplicitlyAction.removeTypeAnnotation(element);
if (!(KotlinBuiltIns.getInstance().isUnit(type) && element.hasBlockBody())) {
PsiElement elementToPrecedeType = element.getValueParameterList();
if (elementToPrecedeType == null) elementToPrecedeType = element.getNameIdentifier();
assert elementToPrecedeType != null : "Return type of function without name can't mismatch anything";
if (elementToPrecedeType.getNextSibling() instanceof PsiErrorElement) {
// if a function doesn't have a value parameter list, a syntax error is raised, and it should follow the function name
elementToPrecedeType = elementToPrecedeType.getNextSibling();
}
Pair<PsiElement, PsiElement> typeWhiteSpaceAndColon = JetPsiFactory.createTypeWhiteSpaceAndColon(project, type.toString());
element.addRangeAfter(typeWhiteSpaceAndColon.first, typeWhiteSpaceAndColon.second, elementToPrecedeType);
addReturnTypeAnnotation(project, element, type.toString());
}
}
public static void addReturnTypeAnnotation(Project project, JetFunction function, String typeText) {
PsiElement elementToPrecedeType = function.getValueParameterList();
if (elementToPrecedeType == null) elementToPrecedeType = function.getNameIdentifier();
assert elementToPrecedeType != null : "Return type of function without name can't mismatch anything";
if (elementToPrecedeType.getNextSibling() instanceof PsiErrorElement) {
// if a function doesn't have a value parameter list, a syntax error is raised, and it should follow the function name
elementToPrecedeType = elementToPrecedeType.getNextSibling();
}
Pair<PsiElement, PsiElement> typeWhiteSpaceAndColon = JetPsiFactory.createTypeWhiteSpaceAndColon(project, typeText);
function.addRangeAfter(typeWhiteSpaceAndColon.first, typeWhiteSpaceAndColon.second, elementToPrecedeType);
}
@NotNull
public static JetMultiDeclarationEntry getMultiDeclarationEntryThatTypeMismatchComponentFunction(Diagnostic diagnostic) {
String componentName = ((DiagnosticWithParameters3<JetExpression, Name, JetType, JetType>) diagnostic).getA().getName();
@@ -22,19 +22,25 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.Visibilities;
import org.jetbrains.jet.lang.descriptors.Visibility;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetModifierListOwner;
import org.jetbrains.jet.lang.psi.JetParameter;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lexer.JetKeywordToken;
import org.jetbrains.jet.lexer.JetToken;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.JetBundle;
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
import org.jetbrains.jet.plugin.refactoring.JetRefactoringUtil;
public class ChangeVisibilityModifierFix extends JetIntentionAction<JetModifierListOwner> {
public static final JetKeywordToken[] VISIBILITY_TOKENS =
new JetKeywordToken[] {JetTokens.PUBLIC_KEYWORD, JetTokens.PRIVATE_KEYWORD, JetTokens.PROTECTED_KEYWORD, JetTokens.INTERNAL_KEYWORD};
public ChangeVisibilityModifierFix(@NotNull JetModifierListOwner element) {
super(element);
}
@@ -61,8 +67,7 @@ public class ChangeVisibilityModifierFix extends JetIntentionAction<JetModifierL
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
if (!(file instanceof JetFile)) return;
JetKeywordToken modifier = findVisibilityChangeTo((JetFile)file);
JetToken[] modifiersThanCanBeReplaced = new JetKeywordToken[] { JetTokens.PUBLIC_KEYWORD, JetTokens.PRIVATE_KEYWORD, JetTokens.PROTECTED_KEYWORD, JetTokens.INTERNAL_KEYWORD };
element.replace(AddModifierFix.addModifier(element, modifier, modifiersThanCanBeReplaced, project, true));
element.replace(AddModifierFix.addModifier(element, modifier, VISIBILITY_TOKENS, project, true));
}
private JetKeywordToken findVisibilityChangeTo(JetFile file) {
@@ -95,17 +100,7 @@ public class ChangeVisibilityModifierFix extends JetIntentionAction<JetModifierL
if (maxVisibility == memberDescriptor.getVisibility()) {
return null;
}
JetKeywordToken modifier = null;
if (maxVisibility == Visibilities.PUBLIC) {
modifier = JetTokens.PUBLIC_KEYWORD;
}
else if (maxVisibility == Visibilities.PROTECTED) {
modifier = JetTokens.PROTECTED_KEYWORD;
}
else if (maxVisibility == Visibilities.INTERNAL) {
modifier = JetTokens.INTERNAL_KEYWORD;
}
return modifier;
return JetRefactoringUtil.getVisibilityToken(maxVisibility);
}
public static JetIntentionActionFactory createFactory() {
@@ -9,3 +9,12 @@ cannot.refactor.namespace.expression=Cannot intoduce namespace reference
cannot.extract.method=Cannot find statements to extract
cannot.find.class.to.extract=Cannot find class to extract method
cannot.refactor.expression.should.have.inferred.type=Expression should have inferred type
error.wrong.caret.position.function.or.constructor.name=The caret should be positioned at the name of the function or constructor to be refactored.
error.cant.refactor.vararg.functions=Can't refactor the function with variable arguments
function.name.is.invalid=Function name is invalid
return.type.is.invalid=Return type is invalid
parameter.name.is.invalid=Parameter name ''{0}'' is invalid
parameter.type.is.invalid=Parameter type ''{0}'' is invalid
column.name.val.var=Val/Var
@@ -19,8 +19,11 @@ package org.jetbrains.jet.plugin.refactoring;
import com.intellij.lang.refactoring.RefactoringSupportProvider;
import com.intellij.psi.PsiElement;
import com.intellij.refactoring.RefactoringActionHandler;
import com.intellij.refactoring.changeSignature.ChangeSignatureHandler;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetFunction;
import org.jetbrains.jet.lang.psi.JetProperty;
import org.jetbrains.jet.plugin.refactoring.changeSignature.JetChangeSignatureHandler;
import org.jetbrains.jet.plugin.refactoring.introduceVariable.JetIntroduceVariableHandler;
/**
@@ -45,4 +48,10 @@ public class JetRefactoringSupportProvider extends RefactoringSupportProvider {
}
return false;
}
@Nullable
@Override
public ChangeSignatureHandler getChangeSignatureHandler() {
return new JetChangeSignatureHandler();
}
}
@@ -27,12 +27,16 @@ import com.intellij.psi.PsiWhiteSpace;
import com.intellij.ui.components.JBList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.Visibilities;
import org.jetbrains.jet.lang.descriptors.Visibility;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.NamespaceType;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.lexer.JetKeywordToken;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.codeInsight.CodeInsightUtils;
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
@@ -51,6 +55,23 @@ public class JetRefactoringUtil {
private JetRefactoringUtil() {
}
public static JetKeywordToken getVisibilityToken(Visibility visibility) {
if (visibility == Visibilities.PUBLIC) {
return JetTokens.PUBLIC_KEYWORD;
}
else if (visibility == Visibilities.PROTECTED) {
return JetTokens.PROTECTED_KEYWORD;
}
else if (visibility == Visibilities.INTERNAL) {
return JetTokens.INTERNAL_KEYWORD;
}
else if (visibility == Visibilities.PRIVATE) {
return JetTokens.PRIVATE_KEYWORD;
}
throw new IllegalArgumentException("Unexpected visibility '" + visibility + "'");
}
public interface SelectExpressionCallback {
void run(@Nullable JetExpression expression);
}
@@ -0,0 +1,234 @@
/*
* 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.lang.Language;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.refactoring.changeSignature.ChangeInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.Visibilities;
import org.jetbrains.jet.lang.descriptors.Visibility;
import org.jetbrains.jet.lang.psi.JetFunction;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.JetLanguage;
import java.util.List;
public class JetChangeInfo implements ChangeInfo {
private final JetFunctionPlatformDescriptor oldDescriptor;
private String newName;
private final JetType newReturnType;
private String newReturnTypeText;
private Visibility newVisibility;
private final List<JetParameterInfo> newParameters;
private final PsiElement context;
private final JetGeneratedInfo generatedInfo;
private Boolean parameterNamesChanged;
public JetChangeInfo(
JetFunctionPlatformDescriptor oldDescriptor,
String newName,
JetType newReturnType,
String newReturnTypeText,
Visibility newVisibility,
List<JetParameterInfo> newParameters,
PsiElement context,
JetGeneratedInfo generatedInfo
) {
this.oldDescriptor = oldDescriptor;
this.newName = newName;
this.newReturnType = newReturnType;
this.newReturnTypeText = newReturnTypeText;
this.newVisibility = newVisibility;
this.newParameters = newParameters;
this.context = context;
this.generatedInfo = generatedInfo;
}
public String getNewSignature(@Nullable JetFunction inheritedFunction, boolean isInherited) {
StringBuilder buffer = new StringBuilder();
if (isConstructor()) {
buffer.append(newName);
if (newVisibility != null && newVisibility != Visibilities.PUBLIC)
buffer.append(' ').append(newVisibility.toString()).append(' ');
}
else {
if (newVisibility != null && newVisibility != Visibilities.INTERNAL)
buffer.append(newVisibility.toString()).append(' ');
buffer.append(JetTokens.FUN_KEYWORD).append(' ').append(newName);
}
buffer.append(getNewParametersSignature(inheritedFunction, isInherited, buffer.length()));
if (newReturnType != null && !KotlinBuiltIns.getInstance().isUnit(newReturnType) && !isConstructor())
buffer.append(": ").append(newReturnTypeText);
return buffer.toString();
}
public String getNewParametersSignature(PsiElement inheritedFunction, boolean isInherited, int indentLength) {
StringBuilder buffer = new StringBuilder("(");
String indent = StringUtil.repeatSymbol(' ', indentLength + 1);
for (int i = 0; i < newParameters.size(); i++) {
JetParameterInfo parameterInfo = newParameters.get(i);
if (i > 0) {
buffer.append(",");
buffer.append("\n");
buffer.append(indent);
}
buffer.append(parameterInfo.getDeclarationSignature(isInherited, inheritedFunction, oldDescriptor));
}
buffer.append(")");
return buffer.toString();
}
private boolean innerParameterSetOrOrderChanged() {
if (newParameters.size() != oldDescriptor.getParametersCount())
return true;
for (int i = 0; i < newParameters.size(); i ++) {
if (newParameters.get(i).getOldIndex() != i)
return true;
}
return false;
}
@NotNull
@Override
public JetParameterInfo[] getNewParameters() {
return newParameters.toArray(new JetParameterInfo[newParameters.size()]);
}
public void setNewParameter(int index, JetParameterInfo parameterInfo) {
newParameters.set(index, parameterInfo);
}
public void addParameter(JetParameterInfo parameterInfo) {
newParameters.add(parameterInfo);
}
@Override
public boolean isParameterSetOrOrderChanged() {
if (parameterNamesChanged == null)
parameterNamesChanged = innerParameterSetOrOrderChanged();
return parameterNamesChanged;
}
@Override
public boolean isParameterTypesChanged() {
return true;
}
@Override
public boolean isParameterNamesChanged() {
return true;
}
@Override
public boolean isGenerateDelegate() {
return false;
}
public void setNewName(String newName) {
this.newName = newName;
}
@Override
public boolean isNameChanged() {
return !newName.equals(oldDescriptor.getName());
}
public boolean isVisibilityChanged() {
return !newVisibility.equals(oldDescriptor.getVisibility());
}
public Visibility getNewVisibility() {
return newVisibility;
}
public void setNewVisibility(Visibility newVisibility) {
this.newVisibility = newVisibility;
}
@Override
public PsiElement getMethod() {
return oldDescriptor.getMethod();
}
@Nullable
public FunctionDescriptor getOldDescriptor() {
return oldDescriptor.getDescriptor();
}
public JetFunctionPlatformDescriptor getFunctionDescriptor() {
return oldDescriptor;
}
public boolean isConstructor() {
return oldDescriptor.isConstructor();
}
public String getNewReturnTypeText() {
return newReturnTypeText;
}
public void setNewReturnTypeText(String newReturnTypeText) {
this.newReturnTypeText = newReturnTypeText;
}
@Override
public boolean isReturnTypeChanged() {
return !newReturnTypeText.equals(oldDescriptor.getReturnTypeText());
}
@Nullable
public String getOldName() {
PsiElement function = oldDescriptor.getMethod();
return function instanceof JetFunction ? ((JetFunction) function).getName() : null;
}
@Override
public String getNewName() {
return newName;
}
public JetGeneratedInfo getGeneratedInfo() {
return generatedInfo;
}
public PsiElement getContext() {
return context;
}
@Override
public Language getLanguage() {
return JetLanguage.INSTANCE;
}
}
@@ -0,0 +1,419 @@
/*
* 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.openapi.editor.Document;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.EditorFontType;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.fileTypes.LanguageFileType;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.VerticalFlowLayout;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiCodeFragment;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.refactoring.BaseRefactoringProcessor;
import com.intellij.refactoring.changeSignature.CallerChooserBase;
import com.intellij.refactoring.changeSignature.ChangeSignatureDialogBase;
import com.intellij.refactoring.changeSignature.MethodDescriptor;
import com.intellij.refactoring.changeSignature.ParameterTableModelItemBase;
import com.intellij.refactoring.ui.ComboBoxVisibilityPanel;
import com.intellij.refactoring.ui.VisibilityPanelBase;
import com.intellij.ui.DottedBorder;
import com.intellij.ui.EditorTextField;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.treeStructure.Tree;
import com.intellij.util.Consumer;
import com.intellij.util.Function;
import com.intellij.util.IJSwingUtilities;
import com.intellij.util.ui.ColumnInfo;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.table.JBTableRow;
import com.intellij.util.ui.table.JBTableRowEditor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.Visibilities;
import org.jetbrains.jet.lang.descriptors.Visibility;
import org.jetbrains.jet.lang.psi.JetPsiFactory;
import org.jetbrains.jet.lang.psi.JetTypeCodeFragment;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.plugin.JetFileType;
import org.jetbrains.jet.plugin.refactoring.JetRefactoringBundle;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class JetChangeSignatureDialog extends ChangeSignatureDialogBase<
JetParameterInfo,
PsiElement,
Visibility,
JetFunctionPlatformDescriptor,
ParameterTableModelItemBase<JetParameterInfo>,
JetFunctionParameterTableModel
>
{
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);
this.commandName = commandName;
}
@Override
protected LanguageFileType getFileType() {
return JetFileType.INSTANCE;
}
@Override
protected JetFunctionParameterTableModel createParametersInfoModel(JetFunctionPlatformDescriptor descriptor) {
if (descriptor.isConstructor())
return new JetConstructorParameterTableModel(myDefaultValueContext);
else
return new JetFunctionParameterTableModel(myDefaultValueContext);
}
@Override
protected PsiCodeFragment createReturnTypeCodeFragment() {
return JetPsiFactory.createTypeCodeFragment(myProject, myMethod.getReturnTypeText(), myMethod.getContext());
}
@Nullable
public JetType getReturnType() {
return getType((JetTypeCodeFragment) myReturnTypeCodeFragment);
}
private static JetType getType(JetTypeCodeFragment typeCodeFragment) {
return typeCodeFragment != null ? typeCodeFragment.getType() : null;
}
@Override
protected JComponent getRowPresentation(ParameterTableModelItemBase<JetParameterInfo> item, boolean selected, boolean focused) {
JPanel panel = new JPanel(new BorderLayout());
String valOrVar = "";
if (myMethod.isConstructor()) {
switch (item.parameter.getValOrVar()) {
case None:
valOrVar = " ";
break;
case Val:
valOrVar = "val ";
break;
case Var:
valOrVar = "var ";
break;
}
}
String parameterName = item.parameter.getName();
String typeText = item.typeCodeFragment.getText();
String defaultValue = item.defaultValueCodeFragment.getText();
String separator = StringUtil.repeatSymbol(' ', getParamNamesMaxLength() - parameterName.length() + 1);
String text = valOrVar + parameterName + ":" + separator + typeText;
if (StringUtil.isNotEmpty(defaultValue))
text += " // default value = " + defaultValue;
EditorTextField field = new EditorTextField(" " + text, getProject(), getFileType()) {
@Override
protected boolean shouldHaveBorder() {
return false;
}
};
Font font = EditorColorsManager.getInstance().getGlobalScheme().getFont(EditorFontType.PLAIN);
font = new Font(font.getFontName(), font.getStyle(), 12);
field.setFont(font);
if (selected && focused) {
panel.setBackground(UIUtil.getTableSelectionBackground());
field.setAsRendererWithSelection(UIUtil.getTableSelectionBackground(), UIUtil.getTableSelectionForeground());
} else {
panel.setBackground(UIUtil.getTableBackground());
if (selected && !focused) {
panel.setBorder(new DottedBorder(UIUtil.getTableForeground()));
}
}
panel.add(field, BorderLayout.WEST);
return panel;
}
private int getColumnTextMaxLength(Function<ParameterTableModelItemBase<JetParameterInfo>, String> nameFunction) {
int len = 0;
for (ParameterTableModelItemBase<JetParameterInfo> item : myParametersTableModel.getItems()) {
String text = nameFunction.fun(item);
len = Math.max(len, text == null ? 0 : text.length());
}
return len;
}
private int getParamNamesMaxLength() {
return getColumnTextMaxLength(new Function<ParameterTableModelItemBase<JetParameterInfo>, String>() {
@Override
public String fun(ParameterTableModelItemBase<JetParameterInfo> item) {
return item.parameter == null ? null : item.parameter.getName();
}
});
}
private int getTypesMaxLength() {
return getColumnTextMaxLength(new Function<ParameterTableModelItemBase<JetParameterInfo>, String>() {
@Override
public String fun(ParameterTableModelItemBase<JetParameterInfo> item) {
return item.typeCodeFragment == null ? null : item.typeCodeFragment.getText();
}
});
}
private int getDefaultValuesMaxLength() {
return getColumnTextMaxLength(new Function<ParameterTableModelItemBase<JetParameterInfo>, String>() {
@Override
public String fun(ParameterTableModelItemBase<JetParameterInfo> item) {
return item.defaultValueCodeFragment == null ? null : item.defaultValueCodeFragment.getText();
}
});
}
@Override
protected boolean isListTableViewSupported() {
return true;
}
@Override
protected boolean isEmptyRow(ParameterTableModelItemBase<JetParameterInfo> row) {
if (!StringUtil.isEmpty(row.parameter.getName())) return false;
if (!StringUtil.isEmpty(row.parameter.getTypeText())) return false;
return true;
}
@Nullable
@Override
protected CallerChooserBase<PsiElement> createCallerChooser(String title, Tree treeToReuse, Consumer<Set<PsiElement>> callback) {
throw new UnsupportedOperationException();
}
@Override
protected JBTableRowEditor getTableEditor(final JTable t, final ParameterTableModelItemBase<JetParameterInfo> item) {
return new JBTableRowEditor() {
private final List<JComponent> components = new ArrayList<JComponent>();
private final boolean defaultValueColumnEnabled = item.parameter.isNewParameter();
@Override
public void prepareEditor(JTable table, final int row) {
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
int column = 0;
for (ColumnInfo columnInfo : myParametersTableModel.getColumnInfos()) {
JPanel panel = new JPanel(new VerticalFlowLayout(VerticalFlowLayout.TOP, 4, 2, true, false));
EditorTextField editor = null;
JComponent component;
final int columnFinal = column;
if (JetFunctionParameterTableModel.isTypeColumn(columnInfo)) {
Document document = PsiDocumentManager.getInstance(getProject()).getDocument(item.typeCodeFragment);
component = editor = new EditorTextField(document, getProject(), getFileType());
}
else if (JetFunctionParameterTableModel.isNameColumn(columnInfo))
component = editor = new EditorTextField((String)columnInfo.valueOf(item), getProject(), getFileType());
else if (JetFunctionParameterTableModel.isDefaultValueColumn(columnInfo) && defaultValueColumnEnabled) {
Document document = PsiDocumentManager.getInstance(getProject()).getDocument(item.defaultValueCodeFragment);
component = editor = new EditorTextField(document, getProject(), getFileType());
}
else if (JetConstructorParameterTableModel.isValVarColumn(columnInfo)) {
JComboBox comboBox = new JComboBox(JetValVar.values());
comboBox.setSelectedItem(item.parameter.getValOrVar());
comboBox.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(@NotNull ItemEvent e) {
myParametersTableModel.setValueAtWithoutUpdate(e.getItem(), row, columnFinal);
updateSignature();
}
});
component = comboBox;
}
else
continue;
JBLabel label = new JBLabel(columnInfo.getName(), UIUtil.ComponentStyle.SMALL);
panel.add(label);
if (editor != null) {
editor.addDocumentListener(new DocumentAdapter() {
@Override
public void documentChanged(DocumentEvent e) {
fireDocumentChanged(e, columnFinal);
}
});
editor.setPreferredWidth(t.getWidth() / myParametersTableModel.getColumnCount());
}
components.add(component);
panel.add(component);
add(panel);
IJSwingUtilities.adjustComponentsOnMac(label, component);
column++;
}
}
@Override
public JBTableRow getValue() {
return new JBTableRow() {
@Override
public Object getValueAt(int column) {
ColumnInfo columnInfo = myParametersTableModel.getColumnInfos()[column];
if (JetConstructorParameterTableModel.isValVarColumn(columnInfo))
return ((JComboBox) components.get(column)).getSelectedItem();
else if (JetFunctionParameterTableModel.isTypeColumn(columnInfo))
return item.typeCodeFragment;
else if (JetFunctionParameterTableModel.isNameColumn(columnInfo))
return ((EditorTextField) components.get(column)).getText();
else if (JetFunctionParameterTableModel.isDefaultValueColumn(columnInfo))
return item.defaultValueCodeFragment;
else
return null;
}
};
}
private int getColumnWidth(int letters) {
Font font = EditorColorsManager.getInstance().getGlobalScheme().getFont(EditorFontType.PLAIN);
font = new Font(font.getFontName(), font.getStyle(), 12);
return letters * Toolkit.getDefaultToolkit().getFontMetrics(font).stringWidth("W");
}
private int getEditorIndex(int x) {
int[] columnLetters = defaultValueColumnEnabled ?
new int[] { 4, getParamNamesMaxLength(), getTypesMaxLength(), getDefaultValuesMaxLength() } :
new int[] { 4, getParamNamesMaxLength(), getTypesMaxLength() };
int columnIndex = 0;
for (int i = myMethod.isConstructor() ? 0 : 1; i < columnLetters.length; i ++) {
int width = getColumnWidth(columnLetters[i]);
if (x <= width)
return columnIndex;
columnIndex ++;
x -= width;
}
return columnIndex - 1;
}
@Override
public JComponent getPreferredFocusedComponent() {
MouseEvent me = getMouseEvent();
int index = me != null ? getEditorIndex((int) me.getPoint().getX()) : myMethod.isConstructor() ? 1 : 0;
JComponent component = components.get(index);
return component instanceof EditorTextField ? ((EditorTextField) component).getFocusTarget() : component;
}
@Override
public JComponent[] getFocusableComponents() {
JComponent[] focusable = new JComponent[components.size()];
for (int i = 0; i < components.size(); i++) {
focusable[i] = components.get(i);
if (focusable[i] instanceof EditorTextField)
focusable[i] = ((EditorTextField) focusable[i]).getFocusTarget();
}
return focusable;
}
};
}
@Override
protected String calculateSignature() {
JetChangeInfo changeInfo = evaluateChangeInfo();
return changeInfo.getNewSignature(null, false);
}
@Override
protected VisibilityPanelBase<Visibility> createVisibilityControl() {
return new ComboBoxVisibilityPanel<Visibility>(new Visibility[]{
Visibilities.INTERNAL, Visibilities.PRIVATE, Visibilities.PROTECTED, Visibilities.PUBLIC }
);
}
@Override
protected void updateSignatureAlarmFired() {
super.updateSignatureAlarmFired();
validateButtons();
}
@Nullable
@Override
protected String validateAndCommitData() {
return null;
}
@Override
protected void canRun() throws ConfigurationException {
if (myNamePanel.isVisible() && myMethod.canChangeName() && !JavaPsiFacade.getInstance(myProject).getNameHelper().isIdentifier(getMethodName()))
throw new ConfigurationException(JetRefactoringBundle.message("function.name.is.invalid"));
if (myMethod.canChangeReturnType() == MethodDescriptor.ReadWriteOption.ReadWrite && getReturnType() == null)
throw new ConfigurationException(JetRefactoringBundle.message("return.type.is.invalid"));
List<ParameterTableModelItemBase<JetParameterInfo>> parameterInfos = myParametersTableModel.getItems();
for (ParameterTableModelItemBase<JetParameterInfo> item : parameterInfos) {
String parameterName = item.parameter.getName();
if (!JavaPsiFacade.getInstance(myProject).getNameHelper().isIdentifier(parameterName))
throw new ConfigurationException(JetRefactoringBundle.message("parameter.name.is.invalid", parameterName));
if (getType((JetTypeCodeFragment) item.typeCodeFragment) == null)
throw new ConfigurationException(JetRefactoringBundle.message("parameter.type.is.invalid", item.typeCodeFragment.getText()));
}
}
@Override
protected BaseRefactoringProcessor createRefactoringProcessor() {
return new JetChangeSignatureProcessor(myProject, evaluateChangeInfo(), commandName != null ? commandName : getTitle());
}
public JetChangeInfo evaluateChangeInfo() {
List<JetParameterInfo> parameters = getParameters();
for (int i = 0; i < parameters.size(); i++) {
JetParameterInfo parameter = parameters.get(i);
parameter.setTypeText(myParametersTableModel.getItems().get(i).typeCodeFragment.getText().trim());
parameter.setDefaultValueText(myParametersTableModel.getItems().get(i).defaultValueCodeFragment.getText().trim());
}
String returnTypeText = myReturnTypeCodeFragment != null ? myReturnTypeCodeFragment.getText().trim() : "";
return new JetChangeInfo(myMethod, getMethodName(), getReturnType(), returnTypeText,
getVisibility(), parameters, myDefaultValueContext, generatedInfo);
}
}
@@ -0,0 +1,155 @@
/*
* 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.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.ScrollType;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.HelpID;
import com.intellij.refactoring.RefactoringBundle;
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.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;
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) {
if (PsiTreeUtil.getParentOfType(element, JetParameterList.class) != null) {
return PsiTreeUtil.getParentOfType(element, JetFunction.class, JetClass.class);
}
JetTypeParameterList typeParameterList = PsiTreeUtil.getParentOfType(element, JetTypeParameterList.class);
if (typeParameterList != null) {
return PsiTreeUtil.getParentOfType(typeParameterList, JetFunction.class, JetClass.class);
}
PsiElement elementParent = element.getParent();
if (elementParent instanceof JetNamedFunction && ((JetNamedFunction)elementParent).getNameIdentifier()==element) {
return elementParent;
}
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 (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;
}
}
}
}
return null;
}
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) {
editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
PsiElement element = findTargetMember(file, editor);
if (element == null) {
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();
}
}
}
@Override
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();
}
}
@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);
if (descriptor instanceof ClassDescriptor) {
descriptor = ((ClassDescriptor) descriptor).getUnsubstitutedPrimaryConstructor();
}
if (descriptor instanceof FunctionDescriptorImpl) {
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);
return null;
}
}
return new JetChangeSignatureDialog(project, new JetFunctionPlatformDescriptorImpl((FunctionDescriptor) descriptor, element), context);
}
else {
String message = RefactoringBundle.getCannotRefactorMessage(JetRefactoringBundle.message(
"error.wrong.caret.position.function.or.constructor.name"));
CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.CHANGE_SIGNATURE);
return null;
}
}
@Nullable
@Override
public String getTargetNotFoundMessage() {
return JetRefactoringBundle.message("error.wrong.caret.position.function.or.constructor.name");
}
}
@@ -0,0 +1,124 @@
/*
* 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.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiElement;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.changeSignature.ChangeSignatureProcessorBase;
import com.intellij.refactoring.changeSignature.ChangeSignatureUsageProcessor;
import com.intellij.refactoring.rename.RenameUtil;
import com.intellij.refactoring.ui.ConflictsDialog;
import com.intellij.usageView.UsageInfo;
import com.intellij.usageView.UsageViewDescriptor;
import com.intellij.util.containers.HashSet;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
import java.util.*;
public class JetChangeSignatureProcessor extends ChangeSignatureProcessorBase {
private final String commandName;
public JetChangeSignatureProcessor(Project project, JetChangeInfo changeInfo, String commandName) {
super(project, changeInfo);
this.commandName = commandName;
}
@NotNull
@Override
protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) {
String subject = getChangeInfo().isConstructor() ? "constructor" : "function";
return new JetUsagesViewDescriptor(myChangeInfo.getMethod(), RefactoringBundle.message("0.to.change.signature", subject));
}
@Override
public JetChangeInfo getChangeInfo() {
return (JetChangeInfo) super.getChangeInfo();
}
@Override
protected boolean preprocessUsages(Ref<UsageInfo[]> refUsages) {
for (ChangeSignatureUsageProcessor processor : ChangeSignatureUsageProcessor.EP_NAME.getExtensions()) {
if (!processor.setupDefaultValues(myChangeInfo, refUsages, myProject)) return false;
}
MultiMap<PsiElement, String> conflictDescriptions = new MultiMap<PsiElement, String>();
for (ChangeSignatureUsageProcessor usageProcessor : ChangeSignatureUsageProcessor.EP_NAME.getExtensions()) {
MultiMap<PsiElement, String> conflicts = usageProcessor.findConflicts(myChangeInfo, refUsages);
for (PsiElement key : conflicts.keySet()) {
Collection<String> collection = conflictDescriptions.get(key);
if (collection.size() == 0) collection = new HashSet<String>();
collection.addAll(conflicts.get(key));
conflictDescriptions.put(key, collection);
}
}
UsageInfo[] usagesIn = refUsages.get();
RenameUtil.addConflictDescriptions(usagesIn, conflictDescriptions);
Set<UsageInfo> usagesSet = new HashSet<UsageInfo>(Arrays.asList(usagesIn));
RenameUtil.removeConflictUsages(usagesSet);
if (!conflictDescriptions.isEmpty()) {
if (ApplicationManager.getApplication().isUnitTestMode()) {
throw new ConflictsInTestsException(conflictDescriptions.values());
}
if (myPrepareSuccessfulSwingThreadCallback != null) {
ConflictsDialog dialog = prepareConflictsDialog(conflictDescriptions, usagesIn);
dialog.show();
if (!dialog.isOK()) {
if (dialog.isShowConflicts()) prepareSuccessful();
return false;
}
}
}
UsageInfo[] array = usagesSet.toArray(new UsageInfo[usagesSet.size()]);
Arrays.sort(array, new Comparator<UsageInfo>() {
@Override
public int compare(@NotNull UsageInfo u1, @NotNull UsageInfo u2) {
PsiElement element1 = u1.getElement();
PsiElement element2 = u2.getElement();
int rank1 = element1 != null ? element1.getTextOffset() : -1;
int rank2 = element2 != null ? element2.getTextOffset() : -1;
return rank2 - rank1; // Reverse order
}
});
refUsages.set(array);
prepareSuccessful();
return true;
}
@Override
protected boolean isPreviewUsages(UsageInfo[] usages) {
return isPreviewUsages();
}
@NotNull
@Override
protected Collection<? extends PsiElement> getElementsToWrite(@NotNull UsageViewDescriptor descriptor) {
Collection<PsiElement> elements = new ArrayList<PsiElement>();
elements.addAll(super.getElementsToWrite(descriptor));
elements.addAll(getChangeInfo().getGeneratedInfo().getFilesToWrite());
return elements;
}
@Override
protected String getCommandName() {
return commandName;
}
}
@@ -0,0 +1,252 @@
/*
* 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.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.refactoring.changeSignature.ChangeInfo;
import com.intellij.refactoring.changeSignature.ChangeSignatureUsageProcessor;
import com.intellij.refactoring.changeSignature.ParameterInfo;
import com.intellij.refactoring.rename.ResolveSnapshotProvider;
import com.intellij.refactoring.util.TextOccurrencesUtil;
import com.intellij.usageView.UsageInfo;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashSet;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
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.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeProjection;
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
import org.jetbrains.jet.plugin.refactoring.changeSignature.usages.JetFunctionCallUsage;
import org.jetbrains.jet.plugin.refactoring.changeSignature.usages.JetFunctionDefinitionUsage;
import org.jetbrains.jet.plugin.refactoring.changeSignature.usages.JetParameterUsage;
import org.jetbrains.jet.plugin.refactoring.changeSignature.usages.JetUsageInfo;
import org.jetbrains.jet.renderer.DescriptorRenderer;
import java.util.Collections;
import java.util.List;
import java.util.Set;
public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsageProcessor {
@Override
public UsageInfo[] findUsages(ChangeInfo info) {
Set<UsageInfo> result = new HashSet<UsageInfo>();
findAllMethodUsages((JetChangeInfo)info, result);
return result.toArray(new UsageInfo[result.size()]);
}
private static void findAllMethodUsages(JetChangeInfo changeInfo, Set<UsageInfo> result) {
PsiElement method = changeInfo.getMethod();
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,
Set<UsageInfo> result, boolean isInherited) {
result.add(new JetFunctionDefinitionUsage(functionPsi, isInherited));
for (PsiReference reference : ReferencesSearch.search(functionPsi, functionPsi.getUseScope())) {
PsiElement element = reference.getElement();
PsiElement parent = element.getParent();
if (parent instanceof JetReferenceExpression) {
parent = parent.getParent();
if (parent instanceof JetCallExpression)
result.add(new JetFunctionCallUsage((JetCallExpression) parent, functionPsi, isInherited));
else if (parent instanceof JetUserType && parent.getParent() instanceof JetTypeReference) {
parent = parent.getParent().getParent();
if (parent instanceof JetConstructorCalleeExpression && parent.getParent() instanceof JetDelegatorToSuperCall)
result.add(new JetFunctionCallUsage((JetDelegatorToSuperCall)parent.getParent(), functionPsi, isInherited));
}
}
}
String oldName = changeInfo.getOldName();
if (oldName != null)
TextOccurrencesUtil.findNonCodeUsages(functionPsi, oldName, true, true, changeInfo.getNewName(), result);
List<JetParameter> oldParameters = functionPsi instanceof JetFunction
? ((JetFunction) functionPsi).getValueParameters()
: ((JetClass) functionPsi).getPrimaryConstructorParameters();
for (JetParameterInfo parameterInfo : changeInfo.getNewParameters()) {
if (parameterInfo.getOldIndex() >= 0 && parameterInfo.getOldIndex() < oldParameters.size()) {
JetParameter oldParam = oldParameters.get(parameterInfo.getOldIndex());
String oldParamName = oldParam.getName();
if (oldParamName != null && !oldParamName.equals(parameterInfo.getName())) {
for (PsiReference reference : ReferencesSearch.search(oldParam, oldParam.getUseScope())) {
PsiElement element = reference.getElement();
if (element.getParent() instanceof JetSimpleNameExpression)
result.add(new JetParameterUsage((JetSimpleNameExpression) element.getParent(), parameterInfo, functionPsi, isInherited));
}
}
}
}
}
@Override
public MultiMap<PsiElement, String> findConflicts(ChangeInfo info, Ref<UsageInfo[]> refUsages) {
MultiMap<PsiElement, String> result = new MultiMap<PsiElement, String>();
Set<String> parameterNames = new HashSet<String>();
JetChangeInfo changeInfo = (JetChangeInfo) info;
PsiElement function = info.getMethod();
PsiElement element = function != null ? function : changeInfo.getContext();
BindingContext bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile)element.getContainingFile()).getBindingContext();
FunctionDescriptor oldDescriptor = changeInfo.getOldDescriptor();
JetScope parametersScope = null;
DeclarationDescriptor containingDeclaration = oldDescriptor != null ? oldDescriptor.getContainingDeclaration() : null;
if (oldDescriptor instanceof ConstructorDescriptor && containingDeclaration instanceof ClassDescriptor)
parametersScope = ((ClassDescriptor) containingDeclaration).getMemberScope(Collections.<TypeProjection>emptyList());
else if (function instanceof JetFunction)
parametersScope = getFunctionBodyScope((JetFunction) function, bindingContext);
JetScope functionScope = getFunctionScope(bindingContext, containingDeclaration);
if (!changeInfo.isConstructor() && functionScope != null && !info.getNewName().isEmpty()) {
for (FunctionDescriptor conflict : functionScope.getFunctions(Name.identifier(info.getNewName()))) {
if (conflict != oldDescriptor && getFunctionParameterTypes(conflict).equals(getFunctionParameterTypes(oldDescriptor))) {
PsiElement conflictElement = BindingContextUtils.descriptorToDeclaration(bindingContext, conflict);
result.putValue(conflictElement, "Function already exists: '" + DescriptorRenderer.SHORT_NAMES_IN_TYPES.render(conflict) + "'");
break;
}
}
}
for (ParameterInfo parameter : info.getNewParameters()) {
JetValVar valOrVar = ((JetParameterInfo) parameter).getValOrVar();
String parameterName = parameter.getName();
if (!parameterNames.add(parameterName)) {
result.putValue(element, "Duplicating parameter '" + parameterName + "'");
}
if (parametersScope != null) {
if (changeInfo.isConstructor() && valOrVar != JetValVar.None) {
for (VariableDescriptor property : parametersScope.getProperties(Name.identifier(parameterName))) {
PsiElement propertyDeclaration = BindingContextUtils.descriptorToDeclaration(bindingContext, property);
if (propertyDeclaration != null && !(propertyDeclaration.getParent() instanceof JetParameterList)) {
result.putValue(propertyDeclaration, "Duplicating property '" + parameterName + "'");
break;
}
}
}
else if (function instanceof JetFunction) {
VariableDescriptor variable = parametersScope.getLocalVariable(Name.identifier(parameterName));
if (variable != null && !(variable instanceof ValueParameterDescriptor)) {
PsiElement conflictElement = BindingContextUtils.descriptorToDeclaration(bindingContext, variable);
result.putValue(conflictElement, "Duplicating local variable '" + parameterName + "'");
}
}
}
}
return result;
}
@Nullable
private static JetScope getFunctionScope(BindingContext bindingContext, DeclarationDescriptor containingDeclaration) {
if (containingDeclaration instanceof ClassDescriptor)
return ((ClassDescriptor) containingDeclaration).getMemberScope(ContainerUtil.<TypeProjection>emptyList());
else if (containingDeclaration instanceof FunctionDescriptorImpl) {
PsiElement container = BindingContextUtils.descriptorToDeclaration(bindingContext, containingDeclaration);
if (container instanceof JetFunction)
return getFunctionBodyScope((JetFunction) container, bindingContext);
}
else if (containingDeclaration instanceof NamespaceDescriptor)
return ((NamespaceDescriptor) containingDeclaration).getMemberScope();
return null;
}
@Nullable
static JetScope getFunctionBodyScope(JetFunction element, BindingContext bindingContext) {
JetExpression body = element.getBodyExpression();
if (body != null) {
for (PsiElement child : body.getChildren()) {
if (child instanceof JetExpression)
return bindingContext.get(BindingContext.RESOLUTION_SCOPE, (JetExpression)child);
}
}
return null;
}
private static List<JetType> getFunctionParameterTypes(FunctionDescriptor descriptor) {
return ContainerUtil.map(descriptor.getValueParameters(), new Function<ValueParameterDescriptor, JetType>() {
@Override
public JetType fun(ValueParameterDescriptor descriptor) {
return descriptor.getType();
}
});
}
@Override
public boolean processUsage(ChangeInfo changeInfo, UsageInfo usageInfo, boolean beforeMethodChange, UsageInfo[] usages) {
if (beforeMethodChange)
return true;
PsiElement element = usageInfo.getElement();
if (element != null)
return usageInfo instanceof JetUsageInfo ? ((JetUsageInfo) usageInfo).processUsage((JetChangeInfo) changeInfo, element) : true;
else
return false;
}
@Override
public boolean processPrimaryMethod(ChangeInfo changeInfo) {
return true;
}
@Override
public boolean shouldPreviewUsages(ChangeInfo changeInfo, UsageInfo[] usages) {
return false;
}
@Override
public boolean setupDefaultValues(ChangeInfo changeInfo, Ref<UsageInfo[]> refUsages, Project project) {
return true;
}
@Override
public void registerConflictResolvers(List<ResolveSnapshotProvider.ResolveSnapshot> snapshots, @NotNull ResolveSnapshotProvider resolveSnapshotProvider, UsageInfo[] usages, ChangeInfo changeInfo) {
}
}
@@ -0,0 +1,79 @@
/*
* 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.openapi.ui.ComboBoxTableRenderer;
import com.intellij.psi.PsiElement;
import com.intellij.refactoring.changeSignature.ParameterTableModelItemBase;
import com.intellij.util.ui.ColumnInfo;
import org.jdesktop.swingx.autocomplete.ComboBoxCellEditor;
import org.jetbrains.jet.plugin.JetFileType;
import org.jetbrains.jet.plugin.refactoring.JetRefactoringBundle;
import javax.swing.*;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
public class JetConstructorParameterTableModel extends JetFunctionParameterTableModel {
public JetConstructorParameterTableModel(PsiElement context) {
super(context,
new ValVarColumn(),
new NameColumn(context.getProject()),
new TypeColumn(context.getProject(), JetFileType.INSTANCE),
new DefaultValueColumn<JetParameterInfo, ParameterTableModelItemBase<JetParameterInfo>>(context.getProject(), JetFileType.INSTANCE));
}
public static boolean isValVarColumn(ColumnInfo column) {
return column instanceof ValVarColumn;
}
protected static class ValVarColumn extends ColumnInfoBase<JetParameterInfo, ParameterTableModelItemBase<JetParameterInfo>, JetValVar> {
public ValVarColumn() {
super(JetRefactoringBundle.message("column.name.val.var"));
}
@Override
public boolean isCellEditable(ParameterTableModelItemBase<JetParameterInfo> item) {
return !item.isEllipsisType() && item.parameter.isNewParameter();
}
@Override
public JetValVar valueOf(ParameterTableModelItemBase<JetParameterInfo> item) {
return item.parameter.getValOrVar();
}
@Override
public void setValue(ParameterTableModelItemBase<JetParameterInfo> item, JetValVar value) {
item.parameter.setValOrVar(value);
}
@Override
public TableCellRenderer doCreateRenderer(ParameterTableModelItemBase<JetParameterInfo> item) {
return new ComboBoxTableRenderer<JetValVar>(JetValVar.values());
}
@Override
public TableCellEditor doCreateEditor(ParameterTableModelItemBase<JetParameterInfo> item) {
return new ComboBoxCellEditor(new JComboBox());
}
@Override
public int getWidth(JTable table) {
return table.getFontMetrics(table.getFont()).stringWidth(getName()) + 8;
}
}
}
@@ -0,0 +1,70 @@
/*
* 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.openapi.project.Project;
import com.intellij.psi.PsiCodeFragment;
import com.intellij.psi.PsiElement;
import com.intellij.refactoring.changeSignature.ParameterTableModelBase;
import com.intellij.refactoring.changeSignature.ParameterTableModelItemBase;
import com.intellij.util.ui.ColumnInfo;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetPsiFactory;
import org.jetbrains.jet.plugin.JetFileType;
public class JetFunctionParameterTableModel extends ParameterTableModelBase<JetParameterInfo, ParameterTableModelItemBase<JetParameterInfo>> {
private final Project project;
protected JetFunctionParameterTableModel(PsiElement context, ColumnInfo... columnInfos) {
super(context, context, columnInfos);
project = context.getProject();
}
public JetFunctionParameterTableModel(PsiElement context) {
this(context,
new NameColumn(context.getProject()),
new TypeColumn(context.getProject(), JetFileType.INSTANCE),
new DefaultValueColumn<JetParameterInfo, ParameterTableModelItemBase<JetParameterInfo>>(context.getProject(), JetFileType.INSTANCE));
}
@Override
protected ParameterTableModelItemBase<JetParameterInfo> createRowItem(@Nullable JetParameterInfo parameterInfo) {
if (parameterInfo == null) {
parameterInfo = new JetParameterInfo(-1);
}
final PsiCodeFragment paramTypeCodeFragment = JetPsiFactory.createTypeCodeFragment(project, parameterInfo.getTypeText(), myTypeContext);
final PsiCodeFragment defaultValueCodeFragment = JetPsiFactory.createExpressionCodeFragment(project, parameterInfo.getDefaultValueText(), myDefaultValueContext);
return new ParameterTableModelItemBase<JetParameterInfo>(parameterInfo, paramTypeCodeFragment, defaultValueCodeFragment) {
@Override
public boolean isEllipsisType() {
return false;
}
};
}
public static boolean isTypeColumn(ColumnInfo column) {
return column instanceof TypeColumn;
}
public static boolean isNameColumn(ColumnInfo column) {
return column instanceof NameColumn;
}
public static boolean isDefaultValueColumn(ColumnInfo column) {
return column instanceof DefaultValueColumn;
}
}
@@ -0,0 +1,37 @@
/*
* 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.refactoring.changeSignature.MethodDescriptor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.Visibility;
public interface JetFunctionPlatformDescriptor extends MethodDescriptor<JetParameterInfo, Visibility> {
boolean isConstructor();
@Nullable
String getReturnTypeText();
@NotNull
PsiElement getContext();
@Nullable
FunctionDescriptor getDescriptor();
}
@@ -0,0 +1,136 @@
/*
* 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().getName(), param.getType(), parameter.getDefaultValue(), parameter.getValOrVarNode());
}
}));
}
@Override
public String getName() {
if (funDescriptor instanceof ConstructorDescriptor)
return funDescriptor.getContainingDeclaration().getName().getName();
else if (funDescriptor instanceof AnonymousFunctionDescriptor)
return "";
else
return funDescriptor.getName().getName();
}
@Override
public List<JetParameterInfo> getParameters() {
return parameters;
}
public void addParameter(JetParameterInfo parameter) {
parameters.add(parameter);
}
public void removeParameter(int index) {
parameters.remove(index);
}
@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;
}
}
@@ -0,0 +1,28 @@
/*
* 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.PsiFile;
import java.util.Collections;
import java.util.List;
public class JetGeneratedInfo {
public List<PsiFile> getFilesToWrite() {
return Collections.emptyList();
}
}
@@ -0,0 +1,183 @@
/*
* 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.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.refactoring.changeSignature.ParameterInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetFunction;
import org.jetbrains.jet.lang.psi.JetParameter;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
import org.jetbrains.jet.renderer.DescriptorRenderer;
import java.util.List;
public class JetParameterInfo implements ParameterInfo {
private String name = "";
private final int oldIndex;
private JetType type;
private String typeText;
private String defaultValueText = "";
private JetValVar valOrVar;
@Nullable private JetExpression defaultValue;
public JetParameterInfo(int oldIndex, String name, JetType type, @Nullable JetExpression defaultValue, @Nullable ASTNode valOrVar) {
this.oldIndex = oldIndex;
this.name = name;
this.type = type;
this.typeText = getOldTypeText();
this.defaultValue = defaultValue;
if (valOrVar == null)
this.valOrVar = JetValVar.None;
else if (valOrVar.getElementType() == JetTokens.VAL_KEYWORD)
this.valOrVar = JetValVar.Val;
else if (valOrVar.getElementType() == JetTokens.VAR_KEYWORD)
this.valOrVar = JetValVar.Var;
else
throw new IllegalArgumentException("Unknown val/var token: " + valOrVar.getText());
}
public JetParameterInfo(String name, JetType type) {
this(-1, name, type, null, null);
}
public JetParameterInfo(int index) {
oldIndex = index;
typeText = "";
valOrVar = JetValVar.None;
}
@Override
public String getName() {
return name;
}
public String getInheritedName(boolean isInherited, @Nullable PsiElement inheritedFunction, @NotNull JetFunctionPlatformDescriptor baseFunction) {
if (!(inheritedFunction instanceof JetFunction))
return name;
List<JetParameter> inheritedParameters = ((JetFunction) inheritedFunction).getValueParameters();
if (!isInherited || oldIndex < 0 || oldIndex >= baseFunction.getParametersCount() || oldIndex >= inheritedParameters.size())
return name;
JetParameterInfo oldParam = baseFunction.getParameters().get(oldIndex);
JetParameter inheritedParam = inheritedParameters.get(oldIndex);
String inheritedParamName = inheritedParam.getName();
if (oldParam.getName().equals(inheritedParamName)) {
BindingContext bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) inheritedFunction.getContainingFile()).getBindingContext();
JetScope parametersScope = JetChangeSignatureUsageProcessor.getFunctionBodyScope((JetFunction) inheritedFunction, bindingContext);
if (parametersScope != null && parametersScope.getLocalVariable(Name.identifier(name)) == null)
return name;
else
return inheritedParamName;
}
else
return inheritedParamName;
}
@Override
public int getOldIndex() {
return oldIndex;
}
public boolean isNewParameter() {
return oldIndex == -1;
}
@Nullable
@Override
public String getDefaultValue() {
return null;
}
@Override
public void setName(String name) {
this.name = name != null ? name : "";
}
@Override
public boolean isUseAnySingleVariable() {
return false;
}
@Override
public void setUseAnySingleVariable(boolean b) {
throw new UnsupportedOperationException();
}
private String getOldTypeText() {
return DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(type);
}
@Override
public String getTypeText() {
return typeText;
}
public void setTypeText(String typeText) {
this.typeText = typeText;
}
public boolean isTypeChanged() {
return !getOldTypeText().equals(typeText);
}
public String getDefaultValueText() {
return defaultValueText;
}
public void setDefaultValueText(String defaultValueText) {
this.defaultValueText = defaultValueText;
}
public JetValVar getValOrVar() {
return valOrVar != null ? valOrVar : JetValVar.None;
}
public void setValOrVar(JetValVar valOrVar) {
this.valOrVar = valOrVar;
}
public String getDeclarationSignature(boolean isInherited, PsiElement inheritedFunction, JetFunctionPlatformDescriptor baseFunction) {
StringBuilder buffer = new StringBuilder();
JetValVar valVar = getValOrVar();
if (valVar != JetValVar.None)
buffer.append(valVar.toString()).append(' ');
buffer.append(getInheritedName(isInherited, inheritedFunction, baseFunction));
buffer.append(": ").append(getTypeText());
if (defaultValue != null)
buffer.append(" = ").append(defaultValue.getText());
return buffer.toString();
}
}
@@ -0,0 +1,54 @@
/*
* 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.refactoring.RefactoringBundle;
import com.intellij.usageView.UsageViewBundle;
import com.intellij.usageView.UsageViewDescriptor;
import org.jetbrains.annotations.NotNull;
public class JetUsagesViewDescriptor implements UsageViewDescriptor {
private final PsiElement myElement;
private final String myElementsHeader;
public JetUsagesViewDescriptor(PsiElement element, String elementsHeader) {
myElement = element;
myElementsHeader = elementsHeader;
}
@NotNull
@Override
public PsiElement[] getElements() {
return myElement != null ? new PsiElement[] {myElement} : new PsiElement[0];
}
@Override
public String getProcessedElementsHeader() {
return myElementsHeader;
}
@Override
public String getCodeReferencesText(int usagesCount, int filesCount) {
return RefactoringBundle.message("references.to.be.changed", UsageViewBundle.getReferencesString(usagesCount, filesCount));
}
@Override
public String getCommentReferencesText(int usagesCount, int filesCount) {
return RefactoringBundle.message("comments.elements.header", UsageViewBundle.getOccurencesString(usagesCount, filesCount));
}
}
@@ -0,0 +1,37 @@
/*
* 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;
public enum JetValVar {
None,
Val,
Var;
@Override
public String toString() {
switch (this) {
case None:
return "none";
case Val:
return "val";
case Var:
return "var";
}
return "";
}
}
@@ -0,0 +1,98 @@
/*
* 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.usages;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.plugin.refactoring.changeSignature.JetChangeInfo;
import org.jetbrains.jet.plugin.refactoring.changeSignature.JetParameterInfo;
import java.util.List;
public class JetFunctionCallUsage extends JetUsageInfo<JetCallElement> {
private final PsiElement function;
private final boolean isInherited;
public JetFunctionCallUsage(@NotNull JetCallElement element, @NotNull PsiElement function, boolean isInherited) {
super(element);
this.function = function;
this.isInherited = isInherited;
}
@Override
public boolean processUsage(JetChangeInfo changeInfo, JetCallElement element) {
JetValueArgumentList arguments = element.getValueArgumentList();
if (changeInfo.isNameChanged()) {
JetExpression callee = element.getCalleeExpression();
if (callee instanceof JetSimpleNameExpression)
callee.replace(JetPsiFactory.createSimpleName(getProject(), changeInfo.getNewName()));
}
if (arguments != null) {
List<JetValueArgument> oldArguments = arguments.getArguments();
if (changeInfo.isParameterSetOrOrderChanged()) {
StringBuilder parametersBuilder = new StringBuilder("(");
boolean isFirst = true;
for (JetParameterInfo parameterInfo : changeInfo.getNewParameters()) {
if (isFirst)
isFirst = false;
else
parametersBuilder.append(',');
String defaultValueText = parameterInfo.getDefaultValueText();
parametersBuilder.append(defaultValueText.isEmpty() ? '0' : defaultValueText);
}
parametersBuilder.append(')');
JetValueArgumentList newArguments = JetPsiFactory.createCallArguments(getProject(), parametersBuilder.toString());
int argIndex = 0;
for (JetValueArgument newArgument : newArguments.getArguments()) {
JetParameterInfo parameterInfo = changeInfo.getNewParameters()[argIndex++];
int oldIndex = parameterInfo.getOldIndex();
if (oldIndex >= 0 && oldIndex < oldArguments.size())
newArgument.replace(oldArguments.get(oldIndex));
else if (parameterInfo.getDefaultValueText().isEmpty())
newArgument.delete();
}
arguments.replace(newArguments);
}
else {
for (JetParameterInfo parameterInfo : changeInfo.getNewParameters()) {
JetValueArgument argument = parameterInfo.getOldIndex() < oldArguments.size() ? oldArguments.get(parameterInfo.getOldIndex()) : null;
JetValueArgumentName argumentName = argument != null ? argument.getArgumentName() : null;
JetSimpleNameExpression argumentNameExpression = argumentName != null ? argumentName.getReferenceExpression() : null;
PsiElement identifier = argumentNameExpression != null ? argumentNameExpression.getIdentifier() : null;
if (identifier != null) {
String newName = parameterInfo.getInheritedName(isInherited, function, changeInfo.getFunctionDescriptor());
identifier.replace(JetPsiFactory.createIdentifier(getProject(), newName));
}
}
}
}
return true;
}
}
@@ -0,0 +1,148 @@
/*
* 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.usages;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.lexer.JetKeywordToken;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.intentions.SpecifyTypeExplicitlyAction;
import org.jetbrains.jet.plugin.quickfix.AddModifierFix;
import org.jetbrains.jet.plugin.quickfix.ChangeFunctionReturnTypeFix;
import org.jetbrains.jet.plugin.quickfix.ChangeVisibilityModifierFix;
import org.jetbrains.jet.plugin.refactoring.JetRefactoringUtil;
import org.jetbrains.jet.plugin.refactoring.changeSignature.JetChangeInfo;
import org.jetbrains.jet.plugin.refactoring.changeSignature.JetParameterInfo;
import org.jetbrains.jet.plugin.refactoring.changeSignature.JetValVar;
public class JetFunctionDefinitionUsage extends JetUsageInfo<PsiElement> {
private final boolean isInherited;
public JetFunctionDefinitionUsage(@NotNull PsiElement function, boolean isInherited) {
super(function);
this.isInherited = isInherited;
}
@Override
public boolean processUsage(JetChangeInfo changeInfo, PsiElement element) {
JetParameterList parameterList;
if (element instanceof JetFunction) {
JetFunction function = (JetFunction) element;
parameterList = function.getValueParameterList();
if (changeInfo.isNameChanged()) {
PsiElement identifier = function.getNameIdentifier();
if (identifier != null)
identifier.replace(JetPsiFactory.createIdentifier(element.getProject(), changeInfo.getNewName()));
}
if (changeInfo.isReturnTypeChanged()) {
SpecifyTypeExplicitlyAction.removeTypeAnnotation(function);
String returnTypeText = changeInfo.getNewReturnTypeText();
//TODO use ChangeFunctionReturnTypeFix.invoke when JetTypeCodeFragment.getType() is ready
if (!KotlinBuiltIns.getInstance().getUnitType().toString().equals(returnTypeText))
ChangeFunctionReturnTypeFix.addReturnTypeAnnotation(getProject(), function, returnTypeText);
}
}
else
parameterList = ((JetClass) element).getPrimaryConstructorParameterList();
if (changeInfo.isParameterSetOrOrderChanged()) {
String parametersText = changeInfo.getNewParametersSignature(element, isInherited, 0);
JetParameterList newParameterList = JetPsiFactory.createParameterList(getProject(), parametersText);
if (parameterList != null)
parameterList = (JetParameterList) parameterList.replace(newParameterList);
else if (element instanceof JetClass) {
PsiElement anchor = ((JetClass) element).getTypeParameterList();
if (anchor == null)
anchor = ((JetClass) element).getNameIdentifier();
if (anchor != null)
parameterList = (JetParameterList) element.addAfter(newParameterList, anchor);
}
}
else if (parameterList != null) {
int paramIndex = 0;
for (JetParameter parameter : parameterList.getParameters()) {
JetParameterInfo parameterInfo = changeInfo.getNewParameters()[paramIndex++];
changeParameter(changeInfo, element, parameter, parameterInfo);
}
}
if (changeInfo.isVisibilityChanged())
changeVisibility(changeInfo, element, parameterList);
return true;
}
private void changeVisibility(JetChangeInfo changeInfo, PsiElement element, JetParameterList parameterList) {
JetKeywordToken newVisibilityToken = JetRefactoringUtil.getVisibilityToken(changeInfo.getNewVisibility());
if (element instanceof JetFunction) {
JetModifierList modifierList = newVisibilityToken == JetTokens.INTERNAL_KEYWORD ? null :
JetPsiFactory.createModifierList(getProject(), newVisibilityToken);
AddModifierFix.changeModifier(element, ((JetFunction) element).getModifierList(), null,
ChangeVisibilityModifierFix.VISIBILITY_TOKENS, getProject(), true, modifierList);
}
else {
JetModifierList modifierList = newVisibilityToken == JetTokens.PUBLIC_KEYWORD ? null :
JetPsiFactory.createConstructorModifierList(getProject(), newVisibilityToken);
AddModifierFix.changeModifier(element, ((JetClass) element).getPrimaryConstructorModifierList(), parameterList,
ChangeVisibilityModifierFix.VISIBILITY_TOKENS, getProject(), true, modifierList);
}
}
private void changeParameter(JetChangeInfo changeInfo, PsiElement element, JetParameter parameter, JetParameterInfo parameterInfo) {
ASTNode valOrVarAstNode = parameter.getValOrVarNode();
PsiElement valOrVarNode = valOrVarAstNode != null ? valOrVarAstNode.getPsi() : null;
JetValVar valOrVar = parameterInfo.getValOrVar();
if (valOrVarNode != null) {
if (valOrVar == JetValVar.None)
valOrVarNode.delete();
else
valOrVarNode.replace(JetPsiFactory.createValOrVarNode(getProject(), valOrVar.toString()).getPsi());
}
else if (valOrVar != JetValVar.None) {
PsiElement firstChild = parameter.getFirstChild();
parameter.addBefore(JetPsiFactory.createValOrVarNode(getProject(), valOrVar.toString()).getPsi(), firstChild);
parameter.addBefore(JetPsiFactory.createWhiteSpace(getProject()), firstChild);
}
if (parameterInfo.isTypeChanged()) {
JetTypeReference newType = JetPsiFactory.createType(getProject(), parameterInfo.getTypeText());
JetTypeReference typeReference = parameter.getTypeReference();
if (typeReference != null)
typeReference.replace(newType);
}
PsiElement identifier = parameter.getNameIdentifier();
if (identifier != null) {
String newName = parameterInfo.getInheritedName(isInherited, element, changeInfo.getFunctionDescriptor());
identifier.replace(JetPsiFactory.createIdentifier(parameter.getProject(), newName));
}
}
}
@@ -0,0 +1,44 @@
/*
* 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.usages;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetPsiFactory;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.plugin.refactoring.changeSignature.JetChangeInfo;
import org.jetbrains.jet.plugin.refactoring.changeSignature.JetParameterInfo;
public class JetParameterUsage extends JetUsageInfo<JetSimpleNameExpression> {
private final JetParameterInfo parameterInfo;
private final PsiElement function;
private final boolean isInherited;
public JetParameterUsage(@NotNull JetSimpleNameExpression element, JetParameterInfo parameterInfo, PsiElement function, boolean inherited) {
super(element);
this.parameterInfo = parameterInfo;
this.function = function;
isInherited = inherited;
}
@Override
public boolean processUsage(JetChangeInfo changeInfo, JetSimpleNameExpression element) {
String newName = parameterInfo.getInheritedName(isInherited, function, changeInfo.getFunctionDescriptor());
element.replace(JetPsiFactory.createSimpleName(element.getProject(), newName));
return false;
}
}
@@ -0,0 +1,35 @@
/*
* 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.usages;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.usageView.UsageInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.plugin.refactoring.changeSignature.JetChangeInfo;
public abstract class JetUsageInfo<T extends PsiElement> extends UsageInfo {
public JetUsageInfo(@NotNull T element) {
super(element);
}
public JetUsageInfo(@NotNull PsiReference reference) {
super(reference);
}
public abstract boolean processUsage(JetChangeInfo changeInfo, T element);
}
@@ -0,0 +1,5 @@
class C1 protected (val x: Any){}
fun f() {
val c = C1(12);
}
@@ -0,0 +1,5 @@
class <caret>C1{}
fun f() {
val c = C1();
}
@@ -0,0 +1,3 @@
fun x(a: Int): Float {
x(1);
}
@@ -0,0 +1,3 @@
fun x(a: Int) {
<caret>x(1);
}
@@ -0,0 +1,3 @@
fun<caret> x(a: Int): Float {
x(1);
}
@@ -0,0 +1 @@
class C1 protected (){}
@@ -0,0 +1 @@
class <caret>C1(){}
@@ -0,0 +1,3 @@
fun x(a: Int): Float {
x(1);
}
@@ -0,0 +1,3 @@
fun <caret>x(a: Int): Int {
x(1);
}
@@ -0,0 +1,14 @@
open class C0(val x: Any?) {}
open class C1 (var _x1: Int = 1, _x2: Float?, val _x3: ((Int) -> Int)?) : C0(_x3){
fun bar() {
val y1 = _x1;
val y2 = _x2;
}
}
class C2 : C1(1, 2.5, null<caret>) {
fun foo() {
var c = C1(2, 3.5, null);
c = C1(_x1 = 2, _x2 = 3.5, _x3 = null);
}
}
@@ -0,0 +1,14 @@
open class C0(val x: Any?) {}
open class C1 protected (val x1: Int = 1, var x2: Float, x3: ((Int) -> Int)?) : C0(x3){
fun bar() {
val y1 = x1;
val y2 = x2;
}
}
class C2 : C1(1, 2.5, null<caret>) {
fun foo() {
var c = C1(2, 3.5, null);
c = C1(x1 = 2, x2 = 3.5, x3 = null);
}
}
@@ -0,0 +1,14 @@
open class C1 protected (x3: ((Int) -> Int)?,
var _x2: Float,
val _x1: Int = 1){
fun bar() {
val y1 = _x1;
val y2 = _x2;
}
}
class C2 : C1(null, 2.5, 1) {
fun foo() {
var c = C1(null, 3.5, 2);
c = C1(x3 = null, _x2 = 3.5, _x1 = 2);
}
}
@@ -0,0 +1,12 @@
open class C1 protected (<caret>val x1: Int = 1, var x2: Float, x3: ((Int) -> Int)?){
fun bar() {
val y1 = x1;
val y2 = x2;
}
}
class C2 : C1(1, 2.5, null) {
fun foo() {
var c = C1(2, 3.5, null);
c = C1(x1 = 2, x2 = 3.5, x3 = null);
}
}
@@ -0,0 +1,5 @@
open class Class(<caret>x: Int, val y: Int, val z: Int, _y: Int, var i: Int) {
var _x: Int = 0;
var _y: Int = 0;
var _z: Int = 0;
}
@@ -0,0 +1,3 @@
Duplicating parameter '_y'
Duplicating property '_y'
Duplicating property '_z'
@@ -0,0 +1,2 @@
fun fun1(x1: Int,
y1: Int): Int = x1 * 2 + fun1(x1, )
@@ -0,0 +1 @@
fun fun1(<caret>x : Int) : Int = x * 2 + fun1(x)
@@ -0,0 +1,5 @@
fun foo() {
val v1 = {(z: Int,
y1: String,
x: Any): Int -> println(z); println(y1) }
}
@@ -0,0 +1,3 @@
fun foo() {
val v1 = {(<caret>z: Int, y: String) -> println(z); println(y) }
}
@@ -0,0 +1,12 @@
fun foo(x0: Any?,
x1: Int = 1,
x2: Float) {
foo(null, 2, 3.5);
val y1 = x1;
val y2 = x2;
val y3 = x3;
}
fun bar() {
foo(null, x1 = 2, x2 = 3.5);
}
@@ -0,0 +1,10 @@
protected fun foo(x1: Int = 1, x2: Float, x3: ((Int) -> Int)?) {
foo(<caret>2, 3.5, null);
val y1 = x1;
val y2 = x2;
val y3 = x3;
}
fun bar() {
foo(x1 = 2, x2 = 3.5, x3 = null);
}
@@ -0,0 +1,10 @@
public fun foo(_x1: Int = 1, _x2: Float?, _x3: ((Int) -> Int)?) {
foo(2, 3.5, null);
val y1 = _x1;
val y2 = _x2;
val y3 = _x3;
}
fun bar() {
foo(_x1 = 2, _x2 = 3.5, _x3 = null);
}
@@ -0,0 +1,10 @@
fun foo(<caret>x1: Int = 1, x2: Float, x3: ((Int) -> Int)?) {
foo(2, 3.5, null);
val y1 = x1;
val y2 = x2;
val y3 = x3;
}
fun bar() {
foo(x1 = 2, x2 = 3.5, x3 = null);
}
@@ -0,0 +1,4 @@
fun outer() {
fun <caret>inner1(x: Int, y: Int): Int { val y: Int; }
fun inner2(x: Int, y: Int): Any { }
}
@@ -0,0 +1,3 @@
Duplicating local variable 'y'
Duplicating parameter 'y'
Function already exists: 'local final fun inner2(x : Int, y : Int) : Any defined in outer'
@@ -0,0 +1,4 @@
class outer() {
fun <caret>inner1(x: Int, z: Int) { fun inner3() { val y: Int; }}
fun inner2(x: Int, y: Int) { }
}
@@ -0,0 +1 @@
Function already exists: 'internal final fun inner2(x : Int, y : Int) : Unit defined in outer'
@@ -0,0 +1,3 @@
fun x(a: Int) {
x(1);
}
@@ -0,0 +1,3 @@
fun x(a: Int): Float {
x(<caret>1);
}
@@ -0,0 +1,6 @@
fun after(a: Int) {
after(1);
}
fun after(a: Int, b: Int) {
}
@@ -0,0 +1,6 @@
fun x(<caret>a: Int) {
x(1);
}
fun after(a: Int, b: Int) {
}
@@ -0,0 +1,2 @@
fun <caret>fun1() { }
fun fun2() { }
@@ -0,0 +1 @@
Function already exists: 'internal fun fun2() : Unit defined in root package'
@@ -0,0 +1,2 @@
fun foo(<caret>x1: Int = 1, vararg x2: Float, x3: ((Int) -> Int)?) {
}
@@ -0,0 +1,225 @@
/*
* 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.openapi.editor.Editor;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
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.Visibilities;
import org.jetbrains.jet.lang.psi.JetPsiFactory;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.plugin.PluginTestCaseBase;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class JetChangeSignatureTest extends LightCodeInsightTestCase {
public void testBadSelection() throws Exception {
configureByFile(getTestName(false) + "Before.kt");
Editor editor = getEditor();
PsiFile file = getFile();
assertNull(new JetChangeSignatureHandler().findTargetMember(file, editor));
}
public void testRenameFunction() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setNewName("after");
doTest(changeInfo);
}
public void testChangeReturnType() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setNewReturnTypeText("Float");
doTest(changeInfo);
}
public void testAddReturnType() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setNewReturnTypeText("Float");
doTest(changeInfo);
}
public void testRemoveReturnType() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setNewReturnTypeText("Unit");
doTest(changeInfo);
}
public void testChangeConstructorVisibility() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setNewVisibility(Visibilities.PROTECTED);
doTest(changeInfo);
}
public void testAddConstructorVisibility() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setNewVisibility(Visibilities.PROTECTED);
JetParameterInfo newParameter = new JetParameterInfo(-1, "x", KotlinBuiltIns.getInstance().getAnyType(),
null, JetPsiFactory.createValOrVarNode(getProject(), "val"));
newParameter.setDefaultValueText("12");
changeInfo.addParameter(newParameter);
doTest(changeInfo);
}
public void testConstructor() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setNewVisibility(Visibilities.PUBLIC);
changeInfo.getNewParameters()[0].setValOrVar(JetValVar.Var);
changeInfo.getNewParameters()[1].setValOrVar(JetValVar.None);
changeInfo.getNewParameters()[2].setValOrVar(JetValVar.Val);
changeInfo.getNewParameters()[0].setName("_x1");
changeInfo.getNewParameters()[1].setName("_x2");
changeInfo.getNewParameters()[2].setName("_x3");
changeInfo.getNewParameters()[1].setTypeText("Float?");
doTest(changeInfo);
}
public void testConstructorSwapArguments() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.getNewParameters()[0].setName("_x1");
changeInfo.getNewParameters()[1].setName("_x2");
JetParameterInfo param = changeInfo.getNewParameters()[0];
changeInfo.setNewParameter(0, changeInfo.getNewParameters()[2]);
changeInfo.setNewParameter(2, param);
doTest(changeInfo);
}
public void testFunctions() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setNewVisibility(Visibilities.PUBLIC);
changeInfo.getNewParameters()[0].setName("_x1");
changeInfo.getNewParameters()[1].setName("_x2");
changeInfo.getNewParameters()[2].setName("_x3");
changeInfo.getNewParameters()[1].setTypeText("Float?");
doTest(changeInfo);
}
public void testExpressionFunction() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.getNewParameters()[0].setName("x1");
changeInfo.addParameter(new JetParameterInfo("y1", KotlinBuiltIns.getInstance().getIntType()));
doTest(changeInfo);
}
public void testFunctionsAddRemoveArguments() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setNewVisibility(Visibilities.INTERNAL);
changeInfo.setNewParameter(2, changeInfo.getNewParameters()[1]);
changeInfo.setNewParameter(1, changeInfo.getNewParameters()[0]);
JetParameterInfo newParameter = new JetParameterInfo("x0", KotlinBuiltIns.getInstance().getNullableAnyType());
newParameter.setDefaultValueText("null");
changeInfo.setNewParameter(0, newParameter);
doTest(changeInfo);
}
public void testFunctionLiteral() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.getNewParameters()[1].setName("y1");
changeInfo.addParameter(new JetParameterInfo("x", KotlinBuiltIns.getInstance().getAnyType()));
changeInfo.setNewReturnTypeText("Int");
doTest(changeInfo);
}
public void testVarargs() throws Exception {
try {
getChangeInfo();
}
catch (CommonRefactoringUtil.RefactoringErrorHintException e) {
assertEquals("Can't refactor the function with variable arguments", e.getMessage());
return;
}
fail("Exception expected");
}
public void testInnerFunctionsConflict() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setNewName("inner2");
changeInfo.getNewParameters()[0].setName("y");
doTestConflict(changeInfo);
}
public void testMemberFunctionsConflict() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setNewName("inner2");
changeInfo.getNewParameters()[0].setName("y");
doTestConflict(changeInfo);
}
public void testTopLevelFunctionsConflict() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setNewName("fun2");
doTestConflict(changeInfo);
}
public void testConstructorsConflict() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.getNewParameters()[0].setName("_x");
changeInfo.getNewParameters()[1].setName("_y");
changeInfo.getNewParameters()[2].setName("_z");
doTestConflict(changeInfo);
}
@NotNull
@Override
protected String getTestDataPath() {
return new File(PluginTestCaseBase.getTestDataPathBase(), "/refactoring/changeSignature").getPath() + File.separator;
}
private JetChangeInfo getChangeInfo() throws Exception {
configureByFile(getTestName(false) + "Before.kt");
Editor editor = getEditor();
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);
assertNotNull(dialog);
dialog.canRun();
return dialog.evaluateChangeInfo();
}
private void doTest(JetChangeInfo changeInfo) throws Exception {
new JetChangeSignatureProcessor(getProject(), changeInfo, "Change signature").run();
checkResultByFile(getTestName(false) + "After.kt");
}
private void doTestConflict(JetChangeInfo changeInfo) throws Exception {
try {
new JetChangeSignatureProcessor(getProject(), changeInfo, "Change signature").run();
}
catch (BaseRefactoringProcessor.ConflictsInTestsException e) {
List<String> messages = new ArrayList<String>(e.getMessages());
Collections.sort(messages);
File conflictsFile = new File(getTestDataPath() + getTestName(false) + "Messages.txt");
String fileText = FileUtil.loadFile(conflictsFile, CharsetToolkit.UTF8);
assertEquals(fileText, StringUtil.join(messages, "\n"));
return;
}
fail("No conflicts found");
}
}