J2K: JetFunctionCallUsage
This commit is contained in:
+337
-456
@@ -14,582 +14,463 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.idea.refactoring.changeSignature.usages;
|
package org.jetbrains.kotlin.idea.refactoring.changeSignature.usages
|
||||||
|
|
||||||
import com.intellij.openapi.util.Ref;
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiReference
|
||||||
import com.intellij.psi.PsiReference;
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import com.intellij.psi.util.PsiTreeUtil;
|
import com.intellij.usageView.UsageInfo
|
||||||
import com.intellij.usageView.UsageInfo;
|
import com.intellij.util.containers.ContainerUtil
|
||||||
import com.intellij.util.containers.ContainerUtil;
|
import gnu.trove.TIntArrayList
|
||||||
import gnu.trove.TIntArrayList;
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import gnu.trove.TIntProcedure;
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import kotlin.ArraysKt;
|
import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet
|
||||||
import kotlin.CollectionsKt;
|
import org.jetbrains.kotlin.idea.core.moveFunctionLiteralOutsideParentheses
|
||||||
import kotlin.Pair;
|
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo
|
||||||
import kotlin.Unit;
|
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetParameterInfo
|
||||||
import kotlin.jvm.functions.Function1;
|
import org.jetbrains.kotlin.idea.refactoring.changeSignature.isInsideOfCallerBody
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.createNameCounterpartMap
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.KotlinIntroduceVariableHandler
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.idea.util.ShortenReferences
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils;
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.shorten.ShortenWaitingSetKt;
|
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
|
||||||
import org.jetbrains.kotlin.idea.core.PsiModificationUtilsKt;
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.ChangeSignatureUtilsKt;
|
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
|
||||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo;
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetParameterInfo;
|
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||||
import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.ExtractorUtilKt;
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.KotlinIntroduceVariableHandler;
|
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
|
||||||
import org.jetbrains.kotlin.idea.util.ShortenReferences;
|
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess
|
||||||
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor;
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.psi.*;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.*;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode;
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver;
|
import org.jetbrains.kotlin.utils.sure
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
import java.util.*
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver;
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType;
|
|
||||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
|
||||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions;
|
|
||||||
|
|
||||||
import java.util.*;
|
class JetFunctionCallUsage(
|
||||||
|
element: KtCallElement,
|
||||||
|
private val callee: JetCallableDefinitionUsage<*>
|
||||||
|
) : JetUsageInfo<KtCallElement>(element) {
|
||||||
|
private val context = element.analyze(BodyResolveMode.FULL)
|
||||||
|
private val resolvedCall = element.getResolvedCall(context)
|
||||||
|
|
||||||
public class JetFunctionCallUsage extends JetUsageInfo<KtCallElement> {
|
override fun processUsage(changeInfo: JetChangeInfo, element: KtCallElement, allUsages: Array<out UsageInfo>): Boolean {
|
||||||
private static final Comparator<Pair<KtElement, KtElement>>
|
if (shouldSkipUsage(element)) return true
|
||||||
REVERSED_TEXT_OFFSET_COMPARATOR = new Comparator<Pair<KtElement, KtElement>>() {
|
|
||||||
@Override
|
|
||||||
public int compare(
|
|
||||||
@NotNull Pair<KtElement, KtElement> p1,
|
|
||||||
@NotNull Pair<KtElement, KtElement> p2
|
|
||||||
) {
|
|
||||||
int offset1 = p1.getFirst().getTextRange().getStartOffset();
|
|
||||||
int offset2 = p2.getFirst().getTextRange().getStartOffset();
|
|
||||||
return offset1 < offset2 ? 1
|
|
||||||
: offset1 > offset2 ? -1
|
|
||||||
: 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final ShortenReferences.Options SHORTEN_ARGUMENTS_OPTIONS = new ShortenReferences.Options(true, true);
|
changeNameIfNeeded(changeInfo, element)
|
||||||
|
|
||||||
private final JetCallableDefinitionUsage<?> callee;
|
if (element.valueArgumentList != null) {
|
||||||
private final BindingContext context;
|
if (changeInfo.isParameterSetOrOrderChanged) {
|
||||||
private final ResolvedCall<? extends CallableDescriptor> resolvedCall;
|
updateArgumentsAndReceiver(changeInfo, element, allUsages)
|
||||||
|
|
||||||
public JetFunctionCallUsage(@NotNull KtCallElement element, JetCallableDefinitionUsage callee) {
|
|
||||||
super(element);
|
|
||||||
this.callee = callee;
|
|
||||||
this.context = ResolutionUtils.analyze(element, BodyResolveMode.FULL);
|
|
||||||
this.resolvedCall = CallUtilKt.getResolvedCall(element, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean processUsage(@NotNull JetChangeInfo changeInfo, @NotNull KtCallElement element, @NotNull UsageInfo[] allUsages) {
|
|
||||||
if (shouldSkipUsage(element)) return true;
|
|
||||||
|
|
||||||
changeNameIfNeeded(changeInfo, element);
|
|
||||||
|
|
||||||
if (element.getValueArgumentList() != null) {
|
|
||||||
if (changeInfo.isParameterSetOrOrderChanged()) {
|
|
||||||
updateArgumentsAndReceiver(changeInfo, element, allUsages);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
changeArgumentNames(changeInfo, element);
|
changeArgumentNames(changeInfo, element)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changeInfo.getNewParametersCount() == 0
|
if (changeInfo.getNewParametersCount() == 0 && element is KtDelegatorToSuperCall) {
|
||||||
&& element instanceof KtDelegatorToSuperCall) {
|
val enumEntry = element.getStrictParentOfType<KtEnumEntry>()
|
||||||
KtEnumEntry enumEntry = PsiTreeUtil.getParentOfType(element, KtEnumEntry.class, true);
|
if (enumEntry != null && enumEntry.initializerList == element.parent) {
|
||||||
if (enumEntry != null && enumEntry.getInitializerList() == element.getParent()) {
|
val initializerList = enumEntry.initializerList
|
||||||
PsiElement colon = enumEntry.getColon();
|
enumEntry.deleteChildRange(enumEntry.getColon() ?: initializerList, initializerList)
|
||||||
KtInitializerList initializerList = enumEntry.getInitializerList();
|
|
||||||
enumEntry.deleteChildRange(colon != null ? colon : initializerList, initializerList);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldSkipUsage(KtCallElement element) {
|
private fun shouldSkipUsage(element: KtCallElement): Boolean {
|
||||||
// TODO: We probable need more clever processing of invalid calls, but for now default to Java-like behaviour
|
// TODO: We probable need more clever processing of invalid calls, but for now default to Java-like behaviour
|
||||||
if (resolvedCall == null && !(element instanceof KtDelegatorToSuperCall)) return true;
|
if (resolvedCall == null && element !is KtDelegatorToSuperCall) return true
|
||||||
if (resolvedCall != null && !ArgumentMappingKt.isReallySuccess(resolvedCall)) {
|
if (resolvedCall == null || resolvedCall.isReallySuccess()) return false
|
||||||
// TODO: investigate why arguments are not recorded for enum constructor call
|
|
||||||
if (element instanceof KtDelegatorToSuperCall && element.getParent().getParent() instanceof KtEnumEntry) return false;
|
// TODO: investigate why arguments are not recorded for enum constructor call
|
||||||
for (ValueArgument valueArgument : resolvedCall.getCall().getValueArguments()) {
|
if (element is KtDelegatorToSuperCall && element.parent.parent is KtEnumEntry) return false
|
||||||
if (!(resolvedCall.getArgumentMapping(valueArgument) instanceof ArgumentMatch)) return true;
|
|
||||||
}
|
if (!resolvedCall.call.valueArguments.all{ resolvedCall.getArgumentMapping(it) is ArgumentMatch }) return true
|
||||||
Map<ValueParameterDescriptor, ResolvedValueArgument> arguments = resolvedCall.getValueArguments();
|
|
||||||
for (ValueParameterDescriptor valueParameter : resolvedCall.getResultingDescriptor().getValueParameters()) {
|
val arguments = resolvedCall.valueArguments
|
||||||
if (!arguments.containsKey(valueParameter)) return true;
|
return !resolvedCall.resultingDescriptor.valueParameters.all{ arguments.containsKey(it) }
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isPropertyJavaUsage() {
|
private val isPropertyJavaUsage: Boolean
|
||||||
PsiElement calleeElement = this.callee.getElement();
|
get() {
|
||||||
return (calleeElement instanceof KtProperty || calleeElement instanceof KtParameter)
|
val calleeElement = this.callee.element
|
||||||
&& resolvedCall != null && resolvedCall.getResultingDescriptor() instanceof JavaMethodDescriptor;
|
if (calleeElement !is KtProperty && calleeElement !is KtParameter) return false
|
||||||
}
|
return resolvedCall?.resultingDescriptor is JavaMethodDescriptor
|
||||||
|
|
||||||
protected void changeNameIfNeeded(JetChangeInfo changeInfo, KtCallElement element) {
|
|
||||||
if (!changeInfo.isNameChanged()) return;
|
|
||||||
|
|
||||||
KtExpression callee = element.getCalleeExpression();
|
|
||||||
if (!(callee instanceof KtSimpleNameExpression)) return;
|
|
||||||
|
|
||||||
String newName = changeInfo.getNewName();
|
|
||||||
if (isPropertyJavaUsage()) {
|
|
||||||
String currentName = ((KtSimpleNameExpression) callee).getReferencedName();
|
|
||||||
if (JvmAbi.isGetterName(currentName)) newName = JvmAbi.getterName(newName);
|
|
||||||
else if (JvmAbi.isSetterName(currentName)) newName = JvmAbi.setterName(newName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
callee.replace(KtPsiFactoryKt.KtPsiFactory(getProject()).createSimpleName(newName));
|
protected fun changeNameIfNeeded(changeInfo: JetChangeInfo, element: KtCallElement) {
|
||||||
|
if (!changeInfo.isNameChanged) return
|
||||||
|
|
||||||
|
val callee = element.calleeExpression
|
||||||
|
if (callee !is KtSimpleNameExpression) return
|
||||||
|
|
||||||
|
var newName = changeInfo.newName
|
||||||
|
if (isPropertyJavaUsage) {
|
||||||
|
val currentName = callee.getReferencedName()
|
||||||
|
if (JvmAbi.isGetterName(currentName))
|
||||||
|
newName = JvmAbi.getterName(newName)
|
||||||
|
else if (JvmAbi.isSetterName(currentName)) newName = JvmAbi.setterName(newName)
|
||||||
|
}
|
||||||
|
|
||||||
|
callee.replace(KtPsiFactory(project).createSimpleName(newName))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
private fun getReceiverExpressionIfMatched(
|
||||||
private KtExpression getReceiverExpressionIfMatched(
|
receiverValue: ReceiverValue,
|
||||||
@NotNull ReceiverValue receiverValue,
|
originalDescriptor: DeclarationDescriptor,
|
||||||
@NotNull DeclarationDescriptor originalDescriptor,
|
psiFactory: KtPsiFactory
|
||||||
@NotNull KtPsiFactory psiFactory
|
): KtExpression? {
|
||||||
) {
|
if (!receiverValue.exists()) return null
|
||||||
if (!receiverValue.exists()) return null;
|
|
||||||
|
|
||||||
// Replace descriptor of extension function/property with descriptor of its receiver
|
// Replace descriptor of extension function/property with descriptor of its receiver
|
||||||
// to simplify checking against receiver value in the corresponding resolved call
|
// to simplify checking against receiver value in the corresponding resolved call
|
||||||
if (originalDescriptor instanceof CallableDescriptor && !(originalDescriptor instanceof ReceiverParameterDescriptor)) {
|
val adjustedDescriptor = if (originalDescriptor is CallableDescriptor && originalDescriptor !is ReceiverParameterDescriptor) {
|
||||||
ReceiverParameterDescriptor receiverParameter = ((CallableDescriptor) originalDescriptor).getExtensionReceiverParameter();
|
originalDescriptor.extensionReceiverParameter ?: return null
|
||||||
if (receiverParameter == null) return null;
|
|
||||||
originalDescriptor = receiverParameter;
|
|
||||||
}
|
}
|
||||||
|
else originalDescriptor
|
||||||
|
|
||||||
boolean currentIsExtension = resolvedCall.getExtensionReceiver() == receiverValue;
|
val currentIsExtension = resolvedCall!!.extensionReceiver == receiverValue
|
||||||
boolean originalIsExtension =
|
val originalIsExtension = adjustedDescriptor is ReceiverParameterDescriptor && adjustedDescriptor.value is ExtensionReceiver
|
||||||
originalDescriptor instanceof ReceiverParameterDescriptor &&
|
if (currentIsExtension != originalIsExtension) return null
|
||||||
((ReceiverParameterDescriptor) originalDescriptor).getValue() instanceof ExtensionReceiver;
|
|
||||||
if (currentIsExtension != originalIsExtension) return null;
|
|
||||||
|
|
||||||
KotlinType originalType = originalDescriptor instanceof ReceiverParameterDescriptor
|
val originalType = when (adjustedDescriptor) {
|
||||||
? ((ReceiverParameterDescriptor) originalDescriptor).getType()
|
is ReceiverParameterDescriptor -> adjustedDescriptor.type
|
||||||
: originalDescriptor instanceof ClassDescriptor
|
is ClassDescriptor -> adjustedDescriptor.defaultType
|
||||||
? ((ClassDescriptor) originalDescriptor).getDefaultType()
|
else -> null
|
||||||
: null;
|
}
|
||||||
if (originalType == null || !KotlinTypeChecker.DEFAULT.isSubtypeOf(receiverValue.getType(), originalType)) return null;
|
if (originalType == null || !KotlinTypeChecker.DEFAULT.isSubtypeOf(receiverValue.type, originalType)) return null
|
||||||
|
|
||||||
return getReceiverExpression(receiverValue, psiFactory);
|
return getReceiverExpression(receiverValue, psiFactory)
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean needSeparateVariable(@NotNull PsiElement element) {
|
private fun needSeparateVariable(element: PsiElement): Boolean {
|
||||||
if (element instanceof KtConstantExpression) return false;
|
return when {
|
||||||
if (element instanceof KtThisExpression) return false;
|
element is KtConstantExpression, element is KtThisExpression, element is KtSimpleNameExpression -> false
|
||||||
if (element instanceof KtSimpleNameExpression) return false;
|
element is KtBinaryExpression && OperatorConventions.ASSIGNMENT_OPERATIONS.containsKeyRaw(element.operationToken) -> true
|
||||||
|
element is KtUnaryExpression && OperatorConventions.INCREMENT_OPERATIONS.containsRaw(element.operationToken) -> true
|
||||||
//noinspection SuspiciousMethodCalls
|
element is KtCallExpression -> element.getResolvedCall(context)?.resultingDescriptor is ConstructorDescriptor
|
||||||
if (element instanceof KtBinaryExpression
|
else -> element.children.any { needSeparateVariable(it) }
|
||||||
&& OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(((KtBinaryExpression) element).getOperationToken())) return true;
|
|
||||||
|
|
||||||
//noinspection SuspiciousMethodCalls
|
|
||||||
if (element instanceof KtUnaryExpression
|
|
||||||
&& OperatorConventions.INCREMENT_OPERATIONS.contains(((KtUnaryExpression) element).getOperationToken())) return true;
|
|
||||||
|
|
||||||
if (element instanceof KtCallExpression) {
|
|
||||||
ResolvedCall<? extends CallableDescriptor> resolvedCall =
|
|
||||||
CallUtilKt.getResolvedCall((KtCallExpression) element, context);
|
|
||||||
return resolvedCall != null && resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (PsiElement child : element.getChildren()) {
|
|
||||||
if (needSeparateVariable(child)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
private fun substituteReferences(
|
||||||
private KtExpression substituteReferences(
|
expression: KtExpression,
|
||||||
@NotNull KtExpression expression,
|
referenceMap: Map<PsiReference, DeclarationDescriptor>,
|
||||||
@NotNull Map<PsiReference, DeclarationDescriptor> referenceMap,
|
psiFactory: KtPsiFactory
|
||||||
@NotNull final KtPsiFactory psiFactory
|
): KtExpression {
|
||||||
) {
|
if (referenceMap.isEmpty() || resolvedCall == null) return expression
|
||||||
if (referenceMap.isEmpty() || resolvedCall == null) return expression;
|
|
||||||
|
|
||||||
KtExpression newExpression = (KtExpression) expression.copy();
|
val newExpression = expression.copy() as KtExpression
|
||||||
|
|
||||||
Map<KtSimpleNameExpression, KtSimpleNameExpression> nameCounterpartMap =
|
val nameCounterpartMap = createNameCounterpartMap(expression, newExpression)
|
||||||
ExtractorUtilKt.createNameCounterpartMap(expression, newExpression);
|
|
||||||
|
|
||||||
Map<ValueParameterDescriptor, ResolvedValueArgument> valueArguments = resolvedCall.getValueArguments();
|
val valueArguments = resolvedCall.valueArguments
|
||||||
|
|
||||||
List<Pair<KtElement, KtElement>> replacements = new ArrayList<Pair<KtElement, KtElement>>();
|
val replacements = ArrayList<Pair<KtElement, KtElement>>()
|
||||||
for (Map.Entry<PsiReference, DeclarationDescriptor> e : referenceMap.entrySet()) {
|
loop@ for ((ref, descriptor) in referenceMap.entries) {
|
||||||
DeclarationDescriptor descriptor = e.getValue();
|
var argumentExpression: KtExpression?
|
||||||
|
val addReceiver: Boolean
|
||||||
KtExpression argumentExpression;
|
if (descriptor is ValueParameterDescriptor) {
|
||||||
boolean addReceiver = false;
|
// Ordinary parameter
|
||||||
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)
|
// Find corresponding parameter in the current function (may differ from 'descriptor' if original function is part of override hierarchy)
|
||||||
ValueParameterDescriptor parameterDescriptor =
|
val parameterDescriptor = resolvedCall.resultingDescriptor.valueParameters[descriptor.index]
|
||||||
resolvedCall.getResultingDescriptor().getValueParameters().get(((ValueParameterDescriptor) descriptor).getIndex());
|
val resolvedValueArgument = valueArguments[parameterDescriptor] as? ExpressionValueArgument ?: continue
|
||||||
|
val argument = resolvedValueArgument.valueArgument ?: continue
|
||||||
|
|
||||||
ResolvedValueArgument resolvedValueArgument = valueArguments.get(parameterDescriptor);
|
addReceiver = false
|
||||||
if (!(resolvedValueArgument instanceof ExpressionValueArgument)) continue;
|
argumentExpression = argument.getArgumentExpression()
|
||||||
|
|
||||||
ValueArgument argument = ((ExpressionValueArgument) resolvedValueArgument).getValueArgument();
|
|
||||||
if (argument == null) continue;
|
|
||||||
|
|
||||||
argumentExpression = argument.getArgumentExpression();
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
addReceiver = !(descriptor instanceof ReceiverParameterDescriptor);
|
addReceiver = descriptor !is ReceiverParameterDescriptor
|
||||||
argumentExpression = getReceiverExpressionIfMatched(resolvedCall.getExtensionReceiver(), descriptor, psiFactory);
|
argumentExpression = getReceiverExpressionIfMatched(resolvedCall.extensionReceiver, descriptor, psiFactory)
|
||||||
if (argumentExpression == null) {
|
?: getReceiverExpressionIfMatched(resolvedCall.dispatchReceiver, descriptor, psiFactory)
|
||||||
argumentExpression = getReceiverExpressionIfMatched(resolvedCall.getDispatchReceiver(), descriptor, psiFactory);
|
}
|
||||||
|
if (argumentExpression == null) continue
|
||||||
|
|
||||||
|
if (needSeparateVariable(argumentExpression)
|
||||||
|
&& PsiTreeUtil.getNonStrictParentOfType(element,
|
||||||
|
KtConstructorDelegationCall::class.java,
|
||||||
|
KtDelegationSpecifier::class.java,
|
||||||
|
KtParameter::class.java) == null) {
|
||||||
|
|
||||||
|
KotlinIntroduceVariableHandler.doRefactoring(project, null, argumentExpression, listOf(argumentExpression)) {
|
||||||
|
argumentExpression = psiFactory.createExpression(it.name!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (argumentExpression == null) continue;
|
|
||||||
|
|
||||||
//noinspection unchecked
|
var expressionToReplace: KtExpression = nameCounterpartMap.getRaw(ref.element) ?: continue
|
||||||
if (needSeparateVariable(argumentExpression) &&
|
val parent = expressionToReplace.parent
|
||||||
PsiTreeUtil.getNonStrictParentOfType(getElement(),
|
|
||||||
KtConstructorDelegationCall.class,
|
|
||||||
KtDelegationSpecifier.class,
|
|
||||||
KtParameter.class) == null) {
|
|
||||||
|
|
||||||
final Ref<KtExpression> newExpressionRef = new Ref<KtExpression>();
|
if (parent is KtThisExpression) {
|
||||||
KotlinIntroduceVariableHandler.doRefactoring(
|
expressionToReplace = parent
|
||||||
getProject(),
|
|
||||||
null,
|
|
||||||
argumentExpression,
|
|
||||||
Collections.singletonList(argumentExpression),
|
|
||||||
new Function1<KtProperty, Unit>() {
|
|
||||||
@Override
|
|
||||||
public Unit invoke(KtProperty property) {
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
newExpressionRef.set(psiFactory.createExpression(property.getName()));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
argumentExpression = newExpressionRef.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
//noinspection SuspiciousMethodCalls
|
|
||||||
KtExpression expressionToReplace = nameCounterpartMap.get(e.getKey().getElement());
|
|
||||||
if (expressionToReplace == null) continue;
|
|
||||||
PsiElement parent = expressionToReplace.getParent();
|
|
||||||
if (parent instanceof KtThisExpression) {
|
|
||||||
expressionToReplace = (KtThisExpression) parent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addReceiver) {
|
if (addReceiver) {
|
||||||
KtCallExpression callExpression = PsiTreeUtil.getParentOfType(expressionToReplace, KtCallExpression.class, true);
|
val callExpression = expressionToReplace.getParentOfTypeAndBranch<KtCallExpression>(true) { calleeExpression }
|
||||||
if (callExpression != null && PsiTreeUtil.isAncestor(callExpression.getCalleeExpression(), expressionToReplace, false)) {
|
when {
|
||||||
expressionToReplace = callExpression;
|
callExpression != null -> expressionToReplace = callExpression
|
||||||
} else {
|
parent is KtOperationExpression && parent.operationReference == expressionToReplace -> continue@loop
|
||||||
// Do not substitute operation references in infix/prefix calls
|
|
||||||
if (parent instanceof KtOperationExpression
|
|
||||||
&& ((KtOperationExpression) parent).getOperationReference() == expressionToReplace) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
replacements.add(
|
|
||||||
new Pair<KtElement, KtElement>(
|
val replacement = psiFactory.createExpression("${argumentExpression!!.text}.${expressionToReplace.text}")
|
||||||
expressionToReplace,
|
replacements.add(expressionToReplace to replacement)
|
||||||
psiFactory.createExpression(argumentExpression.getText() + "." + expressionToReplace.getText())
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
replacements.add(new Pair<KtElement, KtElement>(expressionToReplace, argumentExpression));
|
replacements.add(expressionToReplace to argumentExpression!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort by descending offset so that call arguments are replaced before call itself
|
// Sort by descending offset so that call arguments are replaced before call itself
|
||||||
ContainerUtil.sort(replacements, REVERSED_TEXT_OFFSET_COMPARATOR);
|
ContainerUtil.sort(replacements, REVERSED_TEXT_OFFSET_COMPARATOR)
|
||||||
for (Pair<KtElement, KtElement> replacement : replacements) {
|
for ((expressionToReplace, replacingExpression) in replacements) {
|
||||||
replacement.getFirst().replace(replacement.getSecond());
|
expressionToReplace.replace(replacingExpression)
|
||||||
}
|
}
|
||||||
|
|
||||||
return newExpression;
|
return newExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateArgumentsAndReceiver(JetChangeInfo changeInfo, KtCallElement element, @NotNull UsageInfo[] allUsages) {
|
private fun updateArgumentsAndReceiver(changeInfo: JetChangeInfo, element: KtCallElement, allUsages: Array<out UsageInfo>) {
|
||||||
KtValueArgumentList arguments = element.getValueArgumentList();
|
var arguments = element.valueArgumentList.sure { "Argument list is expected: " + element.text }
|
||||||
assert arguments != null : "Argument list is expected: " + element.getText();
|
val oldArguments = element.valueArguments
|
||||||
List<? extends ValueArgument> oldArguments = element.getValueArguments();
|
|
||||||
|
|
||||||
if (isPropertyJavaUsage()) {
|
if (isPropertyJavaUsage) return updateJavaPropertyCall(changeInfo, element)
|
||||||
updateJavaPropertyCall(changeInfo, element);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isNamedCall = oldArguments.size() > 1 && oldArguments.get(0).isNamed();
|
val isNamedCall = oldArguments.size > 1 && oldArguments[0].isNamed()
|
||||||
StringBuilder parametersBuilder = new StringBuilder("(");
|
|
||||||
boolean isFirst = true;
|
|
||||||
|
|
||||||
TIntArrayList indicesOfArgumentsWithDefaultValues = new TIntArrayList();
|
val indicesOfArgumentsWithDefaultValues = TIntArrayList()
|
||||||
|
|
||||||
KtPsiFactory psiFactory = new KtPsiFactory(element.getProject());
|
val psiFactory = KtPsiFactory(element.project)
|
||||||
|
|
||||||
List<JetParameterInfo> newSignatureParameters = changeInfo.getNonReceiverParameters();
|
val newSignatureParameters = changeInfo.getNonReceiverParameters()
|
||||||
for (JetParameterInfo parameterInfo : newSignatureParameters) {
|
val newArgumentListText = newSignatureParameters
|
||||||
if (isFirst) {
|
.map { parameterInfo ->
|
||||||
isFirst = false;
|
val defaultValueForCall = parameterInfo.defaultValueForCall
|
||||||
}
|
val defaultValueText = when {
|
||||||
else {
|
element.isInsideOfCallerBody(allUsages) ->
|
||||||
parametersBuilder.append(',');
|
parameterInfo.name
|
||||||
}
|
defaultValueForCall != null ->
|
||||||
|
substituteReferences(defaultValueForCall, parameterInfo.defaultValueParameterReferences, psiFactory).text
|
||||||
|
else ->
|
||||||
|
""
|
||||||
|
}
|
||||||
|
val argumentValue = if (defaultValueText.isEmpty()) "0" else defaultValueText
|
||||||
|
if (isNamedCall) "${parameterInfo.getInheritedName(callee)}=$argumentValue" else argumentValue
|
||||||
|
}
|
||||||
|
.joinToString(prefix = "(", postfix = ")")
|
||||||
|
val newArgumentList = KtPsiFactory(project).createCallArguments(newArgumentListText)
|
||||||
|
|
||||||
KtExpression defaultValueForCall = parameterInfo.getDefaultValueForCall();
|
val argumentMap = getParamIndexToArgumentMap(changeInfo, oldArguments)
|
||||||
|
|
||||||
String defaultValueText;
|
val newReceiverInfo = changeInfo.receiverParameterInfo
|
||||||
if (ChangeSignatureUtilsKt.isInsideOfCallerBody(element, allUsages)) {
|
val originalReceiverInfo = changeInfo.methodDescriptor.receiver
|
||||||
defaultValueText = parameterInfo.getName();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
defaultValueText = defaultValueForCall != null
|
|
||||||
? substituteReferences(defaultValueForCall,
|
|
||||||
parameterInfo.getDefaultValueParameterReferences(),
|
|
||||||
psiFactory).getText()
|
|
||||||
: "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isNamedCall) {
|
val extensionReceiver = if (resolvedCall != null) resolvedCall.extensionReceiver else ReceiverValue.NO_RECEIVER
|
||||||
String newName = parameterInfo.getInheritedName(callee);
|
val dispatchReceiver = if (resolvedCall != null) resolvedCall.dispatchReceiver else ReceiverValue.NO_RECEIVER
|
||||||
parametersBuilder.append(newName).append('=');
|
|
||||||
}
|
|
||||||
|
|
||||||
parametersBuilder.append(defaultValueText.isEmpty() ? '0' : defaultValueText);
|
var elementToReplace: PsiElement = element
|
||||||
}
|
val parent = element.parent
|
||||||
|
if (parent is KtQualifiedExpression && parent.selectorExpression == element) {
|
||||||
parametersBuilder.append(')');
|
elementToReplace = parent
|
||||||
KtValueArgumentList newArgumentList = KtPsiFactoryKt.KtPsiFactory(getProject()).createCallArguments(parametersBuilder.toString());
|
|
||||||
|
|
||||||
Map<Integer, ValueArgument> argumentMap = getParamIndexToArgumentMap(changeInfo, oldArguments);
|
|
||||||
|
|
||||||
JetParameterInfo newReceiverInfo = changeInfo.getReceiverParameterInfo();
|
|
||||||
JetParameterInfo originalReceiverInfo = changeInfo.getMethodDescriptor().getReceiver();
|
|
||||||
|
|
||||||
ReceiverValue extensionReceiver = resolvedCall != null ? resolvedCall.getExtensionReceiver() : ReceiverValue.NO_RECEIVER;
|
|
||||||
ReceiverValue dispatchReceiver = resolvedCall != null ? resolvedCall.getDispatchReceiver() : ReceiverValue.NO_RECEIVER;
|
|
||||||
|
|
||||||
PsiElement elementToReplace = element;
|
|
||||||
PsiElement parent = element.getParent();
|
|
||||||
if (parent instanceof KtQualifiedExpression && ((KtQualifiedExpression) parent).getSelectorExpression() == element) {
|
|
||||||
elementToReplace = parent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not add extension receiver to calls with explicit dispatch receiver
|
// Do not add extension receiver to calls with explicit dispatch receiver
|
||||||
if (newReceiverInfo != null
|
if (newReceiverInfo != null && elementToReplace is KtQualifiedExpression && dispatchReceiver is ExpressionReceiver) return
|
||||||
&& elementToReplace instanceof KtQualifiedExpression
|
|
||||||
&& dispatchReceiver instanceof ExpressionReceiver) return;
|
|
||||||
|
|
||||||
List<KtValueArgument> newArguments = newArgumentList.getArguments();
|
val newArguments = newArgumentList.arguments
|
||||||
int actualIndex = 0;
|
var actualIndex = 0
|
||||||
for (int i = 0; i < newArguments.size(); i++) {
|
for (i in newArguments.indices) {
|
||||||
KtValueArgument newArgument = newArguments.get(i);
|
val newArgument = newArguments[i]
|
||||||
JetParameterInfo parameterInfo = newSignatureParameters.get(i);
|
val parameterInfo = newSignatureParameters[i]
|
||||||
if (parameterInfo == originalReceiverInfo) {
|
if (parameterInfo == originalReceiverInfo) {
|
||||||
KtExpression receiverExpression = getReceiverExpression(extensionReceiver, psiFactory);
|
val receiverExpression = getReceiverExpression(extensionReceiver, psiFactory)
|
||||||
if (receiverExpression != null) {
|
if (receiverExpression != null) {
|
||||||
newArgument.replace(receiverExpression);
|
newArgument.replace(receiverExpression)
|
||||||
}
|
}
|
||||||
actualIndex++;
|
actualIndex++
|
||||||
continue;
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueArgument oldArgument = argumentMap.get(parameterInfo.getOldIndex());
|
val oldArgument = argumentMap[parameterInfo.oldIndex]
|
||||||
|
|
||||||
if (oldArgument != null) {
|
if (oldArgument != null) {
|
||||||
ValueArgumentName argumentName = oldArgument.getArgumentName();
|
val argumentName = oldArgument.getArgumentName()
|
||||||
KtSimpleNameExpression argumentNameExpression = argumentName != null ? argumentName.getReferenceExpression() : null;
|
val argumentNameExpression = argumentName?.referenceExpression
|
||||||
changeArgumentName(argumentNameExpression, parameterInfo);
|
changeArgumentName(argumentNameExpression, parameterInfo)
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
ValueArgument argumentReplacement = (ValueArgument) newArgument.replace(
|
val argumentReplacement = newArgument.replace(
|
||||||
oldArgument instanceof KtFunctionLiteralArgument
|
if (oldArgument is KtFunctionLiteralArgument)
|
||||||
? psiFactory.createArgument(oldArgument.getArgumentExpression(), null, false)
|
psiFactory.createArgument(oldArgument.getArgumentExpression(), null, false)
|
||||||
: oldArgument.asElement()
|
else
|
||||||
);
|
oldArgument.asElement()) as ValueArgument
|
||||||
argumentMap.put(parameterInfo.getOldIndex(), argumentReplacement);
|
argumentMap.put(parameterInfo.oldIndex, argumentReplacement)
|
||||||
}
|
}
|
||||||
// TODO: process default arguments in the middle
|
else if (parameterInfo.defaultValueForCall == null) {
|
||||||
else if (parameterInfo.getDefaultValueForCall() == null) {
|
if (parameterInfo.defaultValueForParameter != null) {
|
||||||
if (parameterInfo.getDefaultValueForParameter() != null) {
|
newArgumentList.removeArgument(newArgument)
|
||||||
newArgumentList.removeArgument(newArgument);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
newArgument.delete(); // keep space between commas
|
newArgument.delete() // keep space between commas
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
indicesOfArgumentsWithDefaultValues.add(actualIndex++);
|
indicesOfArgumentsWithDefaultValues.add(actualIndex++)
|
||||||
}
|
}// TODO: process default arguments in the middle
|
||||||
}
|
}
|
||||||
|
|
||||||
List<KtFunctionLiteralArgument> lambdaArguments = element.getFunctionLiteralArguments();
|
val lambdaArguments = element.functionLiteralArguments
|
||||||
boolean hasLambdaArgumentsBefore = !lambdaArguments.isEmpty();
|
val hasLambdaArgumentsBefore = !lambdaArguments.isEmpty()
|
||||||
if (hasLambdaArgumentsBefore) {
|
if (hasLambdaArgumentsBefore) {
|
||||||
element.deleteChildRange(CollectionsKt.first(lambdaArguments), CollectionsKt.last(lambdaArguments));
|
element.deleteChildRange(lambdaArguments.first(), lambdaArguments.last())
|
||||||
}
|
}
|
||||||
|
|
||||||
KtValueArgument lastArgument = CollectionsKt.lastOrNull(newArgumentList.getArguments());
|
val lastArgument = newArgumentList.arguments.lastOrNull()
|
||||||
KtFunctionLiteralExpression lastLambdaExpr =
|
val lastLambdaExpr = if (lastArgument != null) lastArgument.getArgumentExpression()?.unpackFunctionLiteral() else null
|
||||||
lastArgument != null ? KtFunctionLiteralArgumentKt.unpackFunctionLiteral(lastArgument.getArgumentExpression()) : null;
|
val lastNewParam = changeInfo.newParameters.lastOrNull()
|
||||||
JetParameterInfo lastNewParam = ArraysKt.lastOrNull(changeInfo.getNewParameters());
|
val hasTrailingLambdaInArgumentListAfter =
|
||||||
boolean hasTrailingLambdaInArgumentListAfter =
|
lastLambdaExpr != null && lastNewParam != null && argumentMap[lastNewParam.oldIndex] == lastArgument
|
||||||
lastLambdaExpr != null && lastNewParam != null && argumentMap.get(lastNewParam.getOldIndex()) == lastArgument;
|
val newLambdaWithDefaultValueWasAdded =
|
||||||
boolean newLambdaWithDefaultValueWasAdded =
|
|
||||||
lastNewParam != null
|
lastNewParam != null
|
||||||
&& lastNewParam.isNewParameter()
|
&& lastNewParam.isNewParameter
|
||||||
&& lastNewParam.getDefaultValueForCall() instanceof KtFunctionLiteralExpression
|
&& lastNewParam.defaultValueForCall is KtFunctionLiteralExpression
|
||||||
&& lastArgument != null
|
&& lastArgument != null
|
||||||
&& !lastArgument.isNamed();
|
&& !lastArgument.isNamed()
|
||||||
boolean shouldMoveLambdaOut =
|
val shouldMoveLambdaOut = hasTrailingLambdaInArgumentListAfter && hasLambdaArgumentsBefore || newLambdaWithDefaultValueWasAdded
|
||||||
hasTrailingLambdaInArgumentListAfter && hasLambdaArgumentsBefore || newLambdaWithDefaultValueWasAdded;
|
|
||||||
|
|
||||||
arguments = (KtValueArgumentList) arguments.replace(newArgumentList);
|
arguments = arguments.replace(newArgumentList) as KtValueArgumentList
|
||||||
|
|
||||||
final List<KtElement> argumentsToShorten = new ArrayList<KtElement>(indicesOfArgumentsWithDefaultValues.size());
|
val argumentsToShorten = ArrayList<KtElement>(indicesOfArgumentsWithDefaultValues.size())
|
||||||
final List<KtValueArgument> argumentList = arguments.getArguments();
|
val argumentList = arguments.arguments
|
||||||
indicesOfArgumentsWithDefaultValues.forEach(
|
indicesOfArgumentsWithDefaultValues.forEach {
|
||||||
new TIntProcedure() {
|
argumentsToShorten.add(argumentList[it])
|
||||||
@Override
|
true
|
||||||
public boolean execute(int i) {
|
|
||||||
argumentsToShorten.add(argumentList.get(i));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
for (KtElement argument : argumentsToShorten) {
|
|
||||||
ShortenWaitingSetKt.addToShorteningWaitSet(argument, SHORTEN_ARGUMENTS_OPTIONS);
|
|
||||||
}
|
}
|
||||||
|
argumentsToShorten.forEach { it.addToShorteningWaitSet(SHORTEN_ARGUMENTS_OPTIONS) }
|
||||||
|
|
||||||
KtElement newElement = element;
|
var newElement: KtElement = element
|
||||||
if (newReceiverInfo != originalReceiverInfo) {
|
if (newReceiverInfo != originalReceiverInfo) {
|
||||||
PsiElement replacingElement;
|
val replacingElement: PsiElement
|
||||||
if (newReceiverInfo != null) {
|
if (newReceiverInfo != null) {
|
||||||
ValueArgument receiverArgument = argumentMap.get(newReceiverInfo.getOldIndex());
|
val receiverArgument = argumentMap[newReceiverInfo.oldIndex]
|
||||||
KtExpression extensionReceiverExpression = receiverArgument != null ? receiverArgument.getArgumentExpression() : null;
|
val extensionReceiverExpression = receiverArgument?.getArgumentExpression()
|
||||||
KtExpression defaultValueForCall = newReceiverInfo.getDefaultValueForCall();
|
val defaultValueForCall = newReceiverInfo.defaultValueForCall
|
||||||
KtExpression receiver =
|
val receiver = extensionReceiverExpression?.let { psiFactory.createExpression(it.text) }
|
||||||
extensionReceiverExpression != null ? psiFactory.createExpression(extensionReceiverExpression.getText())
|
?: defaultValueForCall
|
||||||
: defaultValueForCall != null ? defaultValueForCall
|
?: psiFactory.createExpression("_")
|
||||||
: psiFactory.createExpression("_");
|
|
||||||
|
|
||||||
replacingElement = CreateByPatternKt.createExpressionByPattern(psiFactory, "$0.$1", receiver, element);
|
replacingElement = psiFactory.createExpressionByPattern("$0.$1", receiver, element)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
replacingElement = psiFactory.createExpression(element.getText());
|
replacingElement = psiFactory.createExpression(element.text)
|
||||||
}
|
}
|
||||||
|
|
||||||
newElement = (KtElement) elementToReplace.replace(replacingElement);
|
newElement = elementToReplace.replace(replacingElement) as KtElement
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldMoveLambdaOut) {
|
if (shouldMoveLambdaOut) {
|
||||||
KtCallExpression newCallExpression =
|
val newCallExpression = ((newElement as? KtQualifiedExpression)?.selectorExpression ?: newElement) as KtCallExpression
|
||||||
(KtCallExpression) (newElement instanceof KtQualifiedExpression
|
newCallExpression.moveFunctionLiteralOutsideParentheses()
|
||||||
? ((KtQualifiedExpression) newElement).getSelectorExpression()
|
|
||||||
: newElement);
|
|
||||||
PsiModificationUtilsKt.moveFunctionLiteralOutsideParentheses(newCallExpression);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void updateJavaPropertyCall(JetChangeInfo changeInfo, KtCallElement element) {
|
private fun changeArgumentNames(changeInfo: JetChangeInfo, element: KtCallElement) {
|
||||||
JetParameterInfo newReceiverInfo = changeInfo.getReceiverParameterInfo();
|
for (argument in element.valueArguments) {
|
||||||
JetParameterInfo originalReceiverInfo = changeInfo.getMethodDescriptor().getReceiver();
|
val argumentName = argument.getArgumentName()
|
||||||
if (newReceiverInfo == originalReceiverInfo) return;
|
val argumentNameExpression = argumentName?.referenceExpression ?: continue
|
||||||
|
val oldParameterIndex = changeInfo.getOldParameterIndex(argumentNameExpression.getReferencedName()) ?: continue
|
||||||
KtValueArgumentList arguments = element.getValueArgumentList();
|
val newParameterIndex = if (changeInfo.receiverParameterInfo != null) oldParameterIndex + 1 else oldParameterIndex
|
||||||
assert arguments != null : "Argument list is expected: " + element.getText();
|
val parameterInfo = changeInfo.newParameters[newParameterIndex]
|
||||||
List<? extends ValueArgument> oldArguments = element.getValueArguments();
|
changeArgumentName(argumentNameExpression, parameterInfo)
|
||||||
|
|
||||||
KtPsiFactory psiFactory = new KtPsiFactory(element.getProject());
|
|
||||||
|
|
||||||
KtValueArgument firstArgument = oldArguments.isEmpty() ? null : (KtValueArgument) oldArguments.get(0);
|
|
||||||
|
|
||||||
if (newReceiverInfo == null) {
|
|
||||||
if (firstArgument != null) arguments.removeArgument(firstArgument);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
KtExpression defaultValueForCall = newReceiverInfo.getDefaultValueForCall();
|
|
||||||
if (defaultValueForCall == null) {
|
|
||||||
defaultValueForCall = psiFactory.createExpression("_");
|
|
||||||
}
|
|
||||||
KtValueArgument newReceiverArgument = psiFactory.createArgument(defaultValueForCall, null, false);
|
|
||||||
|
|
||||||
if (originalReceiverInfo != null) {
|
|
||||||
if (firstArgument != null) firstArgument.replace(newReceiverArgument);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
arguments.addArgumentAfter(newReceiverArgument, null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
private fun changeArgumentName(argumentNameExpression: KtSimpleNameExpression?, parameterInfo: JetParameterInfo) {
|
||||||
private static KtExpression getReceiverExpression(@NotNull ReceiverValue receiver, @NotNull KtPsiFactory psiFactory) {
|
val identifier = argumentNameExpression?.getIdentifier() ?: return
|
||||||
if (receiver instanceof ExpressionReceiver) {
|
val newName = parameterInfo.getInheritedName(callee)
|
||||||
return ((ExpressionReceiver) receiver).getExpression();
|
identifier.replace(KtPsiFactory(project).createIdentifier(newName))
|
||||||
}
|
|
||||||
else if (receiver instanceof ThisReceiver) {
|
|
||||||
DeclarationDescriptor descriptor = ((ThisReceiver) receiver).getDeclarationDescriptor();
|
|
||||||
String thisText = descriptor instanceof ClassDescriptor ? "this@" + descriptor.getName().asString() : "this";
|
|
||||||
return psiFactory.createExpression(thisText);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<Integer, ValueArgument> getParamIndexToArgumentMap(JetChangeInfo changeInfo, List<? extends ValueArgument> oldArguments) {
|
companion object {
|
||||||
Map<Integer, ValueArgument> argumentMap = new HashMap<Integer, ValueArgument>();
|
private val REVERSED_TEXT_OFFSET_COMPARATOR = object : Comparator<Pair<KtElement, KtElement>> {
|
||||||
|
override fun compare(p1: Pair<KtElement, KtElement>, p2: Pair<KtElement, KtElement>): Int {
|
||||||
for (int i = 0; i < oldArguments.size(); i++) {
|
val offset1 = p1.first.startOffset
|
||||||
ValueArgument argument = oldArguments.get(i);
|
val offset2 = p2.first.startOffset
|
||||||
ValueArgumentName argumentName = argument.getArgumentName();
|
return when {
|
||||||
String oldParameterName = argumentName != null ? argumentName.getAsName().asString() : null;
|
offset1 < offset2 -> 1
|
||||||
|
offset1 > offset2 -> -1
|
||||||
if (oldParameterName != null) {
|
else -> 0
|
||||||
Integer oldParameterIndex = changeInfo.getOldParameterIndex(oldParameterName);
|
}
|
||||||
|
|
||||||
if (oldParameterIndex != null)
|
|
||||||
argumentMap.put(oldParameterIndex, argument);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
argumentMap.put(i, argument);
|
|
||||||
}
|
|
||||||
|
|
||||||
return argumentMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void changeArgumentNames(JetChangeInfo changeInfo, KtCallElement element) {
|
|
||||||
for (ValueArgument argument : element.getValueArguments()) {
|
|
||||||
ValueArgumentName argumentName = argument.getArgumentName();
|
|
||||||
KtSimpleNameExpression argumentNameExpression = argumentName != null ? argumentName.getReferenceExpression() : null;
|
|
||||||
|
|
||||||
if (argumentNameExpression != null) {
|
|
||||||
Integer oldParameterIndex = changeInfo.getOldParameterIndex(argumentNameExpression.getReferencedName());
|
|
||||||
if (oldParameterIndex == null) continue;
|
|
||||||
|
|
||||||
JetParameterInfo parameterInfo = changeInfo.getNewParameters()[
|
|
||||||
changeInfo.getReceiverParameterInfo() != null ? oldParameterIndex + 1 : oldParameterIndex
|
|
||||||
];
|
|
||||||
changeArgumentName(argumentNameExpression, parameterInfo);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void changeArgumentName(KtSimpleNameExpression argumentNameExpression, JetParameterInfo parameterInfo) {
|
private val SHORTEN_ARGUMENTS_OPTIONS = ShortenReferences.Options(true, true)
|
||||||
PsiElement identifier = argumentNameExpression != null ? argumentNameExpression.getIdentifier() : null;
|
|
||||||
|
|
||||||
if (identifier != null) {
|
private fun updateJavaPropertyCall(changeInfo: JetChangeInfo, element: KtCallElement) {
|
||||||
String newName = parameterInfo.getInheritedName(callee);
|
val newReceiverInfo = changeInfo.receiverParameterInfo
|
||||||
identifier.replace(KtPsiFactoryKt.KtPsiFactory(getProject()).createIdentifier(newName));
|
val originalReceiverInfo = changeInfo.methodDescriptor.receiver
|
||||||
|
if (newReceiverInfo == originalReceiverInfo) return
|
||||||
|
|
||||||
|
val arguments = element.valueArgumentList.sure { "Argument list is expected: " + element.text }
|
||||||
|
val oldArguments = element.valueArguments
|
||||||
|
|
||||||
|
val psiFactory = KtPsiFactory(element.project)
|
||||||
|
|
||||||
|
val firstArgument = oldArguments.firstOrNull() as KtValueArgument?
|
||||||
|
|
||||||
|
when {
|
||||||
|
newReceiverInfo != null -> {
|
||||||
|
val defaultValueForCall = newReceiverInfo.defaultValueForCall ?: psiFactory.createExpression("_")
|
||||||
|
val newReceiverArgument = psiFactory.createArgument(defaultValueForCall, null, false)
|
||||||
|
|
||||||
|
if (originalReceiverInfo != null) {
|
||||||
|
firstArgument?.replace(newReceiverArgument)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
arguments.addArgumentAfter(newReceiverArgument, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
firstArgument != null -> arguments.removeArgument(firstArgument)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getReceiverExpression(receiver: ReceiverValue, psiFactory: KtPsiFactory): KtExpression? {
|
||||||
|
return when (receiver) {
|
||||||
|
is ExpressionReceiver -> receiver.expression
|
||||||
|
is ThisReceiver -> {
|
||||||
|
val descriptor = receiver.declarationDescriptor
|
||||||
|
val thisText = if (descriptor is ClassDescriptor) "this@" + descriptor.name.asString() else "this"
|
||||||
|
psiFactory.createExpression(thisText)
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getParamIndexToArgumentMap(changeInfo: JetChangeInfo, oldArguments: List<ValueArgument>): MutableMap<Int, ValueArgument> {
|
||||||
|
val argumentMap = HashMap<Int, ValueArgument>()
|
||||||
|
|
||||||
|
for (i in oldArguments.indices) {
|
||||||
|
val argument = oldArguments[i]
|
||||||
|
val argumentName = argument.getArgumentName()
|
||||||
|
val oldParameterName = if (argumentName != null) argumentName.asName.asString() else null
|
||||||
|
|
||||||
|
if (oldParameterName != null) {
|
||||||
|
val oldParameterIndex = changeInfo.getOldParameterIndex(oldParameterName)
|
||||||
|
|
||||||
|
if (oldParameterIndex != null)
|
||||||
|
argumentMap.put(oldParameterIndex, argument)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
argumentMap.put(i, argument)
|
||||||
|
}
|
||||||
|
|
||||||
|
return argumentMap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user