Change Signature: Support conversion between extension and non-extension functions

This commit is contained in:
Alexey Sedunov
2014-12-19 20:40:17 +03:00
parent b31da56e09
commit 96866a108f
82 changed files with 1425 additions and 64 deletions
@@ -54,3 +54,25 @@ fun setTypeReference(declaration: JetCallableDeclaration, addAfter: PsiElement?,
return null
}
}
fun JetCallableDeclaration.setReceiverTypeReference(typeRef: JetTypeReference?): JetTypeReference? {
val oldTypeRef = getReceiverTypeReference()
if (typeRef != null) {
if (oldTypeRef != null) {
return oldTypeRef.replace(typeRef) as JetTypeReference
}
else {
val anchor = getNameIdentifier()
val newTypeRef = addBefore(typeRef, anchor) as JetTypeReference
addAfter(JetPsiFactory(getProject()).createDot(), newTypeRef)
return newTypeRef
}
}
else {
if (oldTypeRef != null) {
val dot = oldTypeRef.siblings(forward = true).firstOrNull { it.getNode().getElementType() == JetTokens.DOT }
deleteChildRange(oldTypeRef, dot ?: oldTypeRef)
}
return null
}
}
@@ -17,21 +17,28 @@
package org.jetbrains.kotlin.idea.refactoring.changeSignature
import com.intellij.lang.Language
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiModifier
import com.intellij.psi.PsiType
import com.intellij.refactoring.changeSignature.*
import com.intellij.usageView.UsageInfo
import com.intellij.util.Function
import com.intellij.util.VisibilityUtil
import com.intellij.util.containers.ContainerUtil
import kotlin.Function1
import kotlin.Pair
import org.jetbrains.kotlin.asJava.*
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.psi.JetFunction
import org.jetbrains.kotlin.psi.JetFunctionLiteral
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.idea.JetLanguage
@@ -40,6 +47,9 @@ import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.JetFunctionD
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import java.util.HashMap
import kotlin.properties.Delegates
import java.util.ArrayList
import java.util.Collections
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
public class JetChangeInfo(
val methodDescriptor: JetMethodDescriptor,
@@ -48,8 +58,17 @@ public class JetChangeInfo(
var newReturnTypeText: String,
var newVisibility: Visibility,
parameterInfos: List<JetParameterInfo>,
receiver: JetParameterInfo?,
val context: PsiElement
): ChangeInfo {
var receiverParameterInfo: JetParameterInfo? = receiver
set(value: JetParameterInfo?) {
if (value != null && value !in newParameters) {
newParameters.add(value)
}
$receiverParameterInfo = value
}
private val newParameters = parameterInfos.toArrayList()
private val originalPsiMethod: PsiMethod? = getCurrentPsiMethod()
@@ -63,8 +82,10 @@ public class JetChangeInfo(
}
public val isParameterSetOrOrderChanged: Boolean by Delegates.lazy {
newParameters.size() != methodDescriptor.getParametersCount() ||
newParameters.indices.any { i -> newParameters.get(i).getOldIndex() != i }
val signatureParameters = getNonReceiverParameters()
methodDescriptor.receiver != receiverParameterInfo ||
signatureParameters.size() != methodDescriptor.getParametersCount() ||
signatureParameters.indices.any { i -> signatureParameters[i].getOldIndex() != i }
}
private var isPrimaryMethodUpdated: Boolean = false
@@ -88,6 +109,12 @@ public class JetChangeInfo(
override fun getNewParameters(): Array<JetParameterInfo> = newParameters.copyToArray()
fun getNonReceiverParametersCount(): Int = newParameters.size() - (if (receiverParameterInfo != null) 1 else 0)
fun getNonReceiverParameters(): List<JetParameterInfo> {
return receiverParameterInfo?.let { receiver -> newParameters.filter { it != receiver } } ?: newParameters
}
public fun setNewParameter(index: Int, parameterInfo: JetParameterInfo) {
newParameters.set(index, parameterInfo)
}
@@ -97,9 +124,15 @@ public class JetChangeInfo(
}
public fun removeParameter(index: Int) {
newParameters.remove(index);
val parameterInfo = newParameters.remove(index);
if (parameterInfo == receiverParameterInfo) {
receiverParameterInfo = null
}
}
public fun hasParameter(parameterInfo: JetParameterInfo): Boolean =
parameterInfo in newParameters
override fun isGenerateDelegate(): Boolean = false
override fun getNewName(): String = name
@@ -118,6 +151,8 @@ public class JetChangeInfo(
override fun isReturnTypeChanged(): Boolean = newReturnTypeText != methodDescriptor.renderOriginalReturnType()
fun isReceiverTypeChanged(): Boolean = receiverParameterInfo?.getTypeText() != methodDescriptor.renderOriginalReceiverType()
override fun getLanguage(): Language = JetLanguage.INSTANCE
public fun getNewSignature(inheritedFunction: JetFunctionDefinitionUsage<PsiElement>): String {
@@ -135,9 +170,15 @@ public class JetChangeInfo(
buffer.append(newVisibility).append(' ')
}
buffer.append(JetTokens.FUN_KEYWORD).append(' ').append(name)
buffer.append(JetTokens.FUN_KEYWORD).append(' ')
}
receiverParameterInfo?.let {
buffer.append(it.currentTypeText).append('.')
}
buffer.append(name)
buffer.append(getNewParametersSignature(inheritedFunction))
if (newReturnType != null && !KotlinBuiltIns.isUnit(newReturnType) && !isConstructor)
@@ -152,16 +193,25 @@ public class JetChangeInfo(
}
public fun getNewParametersSignature(inheritedFunction: JetFunctionDefinitionUsage<PsiElement>): String {
val signatureParameters = getNonReceiverParameters()
val isLambda = inheritedFunction.getDeclaration() is JetFunctionLiteral
if (isLambda && newParameters.size() == 1 && !newParameters.get(0).requiresExplicitType(inheritedFunction)) {
return newParameters.get(0).getDeclarationSignature(0, inheritedFunction)
if (isLambda && signatureParameters.size() == 1 && !signatureParameters.get(0).requiresExplicitType(inheritedFunction)) {
return signatureParameters.get(0).getDeclarationSignature(0, inheritedFunction)
}
return newParameters.indices
.map { i -> newParameters[i].getDeclarationSignature(i, inheritedFunction) }
return signatureParameters.indices
.map { i -> signatureParameters[i].getDeclarationSignature(i, inheritedFunction) }
.joinToString(prefix = "(", separator = ", ", postfix = ")")
}
public fun renderReceiverType(inheritedFunction: JetFunctionDefinitionUsage<PsiElement>): String? {
val receiverTypeText = receiverParameterInfo?.currentTypeText ?: return null
val typeSubstitutor = inheritedFunction.getOrCreateTypeSubstitutor() ?: return receiverTypeText
val currentBaseFunction = inheritedFunction.getBaseFunction().getCurrentFunctionDescriptor() ?: return receiverTypeText
return currentBaseFunction.getExtensionReceiverParameter()!!.getType().renderTypeWithSubstitution(typeSubstitutor, receiverTypeText, false)
}
public fun renderReturnType(inheritedFunction: JetFunctionDefinitionUsage<PsiElement>): String {
val typeSubstitutor = inheritedFunction.getOrCreateTypeSubstitutor() ?: return newReturnTypeText
val currentBaseFunction = inheritedFunction.getBaseFunction().getCurrentFunctionDescriptor() ?: return newReturnTypeText
@@ -190,13 +240,24 @@ public class JetChangeInfo(
else
PsiModifier.PACKAGE_LOCAL
val newJavaParameters = newParameters.withIndex().map { pair ->
val newParameterList = receiverParameterInfo.singletonOrEmptyList() + getNonReceiverParameters()
val newJavaParameters = newParameterList.withIndex().map { pair ->
val (i, info) = pair
val type = if (isPrimaryMethodUpdated)
currentPsiMethod.getParameterList().getParameters()[i].getType()
else
PsiType.VOID
ParameterInfoImpl(info.getOldIndex(), info.getName(), type, info.defaultValueForCall)
val oldIndex = info.getOldIndex()
val javaOldIndex = when {
methodDescriptor.receiver == null -> oldIndex
info == methodDescriptor.receiver -> 0
oldIndex >= 0 -> oldIndex + 1
else -> -1
}
ParameterInfoImpl(javaOldIndex, info.getName(), type, info.defaultValueForCall)
}.copyToArray()
val returnType = if (isPrimaryMethodUpdated) currentPsiMethod.getReturnType() else PsiType.VOID
@@ -257,5 +318,6 @@ public fun ChangeInfo.toJetChangeInfo(originalChangeSignatureDescriptor: JetMeth
returnTypeText,
functionDescriptor.getVisibility(),
newParameters,
null,
method)
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,6 +32,10 @@ import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.JetFunctionD
import java.util.*
import kotlin.properties.Delegates
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.idea.refactoring.CollectingValidator
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.idea.refactoring.JetNameSuggester
public class JetChangeSignatureData(
override val baseDescriptor: FunctionDescriptor,
@@ -39,24 +43,49 @@ public class JetChangeSignatureData(
private val descriptorsForSignatureChange: Collection<FunctionDescriptor>
) : JetMethodDescriptor {
private val parameters: MutableList<JetParameterInfo>
override var receiver: JetParameterInfo?
set(value: JetParameterInfo?) {
if (value != null && value !in parameters) {
parameters.add(value)
}
$receiver = value
}
;{
$receiver = createReceiverInfoIfNeeded()
;{
val valueParameters = when {
baseDeclaration is JetFunction -> baseDeclaration.getValueParameters()
baseDeclaration is JetClass -> baseDeclaration.getPrimaryConstructorParameters()
else -> null
}
parameters = baseDescriptor.getValueParameters().mapTo(ArrayList()) { parameterDescriptor ->
val jetParameter = valueParameters?.get(parameterDescriptor.getIndex())
JetParameterInfo(
originalIndex = parameterDescriptor.getIndex(),
name = parameterDescriptor.getName().asString(),
type = parameterDescriptor.getType(),
defaultValueForParameter = jetParameter?.getDefaultValue(),
valOrVarNode = jetParameter?.getValOrVarNode(),
modifierList = jetParameter?.getModifierList()
)
}
parameters = baseDescriptor.getValueParameters()
.mapTo(receiver?.let{ arrayListOf(it) } ?: arrayListOf()) { parameterDescriptor ->
val jetParameter = valueParameters?.get(parameterDescriptor.getIndex())
JetParameterInfo(
originalIndex = parameterDescriptor.getIndex(),
name = parameterDescriptor.getName().asString(),
type = parameterDescriptor.getType(),
defaultValueForParameter = jetParameter?.getDefaultValue(),
valOrVarNode = jetParameter?.getValOrVarNode(),
modifierList = jetParameter?.getModifierList()
)
}
}
private fun createReceiverInfoIfNeeded(): JetParameterInfo? {
val function = baseDeclaration as? JetFunction ?: return null
val bodyScope = function.getBodyExpression()?.let { it.analyze()[BindingContext.RESOLUTION_SCOPE, it] }
val paramNames = baseDescriptor.getValueParameters().map { it.getName().asString() }
val validator = bodyScope?.let { bodyScope ->
CollectingValidator(paramNames) {
val name = Name.identifier(it)
bodyScope.getLocalVariable(name) == null && bodyScope.getProperties(name).isEmpty()
}
} ?: CollectingValidator(paramNames)
val receiverType = baseDescriptor.getExtensionReceiverParameter()?.getType() ?: return null
val receiverName = JetNameSuggester.suggestNames(receiverType, validator, "receiver").first()
return JetParameterInfo(name = receiverName, type = receiverType)
}
override val primaryFunctions: Collection<JetFunctionDefinitionUsage<PsiElement>> by Delegates.lazy {
@@ -420,7 +420,7 @@ public class JetChangeSignatureDialog extends ChangeSignatureDialogBase<
String returnTypeText = myReturnTypeCodeFragment != null ? myReturnTypeCodeFragment.getText().trim() : "";
return new JetChangeInfo(myMethod, getMethodName(), getReturnType(), returnTypeText,
getVisibility(), parameters, myDefaultValueContext
getVisibility(), parameters, null, myDefaultValueContext
);
}
@@ -25,31 +25,43 @@ import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.changeSignature.*;
import com.intellij.refactoring.rename.ResolveSnapshotProvider;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.refactoring.util.MoveRenameUsageInfo;
import com.intellij.refactoring.util.RefactoringUIUtil;
import com.intellij.refactoring.util.TextOccurrencesUtil;
import com.intellij.usageView.UsageInfo;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashSet;
import com.intellij.util.containers.MultiMap;
import kotlin.Function1;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage;
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToDeclarationUtil;
import org.jetbrains.kotlin.idea.codeInsight.JetFileReferencesResolver;
import org.jetbrains.kotlin.idea.refactoring.RefactoringPackage;
import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.*;
import org.jetbrains.kotlin.idea.references.JetSimpleNameReference;
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.psi.typeRefHelpers.TypeRefHelpersPackage;
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.scopes.JetScope;
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver;
import org.jetbrains.kotlin.types.JetType;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsageProcessor {
@@ -79,7 +91,7 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
}
private static void findOneMethodUsages(
@NotNull JetFunctionDefinitionUsage functionUsageInfo,
@NotNull JetFunctionDefinitionUsage<?> functionUsageInfo,
JetChangeInfo changeInfo,
Set<UsageInfo> result
) {
@@ -92,7 +104,6 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
PsiElement functionPsi = functionUsageInfo.getElement();
if (functionPsi == null) return;
for (PsiReference reference : ReferencesSearch.search(functionPsi, functionPsi.getUseScope())) {
PsiElement element = reference.getElement();
@@ -119,12 +130,14 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
? ((JetFunction) functionPsi).getValueParameters()
: ((JetClass) functionPsi).getPrimaryConstructorParameters();
JetParameterInfo newReceiverInfo = changeInfo.getReceiverParameterInfo();
for (JetParameterInfo parameterInfo : changeInfo.getNewParameters()) {
if (parameterInfo.getOldIndex() >= 0 && parameterInfo.getOldIndex() < oldParameters.size()) {
JetParameter oldParam = oldParameters.get(parameterInfo.getOldIndex());
String oldParamName = oldParam.getName();
if (oldParamName != null && !oldParamName.equals(parameterInfo.getName())) {
if (parameterInfo == newReceiverInfo || (oldParamName != null && !oldParamName.equals(parameterInfo.getName()))) {
for (PsiReference reference : ReferencesSearch.search(oldParam, oldParam.getUseScope())) {
PsiElement element = reference.getElement();
@@ -140,6 +153,10 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
}
}
if (functionPsi instanceof JetFunction && newReceiverInfo != changeInfo.getMethodDescriptor().getReceiver()) {
findOriginalReceiversUsages(functionUsageInfo, result, changeInfo);
}
if (functionPsi instanceof JetClass && ((JetClass) functionPsi).isEnum()) {
for (JetDeclaration declaration : ((JetClass) functionPsi).getDeclarations()) {
if (declaration instanceof JetEnumEntry && ((JetEnumEntry) declaration).getDelegationSpecifierList() == null) {
@@ -149,6 +166,90 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
}
}
private static void processInternalReferences(
JetFunctionDefinitionUsage functionUsageInfo,
JetTreeVisitor<BindingContext> visitor
) {
JetFunction jetFunction = (JetFunction) functionUsageInfo.getDeclaration();
JetExpression body = jetFunction.getBodyExpression();
if (body != null) {
body.accept(visitor, ResolvePackage.analyze(body));
}
for (JetParameter parameter : jetFunction.getValueParameters()) {
JetExpression defaultValue = parameter.getDefaultValue();
if (defaultValue != null) {
defaultValue.accept(visitor, ResolvePackage.analyze(defaultValue));
}
}
}
private static void findOriginalReceiversUsages(
@NotNull final JetFunctionDefinitionUsage<?> functionUsageInfo,
@NotNull final Set<UsageInfo> result,
@NotNull final JetChangeInfo changeInfo
) {
final JetParameterInfo originalReceiverInfo = changeInfo.getMethodDescriptor().getReceiver();
final FunctionDescriptor functionDescriptor = functionUsageInfo.getOriginalFunctionDescriptor();
processInternalReferences(
functionUsageInfo,
new JetTreeVisitor<BindingContext>() {
private void processExplicitThis(
@NotNull JetSimpleNameExpression expression,
@NotNull ReceiverParameterDescriptor receiverDescriptor
) {
if (originalReceiverInfo != null && !changeInfo.hasParameter(originalReceiverInfo)) return;
if (!(expression.getParent() instanceof JetThisExpression)) return;
if (receiverDescriptor == functionDescriptor.getExtensionReceiverParameter()) {
assert originalReceiverInfo != null : "No original receiver info provided: " + functionUsageInfo.getDeclaration().getText();
result.add(new JetParameterUsage(expression, originalReceiverInfo, functionUsageInfo));
}
else {
ClassifierDescriptor targetDescriptor = receiverDescriptor.getType().getConstructor().getDeclarationDescriptor();
assert targetDescriptor != null : "Receiver type has no descriptor: " + functionUsageInfo.getDeclaration().getText();
result.add(new JetNonQualifiedOuterThisUsage((JetThisExpression) expression.getParent(), targetDescriptor));
}
}
private void processImplicitThis(
@NotNull JetElement callElement,
@NotNull ThisReceiver receiverValue
) {
DeclarationDescriptor targetDescriptor = receiverValue.getDeclarationDescriptor();
if (targetDescriptor == functionDescriptor) {
assert originalReceiverInfo != null : "No original receiver info provided: " + functionUsageInfo.getDeclaration().getText();
result.add(new JetImplicitThisToParameterUsage(callElement, originalReceiverInfo, functionUsageInfo));
}
else {
result.add(new JetImplicitOuterThisToQualifiedThisUsage(callElement, targetDescriptor));
}
}
@Override
public Void visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression, BindingContext context) {
ResolvedCall<? extends CallableDescriptor> resolvedCall = CallUtilPackage.getResolvedCall(expression, context);
if (resolvedCall == null) return null;
CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor();
if (resultingDescriptor instanceof ReceiverParameterDescriptor) {
processExplicitThis(expression, (ReceiverParameterDescriptor) resultingDescriptor);
return null;
}
ReceiverValue receiverValue = resolvedCall.getExtensionReceiver();
if (!(receiverValue instanceof ThisReceiver)) {
receiverValue = resolvedCall.getDispatchReceiver();
}
if (receiverValue instanceof ThisReceiver) {
processImplicitThis(resolvedCall.getCall().getCallElement(), (ThisReceiver) receiverValue);
}
return null;
}
}
);
}
private static void findSAMUsages(ChangeInfo changeInfo, Set<UsageInfo> result) {
PsiElement method = changeInfo.getMethod();
if (!RefactoringPackage.isTrueJavaMethod(method)) return;
@@ -203,9 +304,9 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
PsiElement element = function != null ? function : changeInfo.getContext();
BindingContext bindingContext = ResolvePackage.analyze((JetElement) element);
FunctionDescriptor oldDescriptor = ChangeSignaturePackage.getOriginalBaseFunctionDescriptor(changeInfo);
JetScope parametersScope = null;
DeclarationDescriptor containingDeclaration = oldDescriptor != null ? oldDescriptor.getContainingDeclaration() : null;
DeclarationDescriptor containingDeclaration = oldDescriptor.getContainingDeclaration();
JetScope parametersScope = null;
if (oldDescriptor instanceof ConstructorDescriptor && containingDeclaration instanceof ClassDescriptorWithResolutionScopes)
parametersScope = ((ClassDescriptorWithResolutionScopes) containingDeclaration).getScopeForInitializerResolution();
else if (function instanceof JetFunction)
@@ -256,9 +357,104 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
}
}
JetParameterInfo newReceiverInfo = changeInfo.getReceiverParameterInfo();
JetParameterInfo originalReceiverInfo = changeInfo.getMethodDescriptor().getReceiver();
if (function instanceof JetNamedFunction && newReceiverInfo != originalReceiverInfo) {
findReceiverIntroducingConflicts(result, function, newReceiverInfo);
findInternalExplicitReceiverConflicts(refUsages.get(), result, originalReceiverInfo);
}
return result;
}
private static void findInternalExplicitReceiverConflicts(
UsageInfo[] usages,
MultiMap<PsiElement, String> result,
JetParameterInfo originalReceiverInfo
) {
if (originalReceiverInfo == null) {
for (UsageInfo usageInfo : usages) {
if (!(usageInfo instanceof JetFunctionCallUsage)) continue;
JetFunctionCallUsage callUsage = (JetFunctionCallUsage) usageInfo;
JetElement callElement = callUsage.getElement();
if (callElement == null) continue;
PsiElement parent = callElement.getParent();
if (parent instanceof JetQualifiedExpression && ((JetQualifiedExpression) parent).getSelectorExpression() == callElement) {
String message = "Explicit receiver is already present in call element: " +
CommonRefactoringUtil.htmlEmphasize(parent.getText());
result.putValue(callElement, message);
}
}
}
}
private static void findReceiverIntroducingConflicts(
MultiMap<PsiElement, String> result,
PsiElement callable,
JetParameterInfo newReceiverInfo
) {
if (newReceiverInfo != null && ((JetNamedFunction) callable).getBodyExpression() != null) {
Map<JetReferenceExpression, BindingContext> noReceiverRefToContext = KotlinPackage.filter(
JetFileReferencesResolver.INSTANCE$.resolve((JetNamedFunction) callable, true, true),
new Function1<Map.Entry<? extends JetReferenceExpression, ? extends BindingContext>, Boolean>() {
@Override
public Boolean invoke(Map.Entry<? extends JetReferenceExpression, ? extends BindingContext> entry) {
ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(entry.getKey(), entry.getValue());
return resolvedCall != null
&& !resolvedCall.getDispatchReceiver().exists()
&& !resolvedCall.getExtensionReceiver().exists();
}
}
);
JetPsiFactory psiFactory = new JetPsiFactory(callable.getProject());
JetFile tempFile = RefactoringPackage.createTempCopy(
(JetFile) callable.getContainingFile(),
new Function1<String, String>() {
@Override
public String invoke(String s) {
return s;
}
}
);
JetNamedFunction functionWithReceiver =
PsiTreeUtil.getParentOfType(tempFile.findElementAt(callable.getTextOffset()), JetNamedFunction.class);
JetTypeReference receiverTypeRef = psiFactory.createType(newReceiverInfo.getCurrentTypeText());
TypeRefHelpersPackage.setReceiverTypeReference(functionWithReceiver, receiverTypeRef);
//noinspection ConstantConditions
BindingContext newContext = ResolvePackage.analyze(functionWithReceiver.getBodyExpression());
//noinspection ConstantConditions
int originalOffset = ((JetNamedFunction) callable).getBodyExpression().getTextOffset();
JetExpression newBody = functionWithReceiver.getBodyExpression();
for (Map.Entry<JetReferenceExpression, BindingContext> entry : noReceiverRefToContext.entrySet()) {
JetReferenceExpression originalRef = entry.getKey();
BindingContext originalContext = entry.getValue();
//noinspection ConstantConditions
JetReferenceExpression newRef = PsiTreeUtil.getParentOfType(
newBody.findElementAt(originalRef.getTextOffset() - originalOffset),
JetReferenceExpression.class
);
ResolvedCall<?> newResolvedCall = CallUtilPackage.getResolvedCall(newRef, newContext);
if (newResolvedCall == null
|| newResolvedCall.getExtensionReceiver().exists()
|| newResolvedCall.getDispatchReceiver().exists()) {
//noinspection ConstantConditions
CallableDescriptor descriptor =
CallUtilPackage.getResolvedCall(originalRef, originalContext).getCandidateDescriptor();
PsiElement declaration = DescriptorToDeclarationUtil.INSTANCE$.getDeclaration(callable.getProject(), descriptor);
String prefix = declaration != null ? RefactoringUIUtil.getDescription(declaration, true) : originalRef.getText();
result.putValue(
originalRef,
KotlinPackage.capitalize(prefix + " will no longer be accessible after signature change")
);
}
}
}
}
private static List<JetType> getFunctionParameterTypes(FunctionDescriptor descriptor) {
return ContainerUtil.map(descriptor.getValueParameters(), new Function<ValueParameterDescriptor, JetType>() {
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,6 +32,8 @@ public trait JetMethodDescriptor : MethodDescriptor<JetParameterInfo, Visibility
val originalPrimaryFunction: JetFunctionDefinitionUsage<PsiElement>
val primaryFunctions: Collection<JetFunctionDefinitionUsage<PsiElement>>
val affectedFunctions: Collection<UsageInfo>
val receiver: JetParameterInfo?
}
val JetMethodDescriptor.isConstructor: Boolean
@@ -39,3 +41,6 @@ val JetMethodDescriptor.isConstructor: Boolean
fun JetMethodDescriptor.renderOriginalReturnType(): String =
baseDescriptor.getReturnType()?.let { IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(it) } ?: ""
fun JetMethodDescriptor.renderOriginalReceiverType(): String? =
baseDescriptor.getExtensionReceiverParameter()?.getType()?.let { IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(it) }
@@ -18,9 +18,19 @@ package org.jetbrains.kotlin.idea.refactoring.changeSignature.usages;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
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.refactoring.changeSignature.JetChangeInfo;
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetParameterInfo;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver;
import java.util.HashMap;
import java.util.List;
@@ -29,42 +39,48 @@ import java.util.Map;
import static org.jetbrains.kotlin.psi.PsiPackage.JetPsiFactory;
public class JetFunctionCallUsage extends JetUsageInfo<JetCallElement> {
private final JetFunctionDefinitionUsage callee;
private final JetFunctionDefinitionUsage<?> callee;
private final ResolvedCall<? extends CallableDescriptor> resolvedCall;
public JetFunctionCallUsage(@NotNull JetCallElement element, JetFunctionDefinitionUsage callee) {
super(element);
this.callee = callee;
this.resolvedCall = CallUtilPackage.getResolvedCall(element, ResolvePackage.analyze(element));
}
@Override
public boolean processUsage(JetChangeInfo changeInfo, JetCallElement element) {
JetValueArgumentList arguments = element.getValueArgumentList();
if (changeInfo.isNameChanged()) {
JetExpression callee = element.getCalleeExpression();
if (callee instanceof JetSimpleNameExpression)
if (callee instanceof JetSimpleNameExpression) {
callee.replace(JetPsiFactory(getProject()).createSimpleName(changeInfo.getNewName()));
}
}
if (arguments != null) {
List<JetValueArgument> oldArguments = arguments.getArguments();
if (changeInfo.isParameterSetOrOrderChanged())
arguments.replace(generateNewArgumentList(changeInfo, oldArguments));
else
changeArgumentNames(changeInfo, oldArguments);
if (element.getValueArgumentList() != null) {
if (changeInfo.isParameterSetOrOrderChanged()) {
updateArgumentsAndReceiver(changeInfo, element);
}
else {
changeArgumentNames(changeInfo, element);
}
}
return true;
}
private JetValueArgumentList generateNewArgumentList(JetChangeInfo changeInfo, List<JetValueArgument> oldArguments) {
private void updateArgumentsAndReceiver(JetChangeInfo changeInfo, JetCallElement element) {
JetValueArgumentList arguments = element.getValueArgumentList();
assert arguments != null : "Argument list is expected: " + element.getText();
List<JetValueArgument> oldArguments = arguments.getArguments();
boolean isNamedCall = oldArguments.size() > 1 && oldArguments.get(0).getArgumentName() != null;
StringBuilder parametersBuilder = new StringBuilder("(");
boolean isFirst = true;
for (JetParameterInfo parameterInfo : changeInfo.getNewParameters()) {
List<JetParameterInfo> newSignatureParameters = changeInfo.getNonReceiverParameters();
for (JetParameterInfo parameterInfo : newSignatureParameters) {
if (isFirst)
isFirst = false;
else
@@ -86,8 +102,35 @@ public class JetFunctionCallUsage extends JetUsageInfo<JetCallElement> {
Map<Integer, JetValueArgument> argumentMap = getParamIndexToArgumentMap(changeInfo, oldArguments);
int argIndex = 0;
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;
JetPsiFactory psiFactory = new JetPsiFactory(element.getProject());
PsiElement elementToReplace = element;
PsiElement parent = element.getParent();
if (parent instanceof JetQualifiedExpression && ((JetQualifiedExpression) parent).getSelectorExpression() == element) {
elementToReplace = parent;
}
// Do not add extension receiver to calls with explicit dispatch receiver
if (newReceiverInfo != null
&& elementToReplace instanceof JetQualifiedExpression
&& dispatchReceiver instanceof ExpressionReceiver) return;
for (JetValueArgument newArgument : newArguments.getArguments()) {
JetParameterInfo parameterInfo = changeInfo.getNewParameters()[argIndex++];
JetParameterInfo parameterInfo = newSignatureParameters.get(argIndex++);
if (parameterInfo == originalReceiverInfo) {
JetExpression receiverExpression = getReceiverExpression(extensionReceiver, psiFactory);
if (receiverExpression != null) {
newArgument.replace(receiverExpression);
}
continue;
}
JetValueArgument oldArgument = argumentMap.get(parameterInfo.getOldIndex());
if (oldArgument != null) {
@@ -100,7 +143,38 @@ public class JetFunctionCallUsage extends JetUsageInfo<JetCallElement> {
newArgument.delete();
}
return newArguments;
arguments.replace(newArguments);
if (newReceiverInfo == originalReceiverInfo) return;
PsiElement replacingElement = element;
if (newReceiverInfo != null) {
JetValueArgument receiverArgument = argumentMap.get(newReceiverInfo.getOldIndex());
JetExpression extensionReceiverExpression = receiverArgument != null ? receiverArgument.getArgumentExpression() : null;
String receiverText = extensionReceiverExpression != null
? extensionReceiverExpression.getText()
: newReceiverInfo.getDefaultValueForCall();
if (receiverText.isEmpty()) {
receiverText = "_";
}
replacingElement = psiFactory.createExpression(receiverText + "." + element.getText());
}
elementToReplace.replace(replacingElement);
}
@Nullable
private static JetExpression getReceiverExpression(@NotNull ReceiverValue receiver, @NotNull JetPsiFactory psiFactory) {
if (receiver instanceof ExpressionReceiver) {
return ((ExpressionReceiver) receiver).getExpression();
}
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, JetValueArgument> getParamIndexToArgumentMap(JetChangeInfo changeInfo, List<JetValueArgument> oldArguments) {
@@ -125,8 +199,8 @@ public class JetFunctionCallUsage extends JetUsageInfo<JetCallElement> {
return argumentMap;
}
private void changeArgumentNames(JetChangeInfo changeInfo, List<JetValueArgument> oldArguments) {
for (JetValueArgument argument : oldArguments) {
private void changeArgumentNames(JetChangeInfo changeInfo, JetCallElement element) {
for (ValueArgument argument : element.getValueArguments()) {
JetValueArgumentName argumentName = argument.getArgumentName();
JetSimpleNameExpression argumentNameExpression = argumentName != null ? argumentName.getReferenceExpression() : null;
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,11 +26,19 @@ import kotlin.KotlinPackage;
import kotlin.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor;
import org.jetbrains.kotlin.idea.util.ShortenReferences;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.psi.typeRefHelpers.TypeRefHelpersPackage;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.TypeSubstitutor;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.lexer.JetModifierKeywordToken;
import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage;
import org.jetbrains.kotlin.idea.util.ShortenReferences.Options;
import org.jetbrains.kotlin.idea.codeInsight.shorten.ShortenPackage;
@@ -39,12 +47,6 @@ import org.jetbrains.kotlin.idea.refactoring.changeSignature.ChangeSignaturePack
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo;
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetParameterInfo;
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetValVar;
import org.jetbrains.kotlin.lexer.JetModifierKeywordToken;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.TypeSubstitutor;
import java.util.List;
@@ -212,6 +214,16 @@ public class JetFunctionDefinitionUsage<T extends PsiElement> extends JetUsageIn
ShortenPackage.addToShorteningWaitSet(parameterList, Options.DEFAULT);
}
if (element instanceof JetFunction && changeInfo.isReceiverTypeChanged()) {
//noinspection unchecked
String receiverTypeText = changeInfo.renderReceiverType((JetFunctionDefinitionUsage<PsiElement>) this);
JetTypeReference receiverTypeRef = receiverTypeText != null ? psiFactory.createType(receiverTypeText) : null;
JetTypeReference newReceiverTypeRef = TypeRefHelpersPackage.setReceiverTypeReference((JetFunction) element, receiverTypeRef);
if (newReceiverTypeRef != null) {
ShortenPackage.addToShorteningWaitSet(newReceiverTypeRef, ShortenReferences.Options.DEFAULT);
}
}
if (changeInfo.isVisibilityChanged() && !JetPsiUtil.isLocal((JetDeclaration) element)) {
changeVisibility(changeInfo, element);
}
@@ -225,7 +237,7 @@ public class JetFunctionDefinitionUsage<T extends PsiElement> extends JetUsageIn
JetParameterList parameterList,
JetPsiFactory psiFactory
) {
int parametersCount = changeInfo.getNewParametersCount();
int parametersCount = changeInfo.getNonReceiverParametersCount();
boolean isLambda = element instanceof JetFunctionLiteral;
boolean canReplaceEntireList = false;
@@ -0,0 +1,65 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.refactoring.changeSignature.usages
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetParameterInfo
import org.jetbrains.kotlin.psi.JetPsiFactory
import org.jetbrains.kotlin.psi.JetQualifiedExpression
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.psi.JetElement
import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet
import org.jetbrains.kotlin.idea.util.ShortenReferences.Options
public abstract class JetImplicitReceiverUsage(callElement: JetElement): JetUsageInfo<JetElement>(callElement) {
protected abstract fun getNewReceiverText(): String
protected open fun processReplacedElement(element: JetElement) {
}
override fun processUsage(changeInfo: JetChangeInfo, element: JetElement): Boolean {
val newQualifiedCall = JetPsiFactory(element.getProject()).createExpression(
"${getNewReceiverText()}.${element.getText()}"
) as JetQualifiedExpression
processReplacedElement(element.replace(newQualifiedCall) as JetElement)
return false
}
}
public class JetImplicitThisToParameterUsage(
callElement: JetElement,
val parameterInfo: JetParameterInfo,
val containingFunction: JetFunctionDefinitionUsage<*>
): JetImplicitReceiverUsage(callElement) {
override fun getNewReceiverText(): String = parameterInfo.getInheritedName(containingFunction)
override fun processReplacedElement(element: JetElement) {
element.addToShorteningWaitSet(Options(removeThisLabels = true))
}
}
public class JetImplicitOuterThisToQualifiedThisUsage(
callElement: JetElement,
val targetDescriptor: DeclarationDescriptor
): JetImplicitReceiverUsage(callElement) {
override fun getNewReceiverText(): String = "this@${targetDescriptor.getName().asString()}"
override fun processReplacedElement(element: JetElement) {
element.addToShorteningWaitSet(Options(removeThisLabels = true, removeThis = true))
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,15 +20,51 @@ import org.jetbrains.kotlin.psi.JetSimpleNameExpression
import org.jetbrains.kotlin.psi.JetPsiFactory
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetParameterInfo
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet
import org.jetbrains.kotlin.psi.JetQualifiedExpression
import org.jetbrains.kotlin.psi.JetElement
import org.jetbrains.kotlin.psi.JetThisExpression
import org.jetbrains.kotlin.idea.util.ShortenReferences.Options
// Explicit reference to function parameter or outer this
public abstract class JetExplicitReferenceUsage<T: JetElement>(element: T) : JetUsageInfo<T>(element) {
protected abstract fun getReplacementText(changeInfo: JetChangeInfo): String
protected open fun processReplacedElement(element: JetElement) {
}
override fun processUsage(changeInfo: JetChangeInfo, element: T): Boolean {
val newElement = JetPsiFactory(element.getProject()).createExpression(getReplacementText(changeInfo))
processReplacedElement(element.replace(newElement) as JetElement)
return false
}
}
public class JetParameterUsage(
element: JetSimpleNameExpression,
private val parameterInfo: JetParameterInfo,
private val containingFunction: JetFunctionDefinitionUsage<*>
) : JetUsageInfo<JetSimpleNameExpression>(element) {
override fun processUsage(changeInfo: JetChangeInfo, element: JetSimpleNameExpression): Boolean {
val newName = parameterInfo.getInheritedName(containingFunction)
element.replace(JetPsiFactory(element.getProject()).createSimpleName(newName))
return false
) : JetExplicitReferenceUsage<JetSimpleNameExpression>(element) {
override fun processReplacedElement(element: JetElement) {
val qualifiedExpression = element.getParent() as? JetQualifiedExpression
if (qualifiedExpression?.getReceiverExpression() == element) {
qualifiedExpression!!.addToShorteningWaitSet(Options(removeThis = true))
}
}
override fun getReplacementText(changeInfo: JetChangeInfo): String =
if (changeInfo.receiverParameterInfo != parameterInfo) parameterInfo.getInheritedName(containingFunction) else "this"
}
public class JetNonQualifiedOuterThisUsage(
element: JetThisExpression,
val targetDescriptor: DeclarationDescriptor
) : JetExplicitReferenceUsage<JetThisExpression>(element) {
override fun processReplacedElement(element: JetElement) {
element.addToShorteningWaitSet(Options(removeThisLabels = true))
}
override fun getReplacementText(changeInfo: JetChangeInfo): String = "this@${targetDescriptor.getName().asString()}"
}
@@ -20,6 +20,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.usageView.UsageInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo;
public abstract class JetUsageInfo<T extends PsiElement> extends UsageInfo {
@@ -31,5 +32,12 @@ public abstract class JetUsageInfo<T extends PsiElement> extends UsageInfo {
super(reference);
}
@Nullable
@Override
public T getElement() {
//noinspection unchecked
return (T) super.getElement();
}
public abstract boolean processUsage(JetChangeInfo changeInfo, T element);
}
@@ -0,0 +1,5 @@
class J {
void test() {
_DefaultPackage.foo(X(0), "1", 2);
}
}
@@ -0,0 +1,9 @@
fun X.foo(s: String, k: Int): Boolean {
return s.length() - k > 0
}
class X(val k: Int)
fun test() {
X(0).foo("1", 2)
}
@@ -0,0 +1,5 @@
class J {
void test() {
_DefaultPackage.foo("1", 2);
}
}
@@ -0,0 +1,9 @@
fun <caret>foo(s: String, k: Int): Boolean {
return s.length() - k > 0
}
class X(val k: Int)
fun test() {
foo("1", 2)
}
@@ -0,0 +1,13 @@
fun length(): Int = 1
fun <caret>foo(k: Int): Boolean {
return length() - k > 0
}
class X(val k: Int) {
fun length() = 2
}
fun test() {
foo(2)
}
@@ -0,0 +1 @@
Function length will no longer be accessible after signature change
@@ -0,0 +1,5 @@
class J {
void test() {
new A(3).foo(X(0), "1", 2);
}
}
@@ -0,0 +1,19 @@
class A(val k: Int) {
fun X.foo(s: String, n: Int): Boolean {
return s.length() * this@A.k - n.inc() + this@A.k > 0
}
fun test() {
X(0).foo("1", 2)
}
}
class X(val k: Int)
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
fun test() {
with(A(3)) {
X(0).foo("1", 2)
}
}
@@ -0,0 +1,5 @@
class J {
void test() {
new A(3).foo("1", 2);
}
}
@@ -0,0 +1,19 @@
class A(val k: Int) {
fun <caret>foo(s: String, n: Int): Boolean {
return s.length() * this.k - n.inc() + k > 0
}
fun test() {
foo("1", 2)
}
}
class X(val k: Int)
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
fun test() {
with(A(3)) {
foo("1", 2)
}
}
@@ -0,0 +1,20 @@
class A(val k: Int) {
fun <caret>foo(s: String, n: Int): Boolean {
return s.length()*this.k - n.inc() + k > 0
}
fun test() {
foo("1", 2)
}
}
class X(val k: Int)
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
fun test() {
A(3).foo("1", 2)
with(A(3)) {
foo("1", 2)
}
}
@@ -0,0 +1 @@
Explicit receiver is already present in call element: A(3).foo(&quot;1&quot;, 2)
@@ -0,0 +1,18 @@
interface J<A> extends T<A> {
@Override
<B> int foofoofoo(U<A> a, B b);
}
abstract class J1<X> implements J<U<X>> {
@Override
public <C> int foofoofoo(U<U<X>> xu, C c) {
throw new UnsupportedOperationException();
}
}
abstract class J2 extends J1<String> {
@Override
public <C> int foofoofoo(U<U<String>> xu, C c) {
throw new UnsupportedOperationException();
}
}
@@ -0,0 +1,17 @@
class U<A>
trait T<A> {
fun U<A>.foofoofoo<B>(b: B): Int
}
abstract class T1<X> : T<U<X>> {
override fun <B> U<U<X>>.foofoofoo(b: B): Int {
throw UnsupportedOperationException()
}
}
abstract class T2 : T1<String>() {
override fun <C> U<U<String>>.foofoofoo(b: C): Int {
throw UnsupportedOperationException()
}
}
@@ -0,0 +1,18 @@
interface J<A> extends T<A> {
@Override
<B> int foofoofoo(A a, B b);
}
abstract class J1<X> implements J<U<X>> {
@Override
public <C> int foofoofoo(U<X> xu, C c) {
throw new UnsupportedOperationException();
}
}
abstract class J2 extends J1<String> {
@Override
public <C> int foofoofoo(U<String> xu, C c) {
throw new UnsupportedOperationException();
}
}
@@ -0,0 +1,17 @@
class U<A>
trait T<A> {
fun <caret>foofoofoo<B>(a: A, b: B): Int
}
abstract class T1<X> : T<U<X>> {
override fun <B> foofoofoo(a: U<X>, b: B): Int {
throw UnsupportedOperationException()
}
}
abstract class T2 : T1<String>() {
override fun <C> foofoofoo(a: U<String>, b: C): Int {
throw UnsupportedOperationException()
}
}
@@ -0,0 +1,5 @@
class J {
void test() {
_DefaultPackage.foo("1", new X(0), 2);
}
}
@@ -0,0 +1,9 @@
fun String.foo(x: X, k: Int): Boolean {
return x.k + length() - k > 0
}
class X(val k: Int)
fun test() {
"1".foo(X(0), 2)
}
@@ -0,0 +1,5 @@
class J {
void test() {
_DefaultPackage.foo(new X(0), "1", 2);
}
}
@@ -0,0 +1,9 @@
fun X.<caret>foo(s: String, k: Int): Boolean {
return this.k + s.length() - k > 0
}
class X(val k: Int)
fun test() {
X(0).foo("1", 2)
}
@@ -0,0 +1,5 @@
class J {
void test() {
new A(3).foo("1", new X(0), 2);
}
}
@@ -0,0 +1,19 @@
class A(val k: Int) {
fun String.foo(x: X, k: Int): Boolean {
return x.k + length() - k + this@A.k/2 > 0
}
fun test() {
"1".foo(X(0), 2)
}
}
class X(val k: Int)
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
fun test() {
with(A(3)) {
"1".foo(X(0), 2)
}
}
@@ -0,0 +1,5 @@
class J {
void test() {
new A(3).foo(new X(0), "1", 2);
}
}
@@ -0,0 +1,19 @@
class A(val k: Int) {
fun X.<caret>foo(s: String, k: Int): Boolean {
return this.k + s.length() - k + this@A.k/2 > 0
}
fun test() {
X(0).foo("1", 2)
}
}
class X(val k: Int)
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
fun test() {
with(A(3)) {
X(0).foo("1", 2)
}
}
@@ -0,0 +1,5 @@
class J {
void test() {
_DefaultPackage.foo(new X(0), "1", 2);
}
}
@@ -0,0 +1,9 @@
fun X.foo(s: String, k: Int): Boolean {
return this.k + s.length() - k > 0
}
class X(val k: Int)
fun test() {
X(0).foo("1", 2)
}
@@ -0,0 +1,5 @@
class J {
void test() {
_DefaultPackage.foo(new X(0), "1", 2);
}
}
@@ -0,0 +1,9 @@
fun <caret>foo(x: X, s: String, k: Int): Boolean {
return x.k + s.length() - k > 0
}
class X(val k: Int)
fun test() {
foo(X(0), "1", 2)
}
@@ -0,0 +1,5 @@
class J {
void test() {
_DefaultPackage.foo(new X(0), "1", 2);
}
}
@@ -0,0 +1,9 @@
fun X.foo(s: String, k: Int): Boolean {
return this.k + s.length() - k > 0
}
class X(val k: Int)
fun test() {
X(0).foo("1", 2)
}
@@ -0,0 +1,5 @@
class J {
void test() {
_DefaultPackage.foo("1", new X(0), 2);
}
}
@@ -0,0 +1,9 @@
fun <caret>foo(s: String, x: X, k: Int): Boolean {
return x.k + s.length() - k > 0
}
class X(val k: Int)
fun test() {
foo("1", X(0), 2)
}
@@ -0,0 +1,5 @@
class J {
void test() {
new A(3).foo(new X(0), "1", 2);
}
}
@@ -0,0 +1,19 @@
class A(val k: Int) {
fun X.foo(s: String, k: Int): Boolean {
return this.k + s.length() - k + this@A.k/2 > 0
}
fun test() {
X(0).foo("1", 2)
}
}
class X(val k: Int)
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
fun test() {
with(A(3)) {
X(0).foo("1", 2)
}
}
@@ -0,0 +1,5 @@
class J {
void test() {
new A(3).foo(new X(0), "1", 2);
}
}
@@ -0,0 +1,19 @@
class A(val k: Int) {
fun <caret>foo(x: X, s: String, k: Int): Boolean {
return x.k + s.length() - k + this.k/2 > 0
}
fun test() {
foo(X(0), "1", 2)
}
}
class X(val k: Int)
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
fun test() {
with(A(3)) {
foo(X(0), "1", 2)
}
}
@@ -0,0 +1,5 @@
class J {
void test() {
new A(3).foo(new X(0), "1", 2);
}
}
@@ -0,0 +1,19 @@
class A(val k: Int) {
fun X.foo(s: String, k: Int): Boolean {
return this.k + s.length() - k + this@A.k/2 > 0
}
fun test() {
X(0).foo("1", 2)
}
}
class X(val k: Int)
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
fun test() {
with(A(3)) {
X(0).foo("1", 2)
}
}
@@ -0,0 +1,5 @@
class J {
void test() {
new A(3).foo("1", new X(0), 2);
}
}
@@ -0,0 +1,19 @@
class A(val k: Int) {
fun <caret>foo(s: String, x: X, k: Int): Boolean {
return x.k + s.length() - k + this.k/2 > 0
}
fun test() {
foo("1", X(0), 2)
}
}
class X(val k: Int)
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
fun test() {
with(A(3)) {
foo("1", X(0), 2)
}
}
@@ -0,0 +1,20 @@
class A(val k: Int) {
fun <caret>foo(x: X, s: String, k: Int): Boolean {
return x.k + s.length() - k + this.k/2 > 0
}
fun test() {
foo(X(0), "1", 2)
}
}
class X(val k: Int)
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
fun test() {
A(3).foo(X(0), "1", 2)
with(A(3)) {
foo(X(0), "1", 2)
}
}
@@ -0,0 +1 @@
Explicit receiver is already present in call element: A(3).foo(X(0), &quot;1&quot;, 2)
@@ -0,0 +1,5 @@
class J {
void test() {
_DefaultPackage.foo(new X(0), "1", 2);
}
}
@@ -0,0 +1,14 @@
fun <caret>foo(x: X, s: String, k: Int): Boolean {
return x.k + s.length() - k > 0
}
class X(val k: Int)
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
fun test() {
foo(X(0), "1", 2)
with(X(0)) {
foo(this, "1", 2)
}
}
@@ -0,0 +1,5 @@
class J {
void test() {
_DefaultPackage.foo(new X(0), "1", 2);
}
}
@@ -0,0 +1,14 @@
fun X.<caret>foo(s: String, k: Int): Boolean {
return this.k + s.length() - k > 0
}
class X(val k: Int)
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
fun test() {
X(0).foo("1", 2)
with(X(0)) {
foo("1", 2)
}
}
@@ -0,0 +1,5 @@
class J {
void test() {
_DefaultPackage.foo("1", new X(0), 2);
}
}
@@ -0,0 +1,14 @@
fun <caret>foo(s: String, x: X, k: Int): Boolean {
return x.k + s.length() - k > 0
}
class X(val k: Int)
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
fun test() {
foo("1", X(0), 2)
with(X(0)) {
foo("1", this, 2)
}
}
@@ -0,0 +1,5 @@
class J {
void test() {
_DefaultPackage.foo(new X(0), "1", 2);
}
}
@@ -0,0 +1,14 @@
fun X.<caret>foo(s: String, k: Int): Boolean {
return this.k + s.length() - k > 0
}
class X(val k: Int)
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
fun test() {
X(0).foo("1", 2)
with(X(0)) {
foo("1", 2)
}
}
@@ -0,0 +1,5 @@
class X(val k: Int)
fun foo(abc: X, n: Int): Boolean {
return abc.k > n
}
@@ -0,0 +1,5 @@
class X(val k: Int)
fun X.<caret>foo(n: Int): Boolean {
return this.k > n
}
@@ -0,0 +1,5 @@
class J {
void test() {
new A(3).foo(new X(0), "1", 2);
}
}
@@ -0,0 +1,19 @@
class A(val k: Int) {
fun foo(x: X, s: String, k: Int): Boolean {
return x.k + s.length() - k + this.k/2 > 0
}
fun test() {
foo(X(0), "1", 2)
}
}
class X(val k: Int)
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
fun test() {
with(A(3)) {
foo(X(0), "1", 2)
}
}
@@ -0,0 +1,5 @@
class J {
void test() {
new A(3).foo(new X(0), "1", 2);
}
}
@@ -0,0 +1,19 @@
class A(val k: Int) {
fun X.<caret>foo(s: String, k: Int): Boolean {
return this.k + s.length() - k + this@A.k/2 > 0
}
fun test() {
X(0).foo("1", 2)
}
}
class X(val k: Int)
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
fun test() {
with(A(3)) {
X(0).foo("1", 2)
}
}
@@ -0,0 +1,5 @@
class J {
void test() {
new A(3).foo("1", new X(0), 2);
}
}
@@ -0,0 +1,19 @@
class A(val k: Int) {
fun foo(s: String, x: X, k: Int): Boolean {
return x.k + s.length() - k + this.k/2 > 0
}
fun test() {
foo("1", X(0), 2)
}
}
class X(val k: Int)
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
fun test() {
with(A(3)) {
foo("1", X(0), 2)
}
}
@@ -0,0 +1,5 @@
class J {
void test() {
new A(3).foo(new X(0), "1", 2);
}
}
@@ -0,0 +1,19 @@
class A(val k: Int) {
fun X.<caret>foo(s: String, k: Int): Boolean {
return this.k + s.length() - k + this@A.k/2 > 0
}
fun test() {
X(0).foo("1", 2)
}
}
class X(val k: Int)
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
fun test() {
with(A(3)) {
X(0).foo("1", 2)
}
}
@@ -0,0 +1,7 @@
val x1: Int
class X(val x: Int)
fun foo(x2: X, x: Int): Boolean {
return x2.x + x > x1
}
@@ -0,0 +1,7 @@
val x1: Int
class X(val x: Int)
fun X.<caret>foo(x: Int): Boolean {
return this.x + x > x1
}
@@ -0,0 +1,5 @@
class J {
void test() {
_DefaultPackage.foo("1", 2);
}
}
@@ -0,0 +1,14 @@
fun foo(s: String, k: Int): Boolean {
return this.k + s.length() - k > 0
}
class X(val k: Int)
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
fun test() {
with(X(0)) {
foo("1", 2)
}
foo("1", 2)
}
@@ -0,0 +1,5 @@
class J {
void test() {
_DefaultPackage.foo(new X(0), "1", 2);
}
}
@@ -0,0 +1,14 @@
fun X.<caret>foo(s: String, k: Int): Boolean {
return this.k + s.length() - k > 0
}
class X(val k: Int)
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
fun test() {
with(X(0)) {
foo("1", 2)
}
X(0).foo("1", 2)
}
@@ -0,0 +1,5 @@
class J {
void test() {
new A(3).foo(1, "2");
}
}
@@ -0,0 +1,19 @@
class A(val k: Int) {
fun foo(s: String, n: Int): Boolean {
return s.length() * this.k - n.inc() + this@A.k > 0
}
fun test() {
foo("1", 2)
}
}
class X(val k: Int)
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
fun test() {
with(A(3)) {
foo("1", 2)
}
}
@@ -0,0 +1,5 @@
class J {
void test() {
new A(3).foo(new X(0), 1, "2");
}
}
@@ -0,0 +1,19 @@
class A(val k: Int) {
fun X.<caret>foo(s: String, n: Int): Boolean {
return s.length() * this.k - n.inc() + this@A.k > 0
}
fun test() {
X(0).foo("1", 2)
}
}
class X(val k: Int)
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
fun test() {
with(A(3)) {
X(0).foo("1", 2)
}
}
@@ -318,7 +318,8 @@ public class JetChangeSignatureTest extends KotlinCodeInsightTestCase {
public void testFunctionJavaUsagesAndOverridesAddParam() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.addParameter(new JetParameterInfo(-1, "s", KotlinBuiltIns.getInstance().getStringType(), null, "\"abc\"", null, null));
changeInfo.addParameter(new JetParameterInfo(-1, "o", KotlinBuiltIns.getInstance().getNullableAnyType(), null, "\"def\"", null, null));
changeInfo.addParameter(
new JetParameterInfo(-1, "o", KotlinBuiltIns.getInstance().getNullableAnyType(), null, "\"def\"", null, null));
doTest(changeInfo);
}
@@ -360,6 +361,16 @@ public class JetChangeSignatureTest extends KotlinCodeInsightTestCase {
doTest(changeInfo);
}
public void testAddReceiverToGenericsWithOverrides() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
JetParameterInfo parameterInfo = changeInfo.getNewParameters()[0];
parameterInfo.setCurrentTypeText("U<A>");
changeInfo.setReceiverParameterInfo(parameterInfo);
doTest(changeInfo);
}
public void testJavaMethodKotlinUsages() throws Exception {
doJavaTest(
new JavaRefactoringProvider() {
@@ -582,6 +593,135 @@ public class JetChangeSignatureTest extends KotlinCodeInsightTestCase {
doTest(changeInfo);
}
public void testAddNewReceiver() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
JetParameterInfo parameterInfo = new JetParameterInfo(-1, "_", KotlinBuiltIns.getInstance().getAnyType(), null, "X(0)", null, null);
parameterInfo.setCurrentTypeText("X");
changeInfo.setReceiverParameterInfo(parameterInfo);
doTest(changeInfo);
}
public void testAddNewReceiverForMember() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
JetParameterInfo parameterInfo = new JetParameterInfo(-1, "_", KotlinBuiltIns.getInstance().getAnyType(), null, "X(0)", null, null);
parameterInfo.setCurrentTypeText("X");
changeInfo.setReceiverParameterInfo(parameterInfo);
doTest(changeInfo);
}
public void testAddNewReceiverForMemberConflict() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
JetParameterInfo parameterInfo = new JetParameterInfo(-1, "_", KotlinBuiltIns.getInstance().getAnyType(), null, "X(0)", null, null);
parameterInfo.setCurrentTypeText("X");
changeInfo.setReceiverParameterInfo(parameterInfo);
doTestConflict(changeInfo);
}
public void testAddNewReceiverConflict() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
JetParameterInfo parameterInfo = new JetParameterInfo(-1, "_", KotlinBuiltIns.getInstance().getAnyType(), null, "X(0)", null, null);
parameterInfo.setCurrentTypeText("X");
changeInfo.setReceiverParameterInfo(parameterInfo);
doTestConflict(changeInfo);
}
public void testRemoveReceiver() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.removeParameter(0);
doTest(changeInfo);
}
public void testRemoveReceiverForMember() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.removeParameter(0);
doTest(changeInfo);
}
public void testConvertParameterToReceiver1() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setReceiverParameterInfo(changeInfo.getNewParameters()[0]);
doTest(changeInfo);
}
public void testConvertParameterToReceiver2() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setReceiverParameterInfo(changeInfo.getNewParameters()[1]);
doTest(changeInfo);
}
public void testConvertReceiverToParameter1() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setReceiverParameterInfo(null);
doTest(changeInfo);
}
public void testConvertReceiverToParameter2() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setReceiverParameterInfo(null);
JetParameterInfo[] parameters = changeInfo.getNewParameters();
changeInfo.setNewParameter(0, parameters[1]);
changeInfo.setNewParameter(1, parameters[0]);
doTest(changeInfo);
}
public void testConvertParameterToReceiverForMember1() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setReceiverParameterInfo(changeInfo.getNewParameters()[0]);
doTest(changeInfo);
}
public void testConvertParameterToReceiverForMember2() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setReceiverParameterInfo(changeInfo.getNewParameters()[1]);
doTest(changeInfo);
}
public void testConvertParameterToReceiverForMemberConflict() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setReceiverParameterInfo(changeInfo.getNewParameters()[0]);
doTestConflict(changeInfo);
}
public void testConvertReceiverToParameterForMember1() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setReceiverParameterInfo(null);
doTest(changeInfo);
}
public void testConvertReceiverToParameterForMember2() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setReceiverParameterInfo(null);
JetParameterInfo[] parameters = changeInfo.getNewParameters();
changeInfo.setNewParameter(0, parameters[1]);
changeInfo.setNewParameter(1, parameters[0]);
doTest(changeInfo);
}
public void testConvertReceiverToParameterWithNameClash() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setReceiverParameterInfo(null);
doTest(changeInfo);
}
public void testConvertReceiverToParameterAndChangeName() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setReceiverParameterInfo(null);
changeInfo.getNewParameters()[0].setName("abc");
doTest(changeInfo);
}
public void testChangeReceiver() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setReceiverParameterInfo(changeInfo.getNewParameters()[1]);
doTest(changeInfo);
}
public void testChangeReceiverForMember() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.setReceiverParameterInfo(changeInfo.getNewParameters()[1]);
doTest(changeInfo);
}
@NotNull
@Override
protected String getTestDataPath() {