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
}
if (closestModifiableDescriptors.size() == 1 && deepestSuperDeclarations == closestModifiableDescriptors) {
if (closestModifiableDescriptors.size() == 1 && deepestSuperDeclarations.subtract(closestModifiableDescriptors).isEmpty()) {
performRefactoring(closestModifiableDescriptors)
return true
}
@@ -104,7 +104,7 @@ public class JetChangeInfo(
fun getNonReceiverParametersCount(): Int = newParameters.size() - (if (receiverParameterInfo != null) 1 else 0)
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
}
@@ -309,7 +309,7 @@ public class JetChangeInfo(
when (method) {
is JetFunction, is JetClassOrObject ->
createJavaChangeInfoForFunctionOrGetter(originalPsiMethod, currentPsiMethod, false)
is JetProperty -> {
is JetProperty, is JetParameter -> {
val accessorName = originalPsiMethod.getName()
when {
accessorName.startsWith(JvmAbi.GETTER_PREFIX) ->
@@ -51,7 +51,7 @@ public class JetChangePropertySignatureDialog(
)
private val nameField = EditorTextField(methodDescriptor.getName())
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()
private var receiverTypeField: EditorTextField by Delegates.notNull()
var receiverDefaultValueLabel: JLabel? = null
@@ -66,7 +66,7 @@ public class JetChangePropertySignatureDialog(
override fun createCenterPanel(): JComponent? {
fun updateReceiverUI() {
val withReceiver = receiverTypeCheckBox.isSelected()
val withReceiver = receiverTypeCheckBox!!.isSelected()
receiverTypeLabel.setEnabled(withReceiver)
receiverTypeField.setEnabled(withReceiver)
receiverDefaultValueLabel?.setEnabled(withReceiver)
@@ -77,7 +77,8 @@ public class JetChangePropertySignatureDialog(
val psiFactory = JetPsiFactory(myProject)
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())
addLabeledComponent("&Visibility: ", visibilityCombo)
}
@@ -85,38 +86,40 @@ public class JetChangePropertySignatureDialog(
addLabeledComponent("&Name: ", nameField)
val returnTypeCodeFragment = psiFactory.createTypeCodeFragment(methodDescriptor.renderOriginalReturnType(),
methodDescriptor.baseDeclaration)
baseDeclaration)
returnTypeField = EditorTextField(documentManager.getDocument(returnTypeCodeFragment), myProject, JetFileType.INSTANCE)
addLabeledComponent("&Type: ", returnTypeField)
addSeparator()
if (baseDeclaration is JetProperty) {
addSeparator()
val receiverTypeCheckBox = JCheckBox("Extension property: ")
receiverTypeCheckBox.setMnemonic('x')
receiverTypeCheckBox.addActionListener { updateReceiverUI() }
receiverTypeCheckBox.setSelected(methodDescriptor.receiver != null)
addComponent(receiverTypeCheckBox)
this@JetChangePropertySignatureDialog.receiverTypeCheckBox = receiverTypeCheckBox
val receiverTypeCheckBox = JCheckBox("Extension property: ")
receiverTypeCheckBox.setMnemonic('x')
receiverTypeCheckBox.addActionListener { updateReceiverUI() }
receiverTypeCheckBox.setSelected(methodDescriptor.receiver != null)
addComponent(receiverTypeCheckBox)
this@JetChangePropertySignatureDialog.receiverTypeCheckBox = receiverTypeCheckBox
val receiverTypeCodeFragment = psiFactory.createTypeCodeFragment(methodDescriptor.renderOriginalReceiverType() ?: "",
methodDescriptor.baseDeclaration)
receiverTypeField = EditorTextField(documentManager.getDocument(receiverTypeCodeFragment), myProject, JetFileType.INSTANCE)
receiverTypeLabel = JLabel("Receiver type: ")
receiverTypeLabel.setDisplayedMnemonic('t')
addLabeledComponent(receiverTypeLabel, receiverTypeField)
val receiverTypeCodeFragment = psiFactory.createTypeCodeFragment(methodDescriptor.renderOriginalReceiverType() ?: "",
methodDescriptor.baseDeclaration)
receiverTypeField = EditorTextField(documentManager.getDocument(receiverTypeCodeFragment), myProject, JetFileType.INSTANCE)
receiverTypeLabel = JLabel("Receiver type: ")
receiverTypeLabel.setDisplayedMnemonic('t')
addLabeledComponent(receiverTypeLabel, receiverTypeField)
if (methodDescriptor.receiver == null) {
val receiverDefaultValueCodeFragment = psiFactory.createExpressionCodeFragment("", methodDescriptor.baseDeclaration)
receiverDefaultValueField = EditorTextField(documentManager.getDocument(receiverDefaultValueCodeFragment),
myProject,
JetFileType.INSTANCE)
receiverDefaultValueLabel = JLabel("Default receiver value: ")
receiverDefaultValueLabel!!.setDisplayedMnemonic('D')
addLabeledComponent(receiverDefaultValueLabel, receiverDefaultValueField!!)
if (methodDescriptor.receiver == null) {
val receiverDefaultValueCodeFragment = psiFactory.createExpressionCodeFragment("", methodDescriptor.baseDeclaration)
receiverDefaultValueField = EditorTextField(documentManager.getDocument(receiverDefaultValueCodeFragment),
myProject,
JetFileType.INSTANCE)
receiverDefaultValueLabel = JLabel("Default receiver value: ")
receiverDefaultValueLabel!!.setDisplayedMnemonic('D')
addLabeledComponent(receiverDefaultValueLabel, receiverDefaultValueField!!)
}
updateReceiverUI()
}
updateReceiverUI()
getPanel()
}
}
@@ -131,7 +134,7 @@ public class JetChangePropertySignatureDialog(
psiFactory.createSimpleName(nameField.getText()).validateElement("Invalid name")
psiFactory.createType(returnTypeField.getText()).validateElement("Invalid return type")
if (receiverTypeCheckBox.isSelected()) {
if (receiverTypeCheckBox?.isSelected() ?: false) {
psiFactory.createType(receiverTypeField.getText()).validateElement("Invalid receiver type")
}
getDefaultReceiverValue()?.validateElement("Invalid default receiver value")
@@ -140,7 +143,7 @@ public class JetChangePropertySignatureDialog(
override fun doAction() {
val descriptor = (methodDescriptor as? JetMutableMethodDescriptor)?.original ?: methodDescriptor
val receiver = if (receiverTypeCheckBox.isSelected()) {
val receiver = if (receiverTypeCheckBox?.isSelected() ?: false) {
descriptor.receiver ?: JetParameterInfo(callableDescriptor = descriptor.baseDescriptor,
name = "receiver",
defaultValueForCall = getDefaultReceiverValue())
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.refactoring.CallableRefactoring
import org.jetbrains.kotlin.psi.JetClass
import org.jetbrains.kotlin.psi.JetFunction
import org.jetbrains.kotlin.psi.JetParameter
import org.jetbrains.kotlin.psi.JetProperty
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
import org.jetbrains.kotlin.resolve.BindingContext
@@ -79,7 +80,7 @@ public class JetChangeSignature(project: Project,
is JetFunction, is JetClass -> {
JetChangeSignatureDialog.createRefactoringProcessorForSilentChangeSignature(project, commandName, descriptor, defaultValueContext)
}
is JetProperty -> {
is JetProperty, is JetParameter -> {
JetChangePropertySignatureDialog.createProcessorForSilentRefactoring(project, commandName, descriptor)
}
else -> throw AssertionError("Unexpected declaration: ${descriptor.baseDeclaration.getElementTextWithContext()}")
@@ -90,7 +91,7 @@ public class JetChangeSignature(project: Project,
private fun runInteractiveRefactoring(descriptor: JetMethodDescriptor) {
val dialog = when (descriptor.baseDeclaration) {
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()}")
}
@@ -53,6 +53,22 @@ import static org.jetbrains.kotlin.idea.refactoring.changeSignature.ChangeSignat
public class JetChangeSignatureHandler implements ChangeSignatureHandler {
@Nullable
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) {
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);
}
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;
JetCallElement call = PsiTreeUtil.getParentOfType(element,
JetCallExpression.class,
@@ -241,8 +250,8 @@ public class JetChangeSignatureHandler implements ChangeSignatureHandler {
return (FunctionDescriptor) descriptor;
}
else if (descriptor instanceof PropertyDescriptor) {
return (PropertyDescriptor) descriptor;
else if (descriptor instanceof PropertyDescriptor || descriptor instanceof ValueParameterDescriptor) {
return (CallableDescriptor) descriptor;
}
else {
String message = RefactoringBundle.getCannotRefactorMessage(JetRefactoringBundle.message(
@@ -155,7 +155,8 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
if (parent instanceof JetConstructorCalleeExpression && parent.getParent() instanceof JetDelegatorToSuperCall)
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));
}
}
@@ -151,7 +151,7 @@ public class JetCallableDefinitionUsage<T extends PsiElement> extends JetUsageIn
if (currentCallableDescriptor == null) {
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);
}
else if (element instanceof JetClass) {
@@ -227,7 +227,7 @@ public class JetCallableDefinitionUsage<T extends PsiElement> extends JetUsageIn
callable.getTypeReference() != null);
}
else {
returnTypeIsNeeded = element instanceof JetProperty;
returnTypeIsNeeded = element instanceof JetProperty || element instanceof JetParameter;
}
if (changeInfo.isReturnTypeChanged() && returnTypeIsNeeded) {
@@ -273,7 +273,7 @@ public class JetCallableDefinitionUsage<T extends PsiElement> extends JetUsageIn
canReplaceEntireList = true;
}
}
else if (!(element instanceof JetProperty)) {
else if (!(element instanceof JetProperty || element instanceof JetParameter)) {
newParameterList = psiFactory.createParameterList(changeInfo.getNewParametersSignature(
(JetCallableDefinitionUsage<PsiElement>) this)
);
@@ -117,7 +117,8 @@ public class JetFunctionCallUsage extends JetUsageInfo<JetCallElement> {
}
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;
}
@@ -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() {
val y1 = x1;
val y2 = x2;
@@ -1056,6 +1056,13 @@ public class JetChangeSignatureTest extends KotlinCodeInsightTestCase {
doTest(changeInfo);
}
public void testChangeClassParameter() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setNewName("s");
changeInfo.setNewReturnTypeText("String");
doTest(changeInfo);
}
@NotNull
@Override
protected String getTestDataPath() {