Change Signature: Substitute parameter references in default values of call expression arguments
This commit is contained in:
+5
-1
@@ -54,6 +54,7 @@ import org.jetbrains.kotlin.descriptors.Visibilities;
|
|||||||
import org.jetbrains.kotlin.descriptors.Visibility;
|
import org.jetbrains.kotlin.descriptors.Visibility;
|
||||||
import org.jetbrains.kotlin.idea.JetFileType;
|
import org.jetbrains.kotlin.idea.JetFileType;
|
||||||
import org.jetbrains.kotlin.idea.refactoring.JetRefactoringBundle;
|
import org.jetbrains.kotlin.idea.refactoring.JetRefactoringBundle;
|
||||||
|
import org.jetbrains.kotlin.psi.JetExpression;
|
||||||
import org.jetbrains.kotlin.psi.JetExpressionCodeFragment;
|
import org.jetbrains.kotlin.psi.JetExpressionCodeFragment;
|
||||||
import org.jetbrains.kotlin.psi.JetTypeCodeFragment;
|
import org.jetbrains.kotlin.psi.JetTypeCodeFragment;
|
||||||
import org.jetbrains.kotlin.types.JetType;
|
import org.jetbrains.kotlin.types.JetType;
|
||||||
@@ -459,7 +460,10 @@ public class JetChangeSignatureDialog extends ChangeSignatureDialogBase<
|
|||||||
parameter.setCurrentTypeText(myParametersTableModel.getItems().get(i).typeCodeFragment.getText().trim());
|
parameter.setCurrentTypeText(myParametersTableModel.getItems().get(i).typeCodeFragment.getText().trim());
|
||||||
JetExpressionCodeFragment codeFragment =
|
JetExpressionCodeFragment codeFragment =
|
||||||
(JetExpressionCodeFragment) myParametersTableModel.getItems().get(i).defaultValueCodeFragment;
|
(JetExpressionCodeFragment) myParametersTableModel.getItems().get(i).defaultValueCodeFragment;
|
||||||
parameter.setDefaultValueForCall(codeFragment.getContentElement());
|
JetExpression oldDefaultValue = parameter.getDefaultValueForCall();
|
||||||
|
if (!codeFragment.getText().equals(oldDefaultValue != null ? oldDefaultValue.getText() : "")) {
|
||||||
|
parameter.setDefaultValueForCall(codeFragment.getContentElement());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String returnTypeText = myReturnTypeCodeFragment != null ? myReturnTypeCodeFragment.getText().trim() : "";
|
String returnTypeText = myReturnTypeCodeFragment != null ? myReturnTypeCodeFragment.getText().trim() : "";
|
||||||
|
|||||||
@@ -17,16 +17,22 @@
|
|||||||
package org.jetbrains.kotlin.idea.refactoring.changeSignature
|
package org.jetbrains.kotlin.idea.refactoring.changeSignature
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiReference
|
||||||
import com.intellij.refactoring.changeSignature.ParameterInfo
|
import com.intellij.refactoring.changeSignature.ParameterInfo
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.JetFunctionDefinitionUsage
|
import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.JetFunctionDefinitionUsage
|
||||||
|
import org.jetbrains.kotlin.idea.references.JetReference
|
||||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
import org.jetbrains.kotlin.psi.JetExpression
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.JetModifierList
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.psi.JetParameter
|
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver
|
||||||
import org.jetbrains.kotlin.types.JetType
|
import org.jetbrains.kotlin.types.JetType
|
||||||
|
import java.util.LinkedHashMap
|
||||||
|
|
||||||
public class JetParameterInfo(
|
public class JetParameterInfo(
|
||||||
val functionDescriptor: FunctionDescriptor,
|
val functionDescriptor: FunctionDescriptor,
|
||||||
@@ -41,6 +47,54 @@ public class JetParameterInfo(
|
|||||||
val originalType: JetType? = type
|
val originalType: JetType? = type
|
||||||
var currentTypeText: String = getOldTypeText()
|
var currentTypeText: String = getOldTypeText()
|
||||||
|
|
||||||
|
public val defaultValueParameterReferences: Map<PsiReference, DeclarationDescriptor>
|
||||||
|
|
||||||
|
init {
|
||||||
|
val file = defaultValueForCall?.getContainingFile() as? JetFile
|
||||||
|
defaultValueParameterReferences =
|
||||||
|
if (defaultValueForCall != null && file != null && (file.isPhysical() || file.analysisContext != null)) {
|
||||||
|
val map = LinkedHashMap<PsiReference, DeclarationDescriptor>()
|
||||||
|
|
||||||
|
defaultValueForCall!!.accept(
|
||||||
|
object : JetTreeVisitorVoid() {
|
||||||
|
private fun getRelevantDescriptor(
|
||||||
|
expression: JetSimpleNameExpression,
|
||||||
|
ref: JetReference
|
||||||
|
): DeclarationDescriptor? {
|
||||||
|
val context = expression.analyze(BodyResolveMode.PARTIAL)
|
||||||
|
|
||||||
|
val descriptor = ref.resolveToDescriptors(context).singleOrNull()
|
||||||
|
if (descriptor is ValueParameterDescriptor) return descriptor
|
||||||
|
|
||||||
|
if (descriptor is PropertyDescriptor && functionDescriptor is ConstructorDescriptor) {
|
||||||
|
val parameter = DescriptorToSourceUtils.getSourceFromDescriptor(descriptor) as? JetParameter
|
||||||
|
return parameter?.let { context[BindingContext.VALUE_PARAMETER, it] }
|
||||||
|
}
|
||||||
|
|
||||||
|
val resolvedCall = expression.getResolvedCall(context) ?: return null
|
||||||
|
(resolvedCall.getResultingDescriptor() as? ReceiverParameterDescriptor)?.let { return it }
|
||||||
|
|
||||||
|
(resolvedCall.getExtensionReceiver() as? ThisReceiver)?.let { return it.getDeclarationDescriptor() }
|
||||||
|
(resolvedCall.getDispatchReceiver() as? ThisReceiver)?.let { return it.getDeclarationDescriptor() }
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitSimpleNameExpression(expression: JetSimpleNameExpression) {
|
||||||
|
val ref = expression.getReference() as? JetReference ?: return
|
||||||
|
val descriptor = getRelevantDescriptor(expression, ref) ?: return
|
||||||
|
map[ref] = descriptor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
map
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
emptyMap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun getOldTypeText() = originalType?.let { IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(it) } ?: ""
|
private fun getOldTypeText() = originalType?.let { IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(it) } ?: ""
|
||||||
|
|
||||||
override fun getOldIndex(): Int = originalIndex
|
override fun getOldIndex(): Int = originalIndex
|
||||||
|
|||||||
+180
-17
@@ -17,32 +17,63 @@
|
|||||||
package org.jetbrains.kotlin.idea.refactoring.changeSignature.usages;
|
package org.jetbrains.kotlin.idea.refactoring.changeSignature.usages;
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
|
import com.intellij.psi.PsiReference;
|
||||||
import com.intellij.psi.util.PsiTreeUtil;
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
|
import com.intellij.util.containers.ContainerUtil;
|
||||||
|
import gnu.trove.TIntArrayList;
|
||||||
|
import gnu.trove.TIntProcedure;
|
||||||
|
import kotlin.Function1;
|
||||||
import kotlin.KotlinPackage;
|
import kotlin.KotlinPackage;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage;
|
import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage;
|
||||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo;
|
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo;
|
||||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetParameterInfo;
|
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetParameterInfo;
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.ExtractionEnginePackage;
|
||||||
|
import org.jetbrains.kotlin.idea.util.ShortenReferences;
|
||||||
import org.jetbrains.kotlin.idea.util.psiModificationUtil.PsiModificationUtilPackage;
|
import org.jetbrains.kotlin.idea.util.psiModificationUtil.PsiModificationUtilPackage;
|
||||||
import org.jetbrains.kotlin.psi.*;
|
import org.jetbrains.kotlin.psi.*;
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
|
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument;
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument;
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode;
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver;
|
||||||
|
import org.jetbrains.kotlin.types.JetType;
|
||||||
|
import org.jetbrains.kotlin.types.checker.JetTypeChecker;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.psi.PsiPackage.JetPsiFactory;
|
import static org.jetbrains.kotlin.psi.PsiPackage.JetPsiFactory;
|
||||||
|
|
||||||
public class JetFunctionCallUsage extends JetUsageInfo<JetCallElement> {
|
public class JetFunctionCallUsage extends JetUsageInfo<JetCallElement> {
|
||||||
|
private static final Comparator<Map.Entry<PsiReference, DeclarationDescriptor>>
|
||||||
|
REVERSE_TEXT_OFFSET_COMPARATOR = new Comparator<Map.Entry<PsiReference, DeclarationDescriptor>>() {
|
||||||
|
@Override
|
||||||
|
public int compare(
|
||||||
|
@NotNull Map.Entry<PsiReference, DeclarationDescriptor> o1,
|
||||||
|
@NotNull Map.Entry<PsiReference, DeclarationDescriptor> o2
|
||||||
|
) {
|
||||||
|
int offset1 = o1.getKey().getElement().getTextRange().getStartOffset();
|
||||||
|
int offset2 = o2.getKey().getElement().getTextRange().getStartOffset();
|
||||||
|
return offset1 < offset2 ? 1
|
||||||
|
: offset1 > offset2 ? -1
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final Function1<JetElement, ShortenReferences.Options>
|
||||||
|
SHORTEN_ARGUMENTS_OPTIONS = new Function1<JetElement, ShortenReferences.Options>() {
|
||||||
|
@Override
|
||||||
|
public ShortenReferences.Options invoke(JetElement element) {
|
||||||
|
return new ShortenReferences.Options(true, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private final JetFunctionDefinitionUsage<?> callee;
|
private final JetFunctionDefinitionUsage<?> callee;
|
||||||
private final ResolvedCall<? extends CallableDescriptor> resolvedCall;
|
private final ResolvedCall<? extends CallableDescriptor> resolvedCall;
|
||||||
|
|
||||||
@@ -84,6 +115,111 @@ public class JetFunctionCallUsage extends JetUsageInfo<JetCallElement> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private JetExpression getReceiverExpressionIfMatched(
|
||||||
|
@NotNull ReceiverValue receiverValue,
|
||||||
|
@NotNull DeclarationDescriptor originalDescriptor,
|
||||||
|
@NotNull JetPsiFactory psiFactory
|
||||||
|
) {
|
||||||
|
if (!receiverValue.exists()) return null;
|
||||||
|
|
||||||
|
// Replace descriptor of extension function/property with descriptor of its receiver
|
||||||
|
// to simplify checking against receiver value in the corresponding resolved call
|
||||||
|
if (originalDescriptor instanceof CallableDescriptor && !(originalDescriptor instanceof ReceiverParameterDescriptor)) {
|
||||||
|
ReceiverParameterDescriptor receiverParameter = ((CallableDescriptor) originalDescriptor).getExtensionReceiverParameter();
|
||||||
|
if (receiverParameter == null) return null;
|
||||||
|
originalDescriptor = receiverParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean currentIsExtension = resolvedCall.getExtensionReceiver() == receiverValue;
|
||||||
|
boolean originalIsExtension =
|
||||||
|
originalDescriptor instanceof ReceiverParameterDescriptor &&
|
||||||
|
((ReceiverParameterDescriptor) originalDescriptor).getValue() instanceof ExtensionReceiver;
|
||||||
|
if (currentIsExtension != originalIsExtension) return null;
|
||||||
|
|
||||||
|
JetType originalType = originalDescriptor instanceof ReceiverParameterDescriptor
|
||||||
|
? ((ReceiverParameterDescriptor) originalDescriptor).getType()
|
||||||
|
: originalDescriptor instanceof ClassDescriptor
|
||||||
|
? ((ClassDescriptor) originalDescriptor).getDefaultType()
|
||||||
|
: null;
|
||||||
|
if (originalType == null || !JetTypeChecker.DEFAULT.isSubtypeOf(receiverValue.getType(), originalType)) return null;
|
||||||
|
|
||||||
|
return getReceiverExpression(receiverValue, psiFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private JetExpression substituteReferences(
|
||||||
|
@NotNull JetExpression expression,
|
||||||
|
@NotNull Map<PsiReference, DeclarationDescriptor> referenceMap,
|
||||||
|
@NotNull JetPsiFactory psiFactory
|
||||||
|
) {
|
||||||
|
if (referenceMap.isEmpty() || resolvedCall == null) return expression;
|
||||||
|
|
||||||
|
JetExpression newExpression = (JetExpression) expression.copy();
|
||||||
|
|
||||||
|
Map<JetSimpleNameExpression, JetSimpleNameExpression> nameCounterpartMap =
|
||||||
|
ExtractionEnginePackage.createNameCounterpartMap(expression, newExpression);
|
||||||
|
|
||||||
|
Map<ValueParameterDescriptor, ResolvedValueArgument> valueArguments = resolvedCall.getValueArguments();
|
||||||
|
// Sort by descending offset so that call arguments are replaced before call itself
|
||||||
|
List<Map.Entry<PsiReference, DeclarationDescriptor>> sortedEntries =
|
||||||
|
ContainerUtil.sorted(referenceMap.entrySet(), REVERSE_TEXT_OFFSET_COMPARATOR);
|
||||||
|
for (Map.Entry<PsiReference, DeclarationDescriptor> e : sortedEntries) {
|
||||||
|
DeclarationDescriptor descriptor = e.getValue();
|
||||||
|
|
||||||
|
JetExpression argumentExpression;
|
||||||
|
boolean addReceiver = false;
|
||||||
|
if (descriptor instanceof ValueParameterDescriptor) { // Ordinary parameter
|
||||||
|
// Find corresponding parameter in the current function (may differ from 'descriptor' if original function is part of override hierarchy)
|
||||||
|
ValueParameterDescriptor parameterDescriptor =
|
||||||
|
resolvedCall.getResultingDescriptor().getValueParameters().get(((ValueParameterDescriptor) descriptor).getIndex());
|
||||||
|
|
||||||
|
ResolvedValueArgument resolvedValueArgument = valueArguments.get(parameterDescriptor);
|
||||||
|
if (!(resolvedValueArgument instanceof ExpressionValueArgument)) continue;
|
||||||
|
|
||||||
|
ValueArgument argument = ((ExpressionValueArgument) resolvedValueArgument).getValueArgument();
|
||||||
|
if (argument == null) continue;
|
||||||
|
|
||||||
|
argumentExpression = argument.getArgumentExpression();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
addReceiver = !(descriptor instanceof ReceiverParameterDescriptor);
|
||||||
|
argumentExpression = getReceiverExpressionIfMatched(resolvedCall.getExtensionReceiver(), descriptor, psiFactory);
|
||||||
|
if (argumentExpression == null) {
|
||||||
|
argumentExpression = getReceiverExpressionIfMatched(resolvedCall.getDispatchReceiver(), descriptor, psiFactory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (argumentExpression == null) continue;
|
||||||
|
|
||||||
|
//noinspection SuspiciousMethodCalls
|
||||||
|
JetExpression expressionToReplace = nameCounterpartMap.get(e.getKey().getElement());
|
||||||
|
if (expressionToReplace == null) continue;
|
||||||
|
PsiElement parent = expressionToReplace.getParent();
|
||||||
|
if (parent instanceof JetThisExpression) {
|
||||||
|
expressionToReplace = (JetThisExpression) parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addReceiver) {
|
||||||
|
JetCallExpression callExpression = PsiTreeUtil.getParentOfType(expressionToReplace, JetCallExpression.class, true);
|
||||||
|
if (callExpression != null && PsiTreeUtil.isAncestor(callExpression.getCalleeExpression(), expressionToReplace, false)) {
|
||||||
|
expressionToReplace = callExpression;
|
||||||
|
} else {
|
||||||
|
// Do not substitute operation references in infix/prefix calls
|
||||||
|
if (parent instanceof JetOperationExpression
|
||||||
|
&& ((JetOperationExpression) parent).getOperationReference() == expressionToReplace) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expressionToReplace.replace(psiFactory.createExpression(argumentExpression.getText() + "." + expressionToReplace.getText()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
expressionToReplace.replace(argumentExpression);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newExpression;
|
||||||
|
}
|
||||||
|
|
||||||
private void updateArgumentsAndReceiver(JetChangeInfo changeInfo, JetCallElement element) {
|
private void updateArgumentsAndReceiver(JetChangeInfo changeInfo, JetCallElement element) {
|
||||||
JetValueArgumentList arguments = element.getValueArgumentList();
|
JetValueArgumentList arguments = element.getValueArgumentList();
|
||||||
assert arguments != null : "Argument list is expected: " + element.getText();
|
assert arguments != null : "Argument list is expected: " + element.getText();
|
||||||
@@ -93,15 +229,25 @@ public class JetFunctionCallUsage extends JetUsageInfo<JetCallElement> {
|
|||||||
StringBuilder parametersBuilder = new StringBuilder("(");
|
StringBuilder parametersBuilder = new StringBuilder("(");
|
||||||
boolean isFirst = true;
|
boolean isFirst = true;
|
||||||
|
|
||||||
|
TIntArrayList indicesOfArgumentsWithDefaultValues = new TIntArrayList();
|
||||||
|
|
||||||
|
JetPsiFactory psiFactory = new JetPsiFactory(element.getProject());
|
||||||
|
|
||||||
List<JetParameterInfo> newSignatureParameters = changeInfo.getNonReceiverParameters();
|
List<JetParameterInfo> newSignatureParameters = changeInfo.getNonReceiverParameters();
|
||||||
for (JetParameterInfo parameterInfo : newSignatureParameters) {
|
for (JetParameterInfo parameterInfo : newSignatureParameters) {
|
||||||
if (isFirst)
|
if (isFirst) {
|
||||||
isFirst = false;
|
isFirst = false;
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
parametersBuilder.append(',');
|
parametersBuilder.append(',');
|
||||||
|
}
|
||||||
|
|
||||||
JetExpression defaultValueForCall = parameterInfo.getDefaultValueForCall();
|
JetExpression defaultValueForCall = parameterInfo.getDefaultValueForCall();
|
||||||
String defaultValueText = defaultValueForCall != null ? defaultValueForCall.getText() : "";
|
String defaultValueText = defaultValueForCall != null
|
||||||
|
? substituteReferences(defaultValueForCall,
|
||||||
|
parameterInfo.getDefaultValueParameterReferences(),
|
||||||
|
psiFactory).getText()
|
||||||
|
: "";
|
||||||
|
|
||||||
if (isNamedCall) {
|
if (isNamedCall) {
|
||||||
String newName = parameterInfo.getInheritedName(callee);
|
String newName = parameterInfo.getInheritedName(callee);
|
||||||
@@ -112,10 +258,9 @@ public class JetFunctionCallUsage extends JetUsageInfo<JetCallElement> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parametersBuilder.append(')');
|
parametersBuilder.append(')');
|
||||||
JetValueArgumentList newArguments = JetPsiFactory(getProject()).createCallArguments(parametersBuilder.toString());
|
JetValueArgumentList newArgumentList = JetPsiFactory(getProject()).createCallArguments(parametersBuilder.toString());
|
||||||
|
|
||||||
Map<Integer, ? extends ValueArgument> argumentMap = getParamIndexToArgumentMap(changeInfo, oldArguments);
|
Map<Integer, ? extends ValueArgument> argumentMap = getParamIndexToArgumentMap(changeInfo, oldArguments);
|
||||||
int argIndex = 0;
|
|
||||||
|
|
||||||
JetParameterInfo newReceiverInfo = changeInfo.getReceiverParameterInfo();
|
JetParameterInfo newReceiverInfo = changeInfo.getReceiverParameterInfo();
|
||||||
JetParameterInfo originalReceiverInfo = changeInfo.getMethodDescriptor().getReceiver();
|
JetParameterInfo originalReceiverInfo = changeInfo.getMethodDescriptor().getReceiver();
|
||||||
@@ -123,8 +268,6 @@ public class JetFunctionCallUsage extends JetUsageInfo<JetCallElement> {
|
|||||||
ReceiverValue extensionReceiver = resolvedCall != null ? resolvedCall.getExtensionReceiver() : ReceiverValue.NO_RECEIVER;
|
ReceiverValue extensionReceiver = resolvedCall != null ? resolvedCall.getExtensionReceiver() : ReceiverValue.NO_RECEIVER;
|
||||||
ReceiverValue dispatchReceiver = resolvedCall != null ? resolvedCall.getDispatchReceiver() : ReceiverValue.NO_RECEIVER;
|
ReceiverValue dispatchReceiver = resolvedCall != null ? resolvedCall.getDispatchReceiver() : ReceiverValue.NO_RECEIVER;
|
||||||
|
|
||||||
JetPsiFactory psiFactory = new JetPsiFactory(element.getProject());
|
|
||||||
|
|
||||||
PsiElement elementToReplace = element;
|
PsiElement elementToReplace = element;
|
||||||
PsiElement parent = element.getParent();
|
PsiElement parent = element.getParent();
|
||||||
if (parent instanceof JetQualifiedExpression && ((JetQualifiedExpression) parent).getSelectorExpression() == element) {
|
if (parent instanceof JetQualifiedExpression && ((JetQualifiedExpression) parent).getSelectorExpression() == element) {
|
||||||
@@ -136,13 +279,17 @@ public class JetFunctionCallUsage extends JetUsageInfo<JetCallElement> {
|
|||||||
&& elementToReplace instanceof JetQualifiedExpression
|
&& elementToReplace instanceof JetQualifiedExpression
|
||||||
&& dispatchReceiver instanceof ExpressionReceiver) return;
|
&& dispatchReceiver instanceof ExpressionReceiver) return;
|
||||||
|
|
||||||
for (JetValueArgument newArgument : newArguments.getArguments()) {
|
List<JetValueArgument> newArguments = newArgumentList.getArguments();
|
||||||
JetParameterInfo parameterInfo = newSignatureParameters.get(argIndex++);
|
int actualIndex = 0;
|
||||||
|
for (int i = 0; i < newArguments.size(); i++) {
|
||||||
|
JetValueArgument newArgument = newArguments.get(i);
|
||||||
|
JetParameterInfo parameterInfo = newSignatureParameters.get(i);
|
||||||
if (parameterInfo == originalReceiverInfo) {
|
if (parameterInfo == originalReceiverInfo) {
|
||||||
JetExpression receiverExpression = getReceiverExpression(extensionReceiver, psiFactory);
|
JetExpression receiverExpression = getReceiverExpression(extensionReceiver, psiFactory);
|
||||||
if (receiverExpression != null) {
|
if (receiverExpression != null) {
|
||||||
newArgument.replace(receiverExpression);
|
newArgument.replace(receiverExpression);
|
||||||
}
|
}
|
||||||
|
actualIndex++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,6 +313,9 @@ public class JetFunctionCallUsage extends JetUsageInfo<JetCallElement> {
|
|||||||
newArgument.delete();
|
newArgument.delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
indicesOfArgumentsWithDefaultValues.add(actualIndex++);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<JetFunctionLiteralArgument> lambdaArguments = element.getFunctionLiteralArguments();
|
List<JetFunctionLiteralArgument> lambdaArguments = element.getFunctionLiteralArguments();
|
||||||
@@ -173,10 +323,23 @@ public class JetFunctionCallUsage extends JetUsageInfo<JetCallElement> {
|
|||||||
element.deleteChildRange(KotlinPackage.first(lambdaArguments), KotlinPackage.last(lambdaArguments));
|
element.deleteChildRange(KotlinPackage.first(lambdaArguments), KotlinPackage.last(lambdaArguments));
|
||||||
}
|
}
|
||||||
|
|
||||||
JetValueArgument lastArgument = KotlinPackage.lastOrNull(newArguments.getArguments());
|
JetValueArgument lastArgument = KotlinPackage.lastOrNull(newArgumentList.getArguments());
|
||||||
boolean hasTrailingLambdaInArgumentListAfter = lastArgument != null && lastArgument.getArgumentExpression() instanceof JetFunctionLiteralExpression;
|
boolean hasTrailingLambdaInArgumentListAfter = lastArgument != null && lastArgument.getArgumentExpression() instanceof JetFunctionLiteralExpression;
|
||||||
|
|
||||||
arguments.replace(newArguments);
|
arguments = (JetValueArgumentList) arguments.replace(newArgumentList);
|
||||||
|
|
||||||
|
final List<JetElement> argumentsToShorten = new ArrayList<JetElement>(indicesOfArgumentsWithDefaultValues.size());
|
||||||
|
final List<JetValueArgument> argumentList = arguments.getArguments();
|
||||||
|
indicesOfArgumentsWithDefaultValues.forEach(
|
||||||
|
new TIntProcedure() {
|
||||||
|
@Override
|
||||||
|
public boolean execute(int i) {
|
||||||
|
argumentsToShorten.add(argumentList.get(i));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
new ShortenReferences(SHORTEN_ARGUMENTS_OPTIONS).process(argumentsToShorten);
|
||||||
|
|
||||||
JetElement newElement = element;
|
JetElement newElement = element;
|
||||||
if (newReceiverInfo != originalReceiverInfo) {
|
if (newReceiverInfo != originalReceiverInfo) {
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// WITH_DEFAULT_VALUE: false
|
||||||
|
fun foo(a: Int): Int {
|
||||||
|
val b = 1
|
||||||
|
return (<selection>a + b</selection>) * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo(1)
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// WITH_DEFAULT_VALUE: false
|
||||||
|
fun foo(i: Int): Int {
|
||||||
|
val b = 1
|
||||||
|
return i * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo(1 + b)
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// WITH_DEFAULT_VALUE: false
|
||||||
|
|
||||||
|
fun foo(a: Int, b: Int): Int {
|
||||||
|
return <selection>a * b</selection> / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo(1 + 2, 3 - 4)
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// WITH_DEFAULT_VALUE: false
|
||||||
|
|
||||||
|
fun foo(i: Int): Int {
|
||||||
|
return i / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo((1 + 2) * (3 - 4))
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// WITH_DEFAULT_VALUE: false
|
||||||
|
public inline fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
|
||||||
|
|
||||||
|
class A(val a: Int) {
|
||||||
|
fun A.foo(): Int {
|
||||||
|
return (<selection>this@A.a + a</selection>) / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
A(1).foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
val t = with(A(1)) {
|
||||||
|
A(2).foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// WITH_DEFAULT_VALUE: false
|
||||||
|
public inline fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
|
||||||
|
|
||||||
|
class A(val a: Int) {
|
||||||
|
fun A.foo(i: Int): Int {
|
||||||
|
return i / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
A(1).foo(a + A(1).a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
val t = with(A(1)) {
|
||||||
|
A(2).foo(a + A(2).a)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// WITH_DEFAULT_VALUE: false
|
||||||
|
public inline fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
|
||||||
|
|
||||||
|
class A(val a: Int) {
|
||||||
|
fun foo(x: A): Int {
|
||||||
|
return (<selection>this.a + x.a</selection>) / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
A(1).foo(A(2))
|
||||||
|
with(A(1)) {
|
||||||
|
foo(A(2))
|
||||||
|
this.foo(A(2))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// WITH_DEFAULT_VALUE: false
|
||||||
|
public inline fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
|
||||||
|
|
||||||
|
class A(val a: Int) {
|
||||||
|
fun foo(i: Int): Int {
|
||||||
|
return i / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
A(1).foo(A(1).a + A(2).a)
|
||||||
|
with(A(1)) {
|
||||||
|
foo(a + A(2).a)
|
||||||
|
this.foo(a + A(2).a)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// WITH_DEFAULT_VALUE: false
|
||||||
|
public inline fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
|
||||||
|
|
||||||
|
class A(val a: Int) {
|
||||||
|
fun foo(x: A): Int {
|
||||||
|
return (<selection>a + x.a</selection>) / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
A(1).foo(A(2))
|
||||||
|
with(A(1)) {
|
||||||
|
foo(A(2))
|
||||||
|
this.foo(A(2))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// WITH_DEFAULT_VALUE: false
|
||||||
|
public inline fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
|
||||||
|
|
||||||
|
class A(val a: Int) {
|
||||||
|
fun foo(i: Int): Int {
|
||||||
|
return i / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
A(1).foo(A(1).a + A(2).a)
|
||||||
|
with(A(1)) {
|
||||||
|
foo(a + A(2).a)
|
||||||
|
this.foo(a + A(2).a)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
// WITH_DEFAULT_VALUE: false
|
||||||
|
// TARGET:
|
||||||
|
open class A(val a: Int) {
|
||||||
|
constructor(): this(1)
|
||||||
|
|
||||||
|
fun foo(): Int {
|
||||||
|
return (<selection>a + 1</selection>) / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B: A(1) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class C: A {
|
||||||
|
constructor(n: Int): super(n + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() = A(1)
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
// WITH_DEFAULT_VALUE: false
|
||||||
|
// TARGET:
|
||||||
|
open class A(val a: Int, val i: Int) {
|
||||||
|
constructor(): this(1, 1 + 1)
|
||||||
|
|
||||||
|
fun foo(): Int {
|
||||||
|
return i / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B: A(1, 1 + 1) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class C: A {
|
||||||
|
constructor(n: Int): super(n + 1, n + 1 + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() = A(1, 1 + 1)
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// WITH_DEFAULT_VALUE: false
|
||||||
|
open class A {
|
||||||
|
constructor(): this(1)
|
||||||
|
|
||||||
|
constructor(a: Int) {
|
||||||
|
val t = (<selection>a + 1</selection>) / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B: A {
|
||||||
|
constructor(n: Int): super(n + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
class C: A(1) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() = A(1)
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
// WITH_DEFAULT_VALUE: false
|
||||||
|
open class A {
|
||||||
|
constructor(): this(1 + 1)
|
||||||
|
|
||||||
|
constructor(i: Int) {
|
||||||
|
val t = i / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B: A {
|
||||||
|
constructor(n: Int): super(n + 1 + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
class C: A(1 + 1) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() = A(1 + 1)
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// WITH_DEFAULT_VALUE: false
|
||||||
|
fun foo(a: Int): Int {
|
||||||
|
fun Int.bar(n: Int) = this + n
|
||||||
|
|
||||||
|
return (<selection>a bar 1</selection>) * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo(2)
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// WITH_DEFAULT_VALUE: false
|
||||||
|
fun foo(i: Int): Int {
|
||||||
|
fun Int.bar(n: Int) = this + n
|
||||||
|
|
||||||
|
return i * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo(2 bar 1)
|
||||||
|
}
|
||||||
@@ -5,5 +5,5 @@ fun foo(a: Int, i: Int): Int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun test() {
|
fun test() {
|
||||||
foo(1, a + 1)
|
foo(1, 1 + 1)
|
||||||
}
|
}
|
||||||
@@ -5,5 +5,5 @@ fun foo(i: Int): Int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun test() {
|
fun test() {
|
||||||
foo(a + 1)
|
foo(1 + 1)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// WITH_DEFAULT_VALUE: false
|
||||||
|
fun foo(vararg a: Int): Int {
|
||||||
|
return (<selection>a.size() + 1</selection>) * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo()
|
||||||
|
foo(1)
|
||||||
|
foo(1, 2)
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// WITH_DEFAULT_VALUE: false
|
||||||
|
fun foo(i: Int): Int {
|
||||||
|
return i * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo(a.size() + 1)
|
||||||
|
foo(a.size() + 1)
|
||||||
|
foo(a.size() + 1)
|
||||||
|
}
|
||||||
+54
@@ -2344,6 +2344,12 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
doIntroduceSimpleParameterTest(fileName);
|
doIntroduceSimpleParameterTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("partialSubstitution.kt")
|
||||||
|
public void testPartialSubstitution() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/partialSubstitution.kt");
|
||||||
|
doIntroduceSimpleParameterTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("propertyAccessor.kt")
|
@TestMetadata("propertyAccessor.kt")
|
||||||
public void testPropertyAccessor() throws Exception {
|
public void testPropertyAccessor() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/propertyAccessor.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/propertyAccessor.kt");
|
||||||
@@ -2362,6 +2368,48 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
doIntroduceSimpleParameterTest(fileName);
|
doIntroduceSimpleParameterTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("substituteComplexExpressions.kt")
|
||||||
|
public void testSubstituteComplexExpressions() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/substituteComplexExpressions.kt");
|
||||||
|
doIntroduceSimpleParameterTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("substituteDoubleReceiver.kt")
|
||||||
|
public void testSubstituteDoubleReceiver() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/substituteDoubleReceiver.kt");
|
||||||
|
doIntroduceSimpleParameterTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("substituteExplicitThisInMember.kt")
|
||||||
|
public void testSubstituteExplicitThisInMember() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/substituteExplicitThisInMember.kt");
|
||||||
|
doIntroduceSimpleParameterTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("substituteImplicitThisInMember.kt")
|
||||||
|
public void testSubstituteImplicitThisInMember() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/substituteImplicitThisInMember.kt");
|
||||||
|
doIntroduceSimpleParameterTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("substituteInPrimaryConstructorCall.kt")
|
||||||
|
public void testSubstituteInPrimaryConstructorCall() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/substituteInPrimaryConstructorCall.kt");
|
||||||
|
doIntroduceSimpleParameterTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("substituteInSecondaryConstructorCall.kt")
|
||||||
|
public void testSubstituteInSecondaryConstructorCall() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/substituteInSecondaryConstructorCall.kt");
|
||||||
|
doIntroduceSimpleParameterTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("substituteInfixCall.kt")
|
||||||
|
public void testSubstituteInfixCall() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/substituteInfixCall.kt");
|
||||||
|
doIntroduceSimpleParameterTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("throw.kt")
|
@TestMetadata("throw.kt")
|
||||||
public void testThrow() throws Exception {
|
public void testThrow() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/throw.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/throw.kt");
|
||||||
@@ -2380,6 +2428,12 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
doIntroduceSimpleParameterTest(fileName);
|
doIntroduceSimpleParameterTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("varargs.kt")
|
||||||
|
public void testVarargs() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/varargs.kt");
|
||||||
|
doIntroduceSimpleParameterTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("while.kt")
|
@TestMetadata("while.kt")
|
||||||
public void testWhile() throws Exception {
|
public void testWhile() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/while.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/while.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user