Change Signature: val/var parameter support

This commit is contained in:
Alexey Sedunov
2015-07-02 15:17:53 +03:00
parent 2ff63d37c2
commit 161539f3da
14 changed files with 186 additions and 49 deletions
@@ -150,7 +150,7 @@ public abstract class CallableRefactoring<T: CallableDescriptor>(
return true return true
} }
if (closestModifiableDescriptors.size() == 1 && deepestSuperDeclarations == closestModifiableDescriptors) { if (closestModifiableDescriptors.size() == 1 && deepestSuperDeclarations.subtract(closestModifiableDescriptors).isEmpty()) {
performRefactoring(closestModifiableDescriptors) performRefactoring(closestModifiableDescriptors)
return true return true
} }
@@ -104,7 +104,7 @@ public class JetChangeInfo(
fun getNonReceiverParametersCount(): Int = newParameters.size() - (if (receiverParameterInfo != null) 1 else 0) fun getNonReceiverParametersCount(): Int = newParameters.size() - (if (receiverParameterInfo != null) 1 else 0)
fun getNonReceiverParameters(): List<JetParameterInfo> { fun getNonReceiverParameters(): List<JetParameterInfo> {
if (methodDescriptor.baseDeclaration is JetProperty) return emptyList() methodDescriptor.baseDeclaration.let { if (it is JetProperty || it is JetParameter) return emptyList() }
return receiverParameterInfo?.let { receiver -> newParameters.filter { it != receiver } } ?: newParameters return receiverParameterInfo?.let { receiver -> newParameters.filter { it != receiver } } ?: newParameters
} }
@@ -309,7 +309,7 @@ public class JetChangeInfo(
when (method) { when (method) {
is JetFunction, is JetClassOrObject -> is JetFunction, is JetClassOrObject ->
createJavaChangeInfoForFunctionOrGetter(originalPsiMethod, currentPsiMethod, false) createJavaChangeInfoForFunctionOrGetter(originalPsiMethod, currentPsiMethod, false)
is JetProperty -> { is JetProperty, is JetParameter -> {
val accessorName = originalPsiMethod.getName() val accessorName = originalPsiMethod.getName()
when { when {
accessorName.startsWith(JvmAbi.GETTER_PREFIX) -> accessorName.startsWith(JvmAbi.GETTER_PREFIX) ->
@@ -51,7 +51,7 @@ public class JetChangePropertySignatureDialog(
) )
private val nameField = EditorTextField(methodDescriptor.getName()) private val nameField = EditorTextField(methodDescriptor.getName())
private var returnTypeField: EditorTextField by Delegates.notNull() private var returnTypeField: EditorTextField by Delegates.notNull()
private var receiverTypeCheckBox: JCheckBox by Delegates.notNull() private var receiverTypeCheckBox: JCheckBox? = null
var receiverTypeLabel: JLabel by Delegates.notNull() var receiverTypeLabel: JLabel by Delegates.notNull()
private var receiverTypeField: EditorTextField by Delegates.notNull() private var receiverTypeField: EditorTextField by Delegates.notNull()
var receiverDefaultValueLabel: JLabel? = null var receiverDefaultValueLabel: JLabel? = null
@@ -66,7 +66,7 @@ public class JetChangePropertySignatureDialog(
override fun createCenterPanel(): JComponent? { override fun createCenterPanel(): JComponent? {
fun updateReceiverUI() { fun updateReceiverUI() {
val withReceiver = receiverTypeCheckBox.isSelected() val withReceiver = receiverTypeCheckBox!!.isSelected()
receiverTypeLabel.setEnabled(withReceiver) receiverTypeLabel.setEnabled(withReceiver)
receiverTypeField.setEnabled(withReceiver) receiverTypeField.setEnabled(withReceiver)
receiverDefaultValueLabel?.setEnabled(withReceiver) receiverDefaultValueLabel?.setEnabled(withReceiver)
@@ -77,7 +77,8 @@ public class JetChangePropertySignatureDialog(
val psiFactory = JetPsiFactory(myProject) val psiFactory = JetPsiFactory(myProject)
return with(FormBuilder.createFormBuilder()) { return with(FormBuilder.createFormBuilder()) {
if (!((methodDescriptor.baseDeclaration as? JetProperty)?.isLocal() ?: false)) { val baseDeclaration = methodDescriptor.baseDeclaration
if (!((baseDeclaration as? JetProperty)?.isLocal() ?: false)) {
visibilityCombo.setSelectedItem(methodDescriptor.getVisibility()) visibilityCombo.setSelectedItem(methodDescriptor.getVisibility())
addLabeledComponent("&Visibility: ", visibilityCombo) addLabeledComponent("&Visibility: ", visibilityCombo)
} }
@@ -85,38 +86,40 @@ public class JetChangePropertySignatureDialog(
addLabeledComponent("&Name: ", nameField) addLabeledComponent("&Name: ", nameField)
val returnTypeCodeFragment = psiFactory.createTypeCodeFragment(methodDescriptor.renderOriginalReturnType(), val returnTypeCodeFragment = psiFactory.createTypeCodeFragment(methodDescriptor.renderOriginalReturnType(),
methodDescriptor.baseDeclaration) baseDeclaration)
returnTypeField = EditorTextField(documentManager.getDocument(returnTypeCodeFragment), myProject, JetFileType.INSTANCE) returnTypeField = EditorTextField(documentManager.getDocument(returnTypeCodeFragment), myProject, JetFileType.INSTANCE)
addLabeledComponent("&Type: ", returnTypeField) addLabeledComponent("&Type: ", returnTypeField)
addSeparator() if (baseDeclaration is JetProperty) {
addSeparator()
val receiverTypeCheckBox = JCheckBox("Extension property: ") val receiverTypeCheckBox = JCheckBox("Extension property: ")
receiverTypeCheckBox.setMnemonic('x') receiverTypeCheckBox.setMnemonic('x')
receiverTypeCheckBox.addActionListener { updateReceiverUI() } receiverTypeCheckBox.addActionListener { updateReceiverUI() }
receiverTypeCheckBox.setSelected(methodDescriptor.receiver != null) receiverTypeCheckBox.setSelected(methodDescriptor.receiver != null)
addComponent(receiverTypeCheckBox) addComponent(receiverTypeCheckBox)
this@JetChangePropertySignatureDialog.receiverTypeCheckBox = receiverTypeCheckBox this@JetChangePropertySignatureDialog.receiverTypeCheckBox = receiverTypeCheckBox
val receiverTypeCodeFragment = psiFactory.createTypeCodeFragment(methodDescriptor.renderOriginalReceiverType() ?: "", val receiverTypeCodeFragment = psiFactory.createTypeCodeFragment(methodDescriptor.renderOriginalReceiverType() ?: "",
methodDescriptor.baseDeclaration) methodDescriptor.baseDeclaration)
receiverTypeField = EditorTextField(documentManager.getDocument(receiverTypeCodeFragment), myProject, JetFileType.INSTANCE) receiverTypeField = EditorTextField(documentManager.getDocument(receiverTypeCodeFragment), myProject, JetFileType.INSTANCE)
receiverTypeLabel = JLabel("Receiver type: ") receiverTypeLabel = JLabel("Receiver type: ")
receiverTypeLabel.setDisplayedMnemonic('t') receiverTypeLabel.setDisplayedMnemonic('t')
addLabeledComponent(receiverTypeLabel, receiverTypeField) addLabeledComponent(receiverTypeLabel, receiverTypeField)
if (methodDescriptor.receiver == null) { if (methodDescriptor.receiver == null) {
val receiverDefaultValueCodeFragment = psiFactory.createExpressionCodeFragment("", methodDescriptor.baseDeclaration) val receiverDefaultValueCodeFragment = psiFactory.createExpressionCodeFragment("", methodDescriptor.baseDeclaration)
receiverDefaultValueField = EditorTextField(documentManager.getDocument(receiverDefaultValueCodeFragment), receiverDefaultValueField = EditorTextField(documentManager.getDocument(receiverDefaultValueCodeFragment),
myProject, myProject,
JetFileType.INSTANCE) JetFileType.INSTANCE)
receiverDefaultValueLabel = JLabel("Default receiver value: ") receiverDefaultValueLabel = JLabel("Default receiver value: ")
receiverDefaultValueLabel!!.setDisplayedMnemonic('D') receiverDefaultValueLabel!!.setDisplayedMnemonic('D')
addLabeledComponent(receiverDefaultValueLabel, receiverDefaultValueField!!) addLabeledComponent(receiverDefaultValueLabel, receiverDefaultValueField!!)
}
updateReceiverUI()
} }
updateReceiverUI()
getPanel() getPanel()
} }
} }
@@ -131,7 +134,7 @@ public class JetChangePropertySignatureDialog(
psiFactory.createSimpleName(nameField.getText()).validateElement("Invalid name") psiFactory.createSimpleName(nameField.getText()).validateElement("Invalid name")
psiFactory.createType(returnTypeField.getText()).validateElement("Invalid return type") psiFactory.createType(returnTypeField.getText()).validateElement("Invalid return type")
if (receiverTypeCheckBox.isSelected()) { if (receiverTypeCheckBox?.isSelected() ?: false) {
psiFactory.createType(receiverTypeField.getText()).validateElement("Invalid receiver type") psiFactory.createType(receiverTypeField.getText()).validateElement("Invalid receiver type")
} }
getDefaultReceiverValue()?.validateElement("Invalid default receiver value") getDefaultReceiverValue()?.validateElement("Invalid default receiver value")
@@ -140,7 +143,7 @@ public class JetChangePropertySignatureDialog(
override fun doAction() { override fun doAction() {
val descriptor = (methodDescriptor as? JetMutableMethodDescriptor)?.original ?: methodDescriptor val descriptor = (methodDescriptor as? JetMutableMethodDescriptor)?.original ?: methodDescriptor
val receiver = if (receiverTypeCheckBox.isSelected()) { val receiver = if (receiverTypeCheckBox?.isSelected() ?: false) {
descriptor.receiver ?: JetParameterInfo(callableDescriptor = descriptor.baseDescriptor, descriptor.receiver ?: JetParameterInfo(callableDescriptor = descriptor.baseDescriptor,
name = "receiver", name = "receiver",
defaultValueForCall = getDefaultReceiverValue()) defaultValueForCall = getDefaultReceiverValue())
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.refactoring.CallableRefactoring import org.jetbrains.kotlin.idea.refactoring.CallableRefactoring
import org.jetbrains.kotlin.psi.JetClass import org.jetbrains.kotlin.psi.JetClass
import org.jetbrains.kotlin.psi.JetFunction import org.jetbrains.kotlin.psi.JetFunction
import org.jetbrains.kotlin.psi.JetParameter
import org.jetbrains.kotlin.psi.JetProperty import org.jetbrains.kotlin.psi.JetProperty
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
@@ -79,7 +80,7 @@ public class JetChangeSignature(project: Project,
is JetFunction, is JetClass -> { is JetFunction, is JetClass -> {
JetChangeSignatureDialog.createRefactoringProcessorForSilentChangeSignature(project, commandName, descriptor, defaultValueContext) JetChangeSignatureDialog.createRefactoringProcessorForSilentChangeSignature(project, commandName, descriptor, defaultValueContext)
} }
is JetProperty -> { is JetProperty, is JetParameter -> {
JetChangePropertySignatureDialog.createProcessorForSilentRefactoring(project, commandName, descriptor) JetChangePropertySignatureDialog.createProcessorForSilentRefactoring(project, commandName, descriptor)
} }
else -> throw AssertionError("Unexpected declaration: ${descriptor.baseDeclaration.getElementTextWithContext()}") else -> throw AssertionError("Unexpected declaration: ${descriptor.baseDeclaration.getElementTextWithContext()}")
@@ -90,7 +91,7 @@ public class JetChangeSignature(project: Project,
private fun runInteractiveRefactoring(descriptor: JetMethodDescriptor) { private fun runInteractiveRefactoring(descriptor: JetMethodDescriptor) {
val dialog = when (descriptor.baseDeclaration) { val dialog = when (descriptor.baseDeclaration) {
is JetFunction, is JetClass -> JetChangeSignatureDialog(project, descriptor, defaultValueContext, commandName) is JetFunction, is JetClass -> JetChangeSignatureDialog(project, descriptor, defaultValueContext, commandName)
is JetProperty -> JetChangePropertySignatureDialog(project, descriptor, commandName) is JetProperty, is JetParameter -> JetChangePropertySignatureDialog(project, descriptor, commandName)
else -> throw AssertionError("Unexpected declaration: ${descriptor.baseDeclaration.getElementTextWithContext()}") else -> throw AssertionError("Unexpected declaration: ${descriptor.baseDeclaration.getElementTextWithContext()}")
} }
@@ -53,6 +53,22 @@ import static org.jetbrains.kotlin.idea.refactoring.changeSignature.ChangeSignat
public class JetChangeSignatureHandler implements ChangeSignatureHandler { public class JetChangeSignatureHandler implements ChangeSignatureHandler {
@Nullable @Nullable
public static PsiElement findTargetForRefactoring(@NotNull PsiElement element) { public static PsiElement findTargetForRefactoring(@NotNull PsiElement element) {
PsiElement elementParent = element.getParent();
if ((elementParent instanceof JetNamedFunction || elementParent instanceof JetClass || elementParent instanceof JetProperty)
&& ((JetNamedDeclaration) elementParent).getNameIdentifier() == element) return elementParent;
if (elementParent instanceof JetParameter) {
JetParameter parameter = (JetParameter) elementParent;
JetPrimaryConstructor primaryConstructor = PsiTreeUtil.getParentOfType(parameter, JetPrimaryConstructor.class);
if (parameter.hasValOrVar()
&& (parameter.getNameIdentifier() == element || parameter.getValOrVarKeyword() == element)
&& primaryConstructor != null
&& primaryConstructor.getValueParameterList() == parameter.getParent()) return parameter;
}
if (elementParent instanceof JetSecondaryConstructor &&
((JetSecondaryConstructor) elementParent).getConstructorKeyword() == element) return elementParent;
if (PsiTreeUtil.getParentOfType(element, JetParameterList.class) != null) { if (PsiTreeUtil.getParentOfType(element, JetParameterList.class) != null) {
return PsiTreeUtil.getParentOfType(element, JetFunction.class, JetProperty.class, JetClass.class); return PsiTreeUtil.getParentOfType(element, JetFunction.class, JetProperty.class, JetClass.class);
} }
@@ -62,13 +78,6 @@ public class JetChangeSignatureHandler implements ChangeSignatureHandler {
return PsiTreeUtil.getParentOfType(typeParameterList, JetFunction.class, JetProperty.class, JetClass.class); return PsiTreeUtil.getParentOfType(typeParameterList, JetFunction.class, JetProperty.class, JetClass.class);
} }
PsiElement elementParent = element.getParent();
if ((elementParent instanceof JetNamedFunction || elementParent instanceof JetClass || elementParent instanceof JetProperty)
&& ((JetNamedDeclaration) elementParent).getNameIdentifier() == element) return elementParent;
if (elementParent instanceof JetSecondaryConstructor &&
((JetSecondaryConstructor) elementParent).getConstructorKeyword() == element) return elementParent;
JetExpression calleeExpr; JetExpression calleeExpr;
JetCallElement call = PsiTreeUtil.getParentOfType(element, JetCallElement call = PsiTreeUtil.getParentOfType(element,
JetCallExpression.class, JetCallExpression.class,
@@ -241,8 +250,8 @@ public class JetChangeSignatureHandler implements ChangeSignatureHandler {
return (FunctionDescriptor) descriptor; return (FunctionDescriptor) descriptor;
} }
else if (descriptor instanceof PropertyDescriptor) { else if (descriptor instanceof PropertyDescriptor || descriptor instanceof ValueParameterDescriptor) {
return (PropertyDescriptor) descriptor; return (CallableDescriptor) descriptor;
} }
else { else {
String message = RefactoringBundle.getCannotRefactorMessage(JetRefactoringBundle.message( String message = RefactoringBundle.getCannotRefactorMessage(JetRefactoringBundle.message(
@@ -155,7 +155,8 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
if (parent instanceof JetConstructorCalleeExpression && parent.getParent() instanceof JetDelegatorToSuperCall) if (parent instanceof JetConstructorCalleeExpression && parent.getParent() instanceof JetDelegatorToSuperCall)
result.add(new JetFunctionCallUsage((JetDelegatorToSuperCall)parent.getParent(), functionUsageInfo)); result.add(new JetFunctionCallUsage((JetDelegatorToSuperCall)parent.getParent(), functionUsageInfo));
} }
else if (element instanceof JetSimpleNameExpression && functionPsi instanceof JetProperty) { else if (element instanceof JetSimpleNameExpression
&& (functionPsi instanceof JetProperty || functionPsi instanceof JetParameter)) {
result.add(new JetPropertyCallUsage((JetSimpleNameExpression) element)); result.add(new JetPropertyCallUsage((JetSimpleNameExpression) element));
} }
} }
@@ -151,7 +151,7 @@ public class JetCallableDefinitionUsage<T extends PsiElement> extends JetUsageIn
if (currentCallableDescriptor == null) { if (currentCallableDescriptor == null) {
PsiElement element = getDeclaration(); PsiElement element = getDeclaration();
if (element instanceof JetFunction || element instanceof JetProperty) { if (element instanceof JetFunction || element instanceof JetProperty || element instanceof JetParameter) {
currentCallableDescriptor = (CallableDescriptor) ResolvePackage.resolveToDescriptor((JetDeclaration) element); currentCallableDescriptor = (CallableDescriptor) ResolvePackage.resolveToDescriptor((JetDeclaration) element);
} }
else if (element instanceof JetClass) { else if (element instanceof JetClass) {
@@ -227,7 +227,7 @@ public class JetCallableDefinitionUsage<T extends PsiElement> extends JetUsageIn
callable.getTypeReference() != null); callable.getTypeReference() != null);
} }
else { else {
returnTypeIsNeeded = element instanceof JetProperty; returnTypeIsNeeded = element instanceof JetProperty || element instanceof JetParameter;
} }
if (changeInfo.isReturnTypeChanged() && returnTypeIsNeeded) { if (changeInfo.isReturnTypeChanged() && returnTypeIsNeeded) {
@@ -273,7 +273,7 @@ public class JetCallableDefinitionUsage<T extends PsiElement> extends JetUsageIn
canReplaceEntireList = true; canReplaceEntireList = true;
} }
} }
else if (!(element instanceof JetProperty)) { else if (!(element instanceof JetProperty || element instanceof JetParameter)) {
newParameterList = psiFactory.createParameterList(changeInfo.getNewParametersSignature( newParameterList = psiFactory.createParameterList(changeInfo.getNewParametersSignature(
(JetCallableDefinitionUsage<PsiElement>) this) (JetCallableDefinitionUsage<PsiElement>) this)
); );
@@ -117,7 +117,8 @@ public class JetFunctionCallUsage extends JetUsageInfo<JetCallElement> {
} }
private boolean isPropertyJavaUsage() { private boolean isPropertyJavaUsage() {
return this.callee.getElement() instanceof JetProperty PsiElement calleeElement = this.callee.getElement();
return (calleeElement instanceof JetProperty || calleeElement instanceof JetParameter)
&& resolvedCall != null && resolvedCall.getResultingDescriptor() instanceof JavaMethodDescriptor; && resolvedCall != null && resolvedCall.getResultingDescriptor() instanceof JavaMethodDescriptor;
} }
@@ -0,0 +1,38 @@
import org.jetbrains.annotations.NotNull;
import java.lang.Override;
class J extends A {
private int p;
public J() {
super(0);
}
@NotNull
@Override
public String getS() {
return p;
}
@Override
public void setS(@NotNull String value) {
p = value;
}
}
class Test {
static void test() {
new A(0).getS();
new A(0).setS(1);
new B(0).getS();
new B(0).setS(2);
new C().getS();
new C().setS(3);
new J().getS();
new J().setS(4);
}
}
@@ -0,0 +1,21 @@
open class A(open var <caret>s: String)
class B(override var s: String): A(s)
class C: A(0) {
override var s: String = 1
}
fun test() {
val t1 = A(0).s
A(0).s = 1
val t2 = B(0).s
B(0).s = 2
val t3 = C().s
C().s = 3
val t4 = J().getS()
J().setS(4)
}
@@ -0,0 +1,35 @@
import java.lang.Override;
class J extends A {
private int p;
public J() {
super(0);
}
@Override
public int getP() {
return p;
}
@Override
public void setP(int value) {
p = value;
}
}
class Test {
static void test() {
new A(0).getP();
new A(0).setP(1);
new B(0).getP();
new B(0).setP(2);
new C().getP();
new C().setP(3);
new J().getP();
new J().setP(4);
}
}
@@ -0,0 +1,21 @@
open class A(open var <caret>p: Int)
class B(override var p: Int): A(p)
class C: A(0) {
override var p: Int = 1
}
fun test() {
val t1 = A(0).p
A(0).p = 1
val t2 = B(0).p
B(0).p = 2
val t3 = C().p
C().p = 3
val t4 = J().getP()
J().setP(4)
}
@@ -1,4 +1,4 @@
open class C1 protected (<caret>val x1: Int = 1, var x2: Float, x3: ((Int) -> Int)?) { open class C1 protected <caret>(val x1: Int = 1, var x2: Float, x3: ((Int) -> Int)?) {
fun bar() { fun bar() {
val y1 = x1; val y1 = x1;
val y2 = x2; val y2 = x2;
@@ -1056,6 +1056,13 @@ public class JetChangeSignatureTest extends KotlinCodeInsightTestCase {
doTest(changeInfo); doTest(changeInfo);
} }
public void testChangeClassParameter() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setNewName("s");
changeInfo.setNewReturnTypeText("String");
doTest(changeInfo);
}
@NotNull @NotNull
@Override @Override
protected String getTestDataPath() { protected String getTestDataPath() {