Change Signature: Propagate parameters to chosen callers

#KT-7902 Fixed
This commit is contained in:
Alexey Sedunov
2015-07-03 18:31:03 +03:00
parent 9853934087
commit eb7463ed81
46 changed files with 1334 additions and 102 deletions
@@ -19,13 +19,14 @@ package org.jetbrains.kotlin.idea.refactoring.changeSignature
import com.intellij.lang.Language
import com.intellij.lang.java.JavaLanguage
import com.intellij.psi.*
import com.intellij.refactoring.changeSignature.ChangeInfo
import com.intellij.refactoring.changeSignature.ChangeSignatureProcessor
import com.intellij.refactoring.changeSignature.JavaChangeInfo
import com.intellij.refactoring.changeSignature.ParameterInfoImpl
import com.intellij.psi.search.searches.OverridingMethodsSearch
import com.intellij.refactoring.changeSignature.*
import com.intellij.refactoring.util.CanonicalTypes
import com.intellij.usageView.UsageInfo
import com.intellij.util.VisibilityUtil
import org.jetbrains.kotlin.asJava.getRepresentativeLightMethod
import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.codegen.PropertyCodegen
import org.jetbrains.kotlin.descriptors.CallableDescriptor
@@ -37,16 +38,18 @@ import org.jetbrains.kotlin.idea.core.refactoring.j2k
import org.jetbrains.kotlin.idea.project.ProjectStructureUtil
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetMethodDescriptor.Kind
import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.JetCallableDefinitionUsage
import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.KotlinCallerUsage
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.parameterIndex
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
import java.util.*
import java.util.ArrayList
import java.util.HashMap
import java.util.LinkedHashSet
import kotlin.properties.Delegates
public class JetChangeInfo(
@@ -57,7 +60,8 @@ public class JetChangeInfo(
var newVisibility: Visibility = methodDescriptor.getVisibility(),
parameterInfos: List<JetParameterInfo> = methodDescriptor.getParameters(),
receiver: JetParameterInfo? = methodDescriptor.receiver,
val context: PsiElement
val context: PsiElement,
primaryPropagationTargets: Collection<PsiElement> = emptyList()
): ChangeInfo {
var receiverParameterInfo: JetParameterInfo? = receiver
set(value: JetParameterInfo?) {
@@ -148,6 +152,42 @@ public class JetChangeInfo(
override fun getLanguage(): Language = JetLanguage.INSTANCE
public var propagationTargetUsageInfos: List<UsageInfo> = ArrayList()
private set
public var primaryPropagationTargets: Collection<PsiElement> = emptyList()
set(value: Collection<PsiElement>) {
$primaryPropagationTargets = value
val result = LinkedHashSet<UsageInfo>()
fun add(element: PsiElement) {
element.unwrapped?.let {
val usageInfo = when (it) {
is JetNamedFunction, is JetConstructor<*>, is JetClassOrObject ->
KotlinCallerUsage(it as JetNamedDeclaration)
is PsiMethod ->
CallerUsageInfo(it, true, true)
else ->
return
}
result.add(usageInfo)
}
}
for (caller in value) {
add(caller)
OverridingMethodsSearch.search(caller.getRepresentativeLightMethod() ?: continue).forEach { add(it) }
}
propagationTargetUsageInfos = result.toList()
}
init {
this.primaryPropagationTargets = primaryPropagationTargets
}
public fun getNewSignature(inheritedCallable: JetCallableDefinitionUsage<PsiElement>): String {
val buffer = StringBuilder()
@@ -239,13 +279,22 @@ public class JetChangeInfo(
VisibilityUtil.getVisibilityModifier(currentPsiMethod.getModifierList())
else
PsiModifier.PACKAGE_LOCAL
val javaChangeInfo = ChangeSignatureProcessor(getMethod().getProject(),
originalPsiMethod,
false,
newVisibility,
newName,
newReturnType ?: PsiType.VOID,
newParameters).getChangeInfo()
val propagationTargets = primaryPropagationTargets.asSequence()
.map { it.getRepresentativeLightMethod() }
.filterNotNull()
.toSet()
val javaChangeInfo = ChangeSignatureProcessor(
getMethod().getProject(),
originalPsiMethod,
false,
newVisibility,
newName,
CanonicalTypes.createTypeWrapper(newReturnType ?: PsiType.VOID),
newParameters,
arrayOf<ThrownExceptionInfo>(),
propagationTargets,
emptySet()
).getChangeInfo()
javaChangeInfo.updateMethod(currentPsiMethod)
return javaChangeInfo
@@ -336,7 +385,7 @@ public val JetChangeInfo.kind: Kind get() = methodDescriptor.kind
public val JetChangeInfo.oldName: String?
get() = (methodDescriptor.getMethod() as? JetFunction)?.getName()
public val JetChangeInfo.affectedFunctions: Collection<UsageInfo> get() = methodDescriptor.affectedCallables
public fun JetChangeInfo.getAffectedCallables(): Collection<UsageInfo> = methodDescriptor.affectedCallables + propagationTargetUsageInfos
public fun ChangeInfo.toJetChangeInfo(originalChangeSignatureDescriptor: JetMethodDescriptor): JetChangeInfo {
val method = getMethod() as PsiMethod
@@ -369,7 +418,7 @@ public fun ChangeInfo.toJetChangeInfo(originalChangeSignatureDescriptor: JetMeth
name = info.getName(),
type = if (oldIndex >= 0) originalParameterDescriptors[oldIndex].getType() else currentType,
defaultValueForCall = defaultValueExpr)) {
currentTypeText = IdeDescriptorRenderers.SOURCE_CODE.renderType(currentType)
currentTypeText = IdeDescriptorRenderers.SOURCE_CODE_FOR_TYPE_ARGUMENTS.renderType(currentType)
this
}
}
@@ -26,6 +26,7 @@ import com.intellij.refactoring.changeSignature.ChangeSignatureProcessorBase
import com.intellij.refactoring.changeSignature.ChangeSignatureUsageProcessor
import com.intellij.refactoring.changeSignature.JavaChangeSignatureUsageProcessor
import com.intellij.refactoring.rename.RenameUtil
import com.intellij.refactoring.rename.UnresolvableCollisionUsageInfo
import com.intellij.usageView.UsageInfo
import com.intellij.usageView.UsageViewDescriptor
import com.intellij.util.containers.MultiMap
@@ -52,7 +53,7 @@ public class JetChangeSignatureProcessor(project: Project,
KotlinWrapperForJavaUsageInfos(it, javaProcessor.findUsages(it), getChangeInfo().getMethod())
}
}
super.findUsages().filterIsInstanceTo(allUsages, javaClass<JetUsageInfo<PsiElement>>())
super.findUsages().filterTo(allUsages) { it is JetUsageInfo<*> || it is UnresolvableCollisionUsageInfo }
return allUsages.toTypedArray()
}
@@ -28,6 +28,7 @@ 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.rename.UnresolvableCollisionUsageInfo;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.refactoring.util.MoveRenameUsageInfo;
import com.intellij.refactoring.util.RefactoringUIUtil;
@@ -54,6 +55,7 @@ import org.jetbrains.kotlin.idea.core.refactoring.RefactoringPackage;
import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.*;
import org.jetbrains.kotlin.idea.references.JetSimpleNameReference;
import org.jetbrains.kotlin.idea.search.usagesSearch.UsagesSearchPackage;
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers;
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName;
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor;
import org.jetbrains.kotlin.name.Name;
@@ -68,6 +70,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind;
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode;
import org.jetbrains.kotlin.resolve.scopes.JetScope;
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
@@ -80,6 +83,8 @@ import java.util.*;
public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsageProcessor {
@Override
public UsageInfo[] findUsages(ChangeInfo info) {
originalJavaMethodDescriptor = null;
Set<UsageInfo> result = new HashSet<UsageInfo>();
if (info instanceof JetChangeInfo) {
@@ -89,19 +94,29 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
findSAMUsages(info, result);
findConstructorDelegationUsages(info, result);
findKotlinOverrides(info, result);
if (info instanceof JavaChangeInfo) {
findKotlinCallers((JavaChangeInfo) info, result);
}
}
return result.toArray(new UsageInfo[result.size()]);
}
private static void findAllMethodUsages(JetChangeInfo changeInfo, Set<UsageInfo> result) {
for (UsageInfo functionUsageInfo : ChangeSignaturePackage.getAffectedFunctions(changeInfo)) {
for (UsageInfo functionUsageInfo : ChangeSignaturePackage.getAffectedCallables(changeInfo)) {
if (functionUsageInfo instanceof JetCallableDefinitionUsage) {
findOneMethodUsages((JetCallableDefinitionUsage) functionUsageInfo, changeInfo, result);
}
else if (functionUsageInfo instanceof KotlinCallerUsage) {
findCallerUsages((KotlinCallerUsage) functionUsageInfo, changeInfo, result);
}
else {
result.add(functionUsageInfo);
boolean propagationTarget = functionUsageInfo instanceof CallerUsageInfo
|| (functionUsageInfo instanceof OverriderUsageInfo
&& !((OverriderUsageInfo) functionUsageInfo).isOriginalOverrider());
PsiElement callee = functionUsageInfo.getElement();
if (callee == null) continue;
@@ -115,13 +130,89 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
JetCallElement callElement = PsiTreeUtil.getParentOfType(element, JetCallElement.class);
JetExpression calleeExpression = callElement != null ? callElement.getCalleeExpression() : null;
if (calleeExpression != null && PsiTreeUtil.isAncestor(calleeExpression, element, false)) {
result.add(new JetFunctionCallUsage(callElement, changeInfo.getMethodDescriptor().getOriginalPrimaryCallable()));
result.add(propagationTarget
? new KotlinCallerCallUsage(callElement)
: new JetFunctionCallUsage(callElement, changeInfo.getMethodDescriptor().getOriginalPrimaryCallable()));
}
}
}
}
}
private static void findCallerUsages(KotlinCallerUsage callerUsage, JetChangeInfo changeInfo, final Set<UsageInfo> result) {
result.add(callerUsage);
JetNamedDeclaration element = callerUsage.getElement();
if (element == null) return;
for (PsiReference ref : ReferencesSearch.search(element, element.getUseScope())) {
PsiElement refElement = ref.getElement();
JetCallElement callElement = PsiTreeUtil.getParentOfType(refElement, JetCallElement.class);
if (callElement != null && PsiTreeUtil.isAncestor(callElement.getCalleeExpression(), refElement, false)) {
result.add(new KotlinCallerCallUsage(callElement));
}
}
JetElement body = ChangeSignaturePackage.getDeclarationBody(element);
final Set<String> newParameterNames = KotlinPackage.mapTo(
changeInfo.getNonReceiverParameters(),
new HashSet<String>(),
new Function1<JetParameterInfo, String>() {
@Override
public String invoke(JetParameterInfo info) {
return info.getName();
}
}
);
if (body != null) {
final DeclarationDescriptor callerDescriptor = ResolvePackage.resolveToDescriptor(element);
final BindingContext context = ResolvePackage.analyze(body);
body.accept(
new JetTreeVisitorVoid() {
@Override
public void visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression) {
final String currentName = expression.getReferencedName();
if (!newParameterNames.contains(currentName)) return;
ResolvedCall<? extends CallableDescriptor> resolvedCall = CallUtilPackage.getResolvedCall(expression, context);
if (resolvedCall == null) return;
if (resolvedCall.getExplicitReceiverKind() != ExplicitReceiverKind.NO_EXPLICIT_RECEIVER) return;
CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor();
if (!(resultingDescriptor instanceof VariableDescriptor)) return;
// Do not report usages of duplicated parameter
if (resultingDescriptor instanceof ValueParameterDescriptor
&& resultingDescriptor.getContainingDeclaration() == callerDescriptor) return;
JetElement callElement = resolvedCall.getCall().getCallElement();
ReceiverValue receiver = resolvedCall.getExtensionReceiver();
if (!(receiver instanceof ThisReceiver)) {
receiver = resolvedCall.getDispatchReceiver();
}
if (receiver instanceof ThisReceiver) {
result.add(new JetImplicitThisUsage(callElement, ((ThisReceiver) receiver).getDeclarationDescriptor()));
}
else if (!receiver.exists()) {
result.add(
new UnresolvableCollisionUsageInfo(callElement, null) {
@Override
public String getDescription() {
return "There is already a variable '" + currentName + "' in " +
IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.render(callerDescriptor) +
". It will conflict with the new parameter.";
}
}
);
}
}
}
);
}
}
private static void findOneMethodUsages(
@NotNull JetCallableDefinitionUsage<?> functionUsageInfo,
final JetChangeInfo changeInfo,
@@ -269,7 +360,7 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
result.add(new JetImplicitThisToParameterUsage(callElement, originalReceiverInfo, functionUsageInfo));
}
else {
result.add(new JetImplicitOuterThisToQualifiedThisUsage(callElement, targetDescriptor));
result.add(new JetImplicitThisUsage(callElement, targetDescriptor));
}
}
@@ -375,6 +466,25 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
}
}
private static void findKotlinCallers(JavaChangeInfo changeInfo, Set<UsageInfo> result) {
PsiElement method = changeInfo.getMethod();
if (!RefactoringPackage.isTrueJavaMethod(method)) return;
for (PsiMethod primaryCaller : changeInfo.getMethodsToPropagateParameters()) {
addDeferredCallerIfPossible(result, primaryCaller);
for (PsiMethod overridingCaller : OverridingMethodsSearch.search(primaryCaller)) {
addDeferredCallerIfPossible(result, overridingCaller);
}
}
}
private static void addDeferredCallerIfPossible(Set<UsageInfo> result, PsiMethod overridingCaller) {
PsiElement unwrappedElement = AsJavaPackage.getNamedUnwrappedElement(overridingCaller);
if (unwrappedElement instanceof JetFunction || unwrappedElement instanceof JetClass) {
result.add(new DeferredJavaMethodKotlinCallerUsage((JetNamedDeclaration) unwrappedElement));
}
}
private static void findDeferredUsagesOfParameters(
ChangeInfo changeInfo,
Set<UsageInfo> result,
@@ -408,7 +518,7 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
javaMethodChangeInfo) {
@NotNull
@Override
protected JetUsageInfo<JetElement> getDelegateUsage() {
public JetUsageInfo<JetElement> getDelegateUsage() {
return new JetParameterUsage((JetElement) element,
getJavaMethodChangeInfo().getNewParameters()[paramIndex],
functionInfoForParameters);
@@ -428,16 +538,15 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
public MultiMap<PsiElement, String> findConflicts(ChangeInfo info, Ref<UsageInfo[]> refUsages) {
MultiMap<PsiElement, String> result = new MultiMap<PsiElement, String>();
// Delete OverriderUsageInfo for Kotlin declarations since they can't be processed correctly
// TODO: Drop when OverriderUsageInfo.getElement() gets deleted
// Delete OverriderUsageInfo and CallerUsageInfo for Kotlin declarations since they can't be processed correctly
// TODO (OverriderUsageInfo only): Drop when OverriderUsageInfo.getElement() gets deleted
UsageInfo[] usageInfos = refUsages.get();
List<UsageInfo> adjustedUsages = KotlinPackage.filterNot(
usageInfos,
new Function1<UsageInfo, Boolean>() {
@Override
public Boolean invoke(UsageInfo info) {
return info instanceof OverriderUsageInfo &&
((OverriderUsageInfo) info).getOverridingMethod() instanceof KotlinLightMethod;
return getOverriderOrCaller(info) instanceof KotlinLightMethod;
}
}
);
@@ -519,9 +628,47 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
findThisLabelConflicts((JetChangeInfo) info, refUsages, result, changeInfo, function);
}
for (UsageInfo usageInfo : usageInfos) {
if (!(usageInfo instanceof KotlinCallerUsage)) continue;
JetNamedDeclaration caller = (JetNamedDeclaration) usageInfo.getElement();
DeclarationDescriptor callerDescriptor = ResolvePackage.resolveToDescriptor(caller);
findParameterDuplicationInCaller(result, changeInfo, caller, callerDescriptor);
}
return result;
}
private static void findParameterDuplicationInCaller(
MultiMap<PsiElement, String> result,
JetChangeInfo changeInfo,
JetNamedDeclaration caller,
DeclarationDescriptor callerDescriptor
) {
List<JetParameter> valueParameters = PsiUtilPackage.getValueParameters(caller);
Map<String, JetParameter> existingParameters = KotlinPackage.toMap(
valueParameters,
new Function1<JetParameter, String>() {
@Override
public String invoke(JetParameter parameter) {
return parameter.getName();
}
}
);
for (JetParameterInfo parameterInfo : changeInfo.getNonReceiverParameters()) {
if (!(parameterInfo.getIsNewParameter())) continue;
String name = parameterInfo.getName();
JetParameter parameter = existingParameters.get(name);
if (parameter != null) {
result.putValue(parameter, "There is already a parameter '" + name + "' in " +
IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.render(callerDescriptor) +
". It will conflict with the new parameter.");
}
}
}
private static void findThisLabelConflicts(
JetChangeInfo info,
Ref<UsageInfo[]> refUsages,
@@ -666,21 +813,24 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
private JetMethodDescriptor originalJavaMethodDescriptor;
private static boolean isJavaMethodUsage(UsageInfo usageInfo) {
if (usageInfo instanceof JavaMethodDeferredKotlinUsage) return true;
// MoveRenameUsageInfo corresponds to non-Java usage of Java method
return usageInfo instanceof MoveRenameUsageInfo
&& RefactoringPackage.isTrueJavaMethod(((MoveRenameUsageInfo) usageInfo).getReferencedElement());
return usageInfo instanceof JavaMethodDeferredKotlinUsage || usageInfo instanceof MoveRenameUsageInfo;
}
@Nullable
private static UsageInfo createReplacementUsage(UsageInfo originalUsageInfo, JetChangeInfo javaMethodChangeInfo) {
private static UsageInfo createReplacementUsage(UsageInfo originalUsageInfo, JetChangeInfo javaMethodChangeInfo, UsageInfo[] allUsages) {
if (originalUsageInfo instanceof JavaMethodDeferredKotlinUsage) {
return ((JavaMethodDeferredKotlinUsage<?>) originalUsageInfo).resolve(javaMethodChangeInfo);
}
JetCallElement callElement = PsiTreeUtil.getParentOfType(originalUsageInfo.getElement(), JetCallElement.class);
return callElement != null ? new JavaMethodKotlinCallUsage(callElement, javaMethodChangeInfo) : null;
if (callElement == null) return null;
PsiReference ref = originalUsageInfo.getReference();
PsiElement refTarget = ref != null ? ref.resolve() : null;
return new JavaMethodKotlinCallUsage(callElement,
javaMethodChangeInfo,
refTarget != null && ChangeSignaturePackage.isCaller(refTarget, allUsages));
}
private static class NullabilityPropagator {
@@ -752,6 +902,20 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
}
}
private static boolean isOverriderOrCaller(UsageInfo usage) {
return usage instanceof OverriderUsageInfo || usage instanceof CallerUsageInfo;
}
@Nullable
private static PsiMethod getOverriderOrCaller(UsageInfo usage) {
if (usage instanceof OverriderUsageInfo) return ((OverriderUsageInfo) usage).getOverridingMethod();
if (usage instanceof CallerUsageInfo) {
PsiElement element = usage.getElement();
return element instanceof PsiMethod ? (PsiMethod) element : null;
}
return null;
}
@Override
public boolean processUsage(ChangeInfo changeInfo, UsageInfo usageInfo, boolean beforeMethodChange, UsageInfo[] usages) {
PsiElement method = changeInfo.getMethod();
@@ -772,15 +936,15 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
NullabilityPropagator nullabilityPropagator = new NullabilityPropagator(javaChangeInfo.getMethod());
for (UsageInfo usage : javaUsageInfos) {
if (usage instanceof OverriderUsageInfo && beforeMethodChange) continue;
if (isOverriderOrCaller(usage) && beforeMethodChange) continue;
for (ChangeSignatureUsageProcessor processor : processors) {
if (processor instanceof JetChangeSignatureUsageProcessor) continue;
if (usage instanceof OverriderUsageInfo) {
if (isOverriderOrCaller(usage)) {
processor.processUsage(javaChangeInfo, usage, true, javaUsageInfos);
}
if (processor.processUsage(javaChangeInfo, usage, beforeMethodChange, javaUsageInfos)) break;
}
if (usage instanceof OverriderUsageInfo) {
if (usage instanceof OverriderUsageInfo && ((OverriderUsageInfo) usage).isOriginalOverrider()) {
PsiMethod overridingMethod = ((OverriderUsageInfo) usage).getOverridingMethod();
if (overridingMethod != null && !(overridingMethod instanceof KotlinLightMethod)) {
nullabilityPropagator.processMethod(overridingMethod);
@@ -791,23 +955,29 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
}
if (beforeMethodChange) {
if (isJavaMethodUsage) {
boolean startedFromJava = method instanceof PsiMethod;
if (startedFromJava && originalJavaMethodDescriptor == null) {
FunctionDescriptor methodDescriptor = ResolvePackage.getJavaMethodDescriptor((PsiMethod) method);
JetChangeSignatureData changeSignatureData =
new JetChangeSignatureData(methodDescriptor, method, Collections.singletonList(methodDescriptor));
if (changeSignatureData != originalJavaMethodDescriptor) {
originalJavaMethodDescriptor = changeSignatureData;
}
originalJavaMethodDescriptor =
new JetChangeSignatureData(methodDescriptor, method, Collections.singletonList(methodDescriptor));;
// This change info is used as a placeholder before primary method update
// It gets replaced with real change info afterwards
JetChangeInfo dummyChangeInfo =
new JetChangeInfo(originalJavaMethodDescriptor, "", null, "", Visibilities.INTERNAL, Collections.<JetParameterInfo>emptyList(), null, changeInfo.getMethod());
new JetChangeInfo(originalJavaMethodDescriptor,
"",
null,
"",
Visibilities.INTERNAL,
Collections.<JetParameterInfo>emptyList(),
null,
changeInfo.getMethod(),
Collections.<PsiElement>emptyList());
for (int i = 0; i < usages.length; i++) {
UsageInfo oldUsageInfo = usages[i];
if (!isJavaMethodUsage(oldUsageInfo)) continue;
UsageInfo newUsageInfo = createReplacementUsage(oldUsageInfo, dummyChangeInfo);
UsageInfo newUsageInfo = createReplacementUsage(oldUsageInfo, dummyChangeInfo, usages);
if (newUsageInfo != null) {
usages[i] = newUsageInfo;
}
@@ -832,7 +1002,7 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
}
if (usageInfo instanceof JavaMethodKotlinUsageWithDelegate) {
return ((JavaMethodKotlinUsageWithDelegate) usageInfo).processUsage();
return ((JavaMethodKotlinUsageWithDelegate) usageInfo).processUsage(usages);
}
if (usageInfo instanceof MoveRenameUsageInfo && isJavaMethodUsage) {
@@ -846,7 +1016,7 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
return false;
}
return usageInfo instanceof JetUsageInfo ? ((JetUsageInfo) usageInfo).processUsage((JetChangeInfo) changeInfo, element) : true;
return usageInfo instanceof JetUsageInfo ? ((JetUsageInfo) usageInfo).processUsage((JetChangeInfo) changeInfo, element, usages) : true;
}
@Override
@@ -855,7 +1025,7 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
JetChangeInfo jetChangeInfo = (JetChangeInfo) changeInfo;
for (JetCallableDefinitionUsage primaryFunction : jetChangeInfo.getMethodDescriptor().getPrimaryCallables()) {
primaryFunction.processUsage(jetChangeInfo, primaryFunction.getDeclaration());
primaryFunction.processUsage(jetChangeInfo, primaryFunction.getDeclaration(), UsageInfo.EMPTY_ARRAY);
}
jetChangeInfo.primaryMethodUpdated();
return true;
@@ -0,0 +1,59 @@
/*
* Copyright 2010-2015 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
import com.intellij.psi.PsiElement
import com.intellij.refactoring.changeSignature.CallerUsageInfo
import com.intellij.refactoring.changeSignature.OverriderUsageInfo
import com.intellij.usageView.UsageInfo
import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.DeferredJavaMethodKotlinCallerUsage
import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.JavaMethodKotlinUsageWithDelegate
import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.KotlinCallerUsage
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
private fun JetNamedDeclaration.getDeclarationBody(): JetElement? {
return when {
this is JetClassOrObject -> getDelegationSpecifierList()
this is JetPrimaryConstructor -> getContainingClassOrObject().getDelegationSpecifierList()
this is JetSecondaryConstructor -> getDelegationCall()
this is JetNamedFunction -> getBodyExpression()
else -> null
}
}
public fun PsiElement.isCaller(allUsages: Array<out UsageInfo>): Boolean {
val elementToSearch = (this as? JetClass)?.getPrimaryConstructor() ?: this
return allUsages
.asSequence()
.filter {
val usage = (it as? JavaMethodKotlinUsageWithDelegate<*>)?.delegateUsage ?: it
usage is KotlinCallerUsage
|| usage is DeferredJavaMethodKotlinCallerUsage
|| usage is CallerUsageInfo
|| (usage is OverriderUsageInfo && !usage.isOriginalOverrider())
}
.any { it.getElement() == elementToSearch }
}
public fun JetElement.isInsideOfCallerBody(allUsages: Array<out UsageInfo>): Boolean {
val container = parentsWithSelf.firstOrNull {
it is JetNamedFunction || it is JetConstructor<*> || it is JetClassOrObject
} as? JetNamedDeclaration ?: return false
val body = container.getDeclarationBody() ?: return false
return body.getTextRange().contains(getTextRange()) && container.isCaller(allUsages)
}
@@ -20,7 +20,6 @@ import com.intellij.openapi.editor.colors.EditorColorsManager
import com.intellij.openapi.editor.colors.EditorFontType
import com.intellij.openapi.editor.event.DocumentAdapter
import com.intellij.openapi.editor.event.DocumentEvent
import com.intellij.openapi.fileTypes.LanguageFileType
import com.intellij.openapi.options.ConfigurationException
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.VerticalFlowLayout
@@ -30,18 +29,15 @@ import com.intellij.psi.PsiCodeFragment
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement
import com.intellij.refactoring.BaseRefactoringProcessor
import com.intellij.refactoring.changeSignature.CallerChooserBase
import com.intellij.refactoring.changeSignature.ChangeSignatureDialogBase
import com.intellij.refactoring.changeSignature.MethodDescriptor
import com.intellij.refactoring.changeSignature.ParameterTableModelItemBase
import com.intellij.refactoring.ui.ComboBoxVisibilityPanel
import com.intellij.refactoring.ui.VisibilityPanelBase
import com.intellij.ui.DottedBorder
import com.intellij.ui.EditorTextField
import com.intellij.ui.components.JBLabel
import com.intellij.ui.treeStructure.Tree
import com.intellij.util.Consumer
import com.intellij.util.Function
import com.intellij.util.IJSwingUtilities
import com.intellij.util.ui.UIUtil
import com.intellij.util.ui.table.JBTableRow
@@ -158,6 +154,10 @@ public class JetChangeSignatureDialog(
override fun createCallerChooser(title: String, treeToReuse: Tree?, callback: Consumer<Set<PsiElement>>) =
KotlinCallerChooser(myMethod.getMethod(), myProject, title, treeToReuse, callback)
// Forbid receiver propagation
override fun mayPropagateParameters() =
getParameters().any { it.isNewParameter && it != parametersTableModel.getReceiver() }
override fun getTableEditor(table: JTable, item: ParameterTableModelItemBase<JetParameterInfo>): JBTableRowEditor? {
return object : JBTableRowEditor() {
private val components = ArrayList<JComponent>()
@@ -364,6 +364,7 @@ public class JetChangeSignatureDialog(
getVisibility(),
getMethodName(),
myDefaultValueContext)
changeInfo.primaryPropagationTargets = myMethodsToPropagateParameters ?: emptyList();
return JetChangeSignatureProcessor(myProject, changeInfo, commandName ?: getTitle())
}
@@ -22,35 +22,41 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo
import org.jetbrains.kotlin.psi.JetConstructorDelegationCall
import org.jetbrains.kotlin.psi.JetFunction
import org.jetbrains.kotlin.psi.JetNamedDeclaration
import org.jetbrains.kotlin.types.JetType
public abstract class JavaMethodDeferredKotlinUsage<T: PsiElement>(element: T): UsageInfo(element) {
abstract fun resolve(javaMethodChangeInfo: JetChangeInfo): JavaMethodKotlinUsageWithDelegate<T>
public abstract class JavaMethodDeferredKotlinUsage<T : PsiElement>(element: T) : UsageInfo(element) {
abstract fun resolve(javaMethodChangeInfo: JetChangeInfo): JavaMethodKotlinUsageWithDelegate<T>
}
public class DeferredJavaMethodOverrideOrSAMUsage(
val function: JetFunction,
val functionDescriptor: FunctionDescriptor,
val samCallType: JetType?
): JavaMethodDeferredKotlinUsage<JetFunction>(function) {
override fun resolve(javaMethodChangeInfo: JetChangeInfo): JavaMethodKotlinUsageWithDelegate<JetFunction> {
return object : JavaMethodKotlinUsageWithDelegate<JetFunction>(function, javaMethodChangeInfo) {
override val delegateUsage = JetCallableDefinitionUsage(
function,
functionDescriptor,
javaMethodChangeInfo.methodDescriptor.originalPrimaryCallable,
samCallType
)
}
) : JavaMethodDeferredKotlinUsage<JetFunction>(function) {
override fun resolve(javaMethodChangeInfo: JetChangeInfo): JavaMethodKotlinUsageWithDelegate<JetFunction> {
return object : JavaMethodKotlinUsageWithDelegate<JetFunction>(function, javaMethodChangeInfo) {
override val delegateUsage = JetCallableDefinitionUsage(function, functionDescriptor, javaMethodChangeInfo.methodDescriptor.originalPrimaryCallable, samCallType)
}
}
}
public class DeferredJavaMethodKotlinCallerUsage(
val declaration: JetNamedDeclaration
) : JavaMethodDeferredKotlinUsage<JetNamedDeclaration>(declaration) {
override fun resolve(javaMethodChangeInfo: JetChangeInfo): JavaMethodKotlinUsageWithDelegate<JetNamedDeclaration> {
return object : JavaMethodKotlinUsageWithDelegate<JetNamedDeclaration>(declaration, javaMethodChangeInfo) {
override val delegateUsage = KotlinCallerUsage(declaration)
}
}
}
public class JavaConstructorDeferredUsageInDelegationCall(
val delegationCall: JetConstructorDelegationCall
): JavaMethodDeferredKotlinUsage<JetConstructorDelegationCall>(delegationCall) {
override fun resolve(javaMethodChangeInfo: JetChangeInfo): JavaMethodKotlinUsageWithDelegate<JetConstructorDelegationCall> {
return object : JavaMethodKotlinUsageWithDelegate<JetConstructorDelegationCall>(delegationCall, javaMethodChangeInfo) {
override val delegateUsage = JetConstructorDelegationCallUsage(delegationCall, javaMethodChangeInfo)
}
) : JavaMethodDeferredKotlinUsage<JetConstructorDelegationCall>(delegationCall) {
override fun resolve(javaMethodChangeInfo: JetChangeInfo): JavaMethodKotlinUsageWithDelegate<JetConstructorDelegationCall> {
return object : JavaMethodKotlinUsageWithDelegate<JetConstructorDelegationCall>(delegationCall, javaMethodChangeInfo) {
override val delegateUsage = JetConstructorDelegationCallUsage(delegationCall, javaMethodChangeInfo)
}
}
}
@@ -26,13 +26,18 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
public abstract class JavaMethodKotlinUsageWithDelegate<T: PsiElement>(
val psiElement: T,
var javaMethodChangeInfo: JetChangeInfo): UsageInfo(psiElement) {
protected abstract val delegateUsage: JetUsageInfo<T>
abstract val delegateUsage: JetUsageInfo<T>
fun processUsage(): Boolean = delegateUsage.processUsage(javaMethodChangeInfo, psiElement)
fun processUsage(allUsages: Array<UsageInfo>): Boolean = delegateUsage.processUsage(javaMethodChangeInfo, psiElement, allUsages)
}
public class JavaMethodKotlinCallUsage(
callElement: JetCallElement,
javaMethodChangeInfo: JetChangeInfo): JavaMethodKotlinUsageWithDelegate<JetCallElement>(callElement, javaMethodChangeInfo) {
override protected val delegateUsage = JetFunctionCallUsage(psiElement, javaMethodChangeInfo.methodDescriptor.originalPrimaryCallable)
javaMethodChangeInfo: JetChangeInfo,
propagationCall: Boolean): JavaMethodKotlinUsageWithDelegate<JetCallElement>(callElement, javaMethodChangeInfo) {
override val delegateUsage = if (propagationCall) {
KotlinCallerCallUsage(psiElement)
} else {
JetFunctionCallUsage(psiElement, javaMethodChangeInfo.methodDescriptor.originalPrimaryCallable)
}
}
@@ -21,6 +21,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.usageView.UsageInfo;
import kotlin.KotlinPackage;
import kotlin.Pair;
import org.jetbrains.annotations.NotNull;
@@ -165,7 +166,7 @@ public class JetCallableDefinitionUsage<T extends PsiElement> extends JetUsageIn
}
@Override
public boolean processUsage(@NotNull JetChangeInfo changeInfo, @NotNull PsiElement element) {
public boolean processUsage(@NotNull JetChangeInfo changeInfo, @NotNull PsiElement element, @NotNull UsageInfo[] allUsages) {
if (!(element instanceof JetNamedDeclaration)) return true;
JetPsiFactory psiFactory = JetPsiFactory(element.getProject());
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.idea.refactoring.changeSignature.usages
import com.intellij.usageView.UsageInfo
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo
import org.jetbrains.kotlin.psi.JetConstructorDelegationCall
import org.jetbrains.kotlin.psi.JetPsiFactory
@@ -27,7 +28,7 @@ public class JetConstructorDelegationCallUsage(
) : JetUsageInfo<JetConstructorDelegationCall>(call) {
val delegate = JetFunctionCallUsage(call, changeInfo.methodDescriptor.originalPrimaryCallable)
override fun processUsage(changeInfo: JetChangeInfo, element: JetConstructorDelegationCall): Boolean {
override fun processUsage(changeInfo: JetChangeInfo, element: JetConstructorDelegationCall, allUsages: Array<out UsageInfo>): Boolean {
val isThisCall = element.isCallToThis()
var elementToWorkWith = element
@@ -36,7 +37,7 @@ public class JetConstructorDelegationCallUsage(
elementToWorkWith = constructor.replaceImplicitDelegationCallWithExplicit(isThisCall)
}
val result = delegate.processUsage(changeInfo, elementToWorkWith)
val result = delegate.processUsage(changeInfo, elementToWorkWith, allUsages)
if (changeInfo.getNewParametersCount() == 0 && !isThisCall && !elementToWorkWith.isImplicit()) {
(elementToWorkWith.getParent() as? JetSecondaryConstructor)?.getColon()?.delete()
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.idea.refactoring.changeSignature.usages
import com.intellij.usageView.UsageInfo
import org.jetbrains.kotlin.psi.JetEnumEntry
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo
import org.jetbrains.kotlin.psi.JetPsiFactory
@@ -24,7 +25,7 @@ import org.jetbrains.kotlin.psi.JetDelegatorToSuperCall
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
public class JetEnumEntryWithoutSuperCallUsage(enumEntry: JetEnumEntry) : JetUsageInfo<JetEnumEntry>(enumEntry) {
override fun processUsage(changeInfo: JetChangeInfo, element: JetEnumEntry): Boolean {
override fun processUsage(changeInfo: JetChangeInfo, element: JetEnumEntry, allUsages: Array<out UsageInfo>): Boolean {
if (changeInfo.getNewParameters().size() > 0) {
val psiFactory = JetPsiFactory(element)
@@ -36,7 +37,7 @@ public class JetEnumEntryWithoutSuperCallUsage(enumEntry: JetEnumEntry) : JetUsa
element.addBefore(psiFactory.createColon(), delegatorToSuperCall)
return JetFunctionCallUsage(delegatorToSuperCall, changeInfo.methodDescriptor.originalPrimaryCallable)
.processUsage(changeInfo, delegatorToSuperCall)
.processUsage(changeInfo, delegatorToSuperCall, allUsages)
}
return true
@@ -20,6 +20,7 @@ import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.usageView.UsageInfo;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.TIntArrayList;
import gnu.trove.TIntProcedure;
@@ -34,6 +35,7 @@ import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage;
import org.jetbrains.kotlin.idea.codeInsight.shorten.ShortenPackage;
import org.jetbrains.kotlin.idea.core.CorePackage;
import org.jetbrains.kotlin.idea.refactoring.changeSignature.ChangeSignaturePackage;
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo;
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetParameterInfo;
import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.ExtractionEnginePackage;
@@ -89,14 +91,14 @@ public class JetFunctionCallUsage extends JetUsageInfo<JetCallElement> {
}
@Override
public boolean processUsage(JetChangeInfo changeInfo, JetCallElement element) {
public boolean processUsage(@NotNull JetChangeInfo changeInfo, @NotNull JetCallElement element, @NotNull UsageInfo[] allUsages) {
if (shouldSkipUsage(element)) return true;
changeNameIfNeeded(changeInfo, element);
if (element.getValueArgumentList() != null) {
if (changeInfo.isParameterSetOrOrderChanged()) {
updateArgumentsAndReceiver(changeInfo, element);
updateArgumentsAndReceiver(changeInfo, element, allUsages);
}
else {
changeArgumentNames(changeInfo, element);
@@ -319,7 +321,7 @@ public class JetFunctionCallUsage extends JetUsageInfo<JetCallElement> {
return newExpression;
}
private void updateArgumentsAndReceiver(JetChangeInfo changeInfo, JetCallElement element) {
private void updateArgumentsAndReceiver(JetChangeInfo changeInfo, JetCallElement element, @NotNull UsageInfo[] allUsages) {
JetValueArgumentList arguments = element.getValueArgumentList();
assert arguments != null : "Argument list is expected: " + element.getText();
List<? extends ValueArgument> oldArguments = element.getValueArguments();
@@ -347,11 +349,18 @@ public class JetFunctionCallUsage extends JetUsageInfo<JetCallElement> {
}
JetExpression defaultValueForCall = parameterInfo.getDefaultValueForCall();
String defaultValueText = defaultValueForCall != null
? substituteReferences(defaultValueForCall,
parameterInfo.getDefaultValueParameterReferences(),
psiFactory).getText()
: "";
String defaultValueText;
if (ChangeSignaturePackage.isInsideOfCallerBody(element, allUsages)) {
defaultValueText = parameterInfo.getName();
}
else {
defaultValueText = defaultValueForCall != null
? substituteReferences(defaultValueForCall,
parameterInfo.getDefaultValueParameterReferences(),
psiFactory).getText()
: "";
}
if (isNamedCall) {
String newName = parameterInfo.getInheritedName(callee);
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.idea.refactoring.changeSignature.usages
import com.intellij.usageView.UsageInfo
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetParameterInfo
import org.jetbrains.kotlin.psi.JetPsiFactory
@@ -32,7 +33,7 @@ public abstract class JetImplicitReceiverUsage(callElement: JetElement): JetUsag
}
override fun processUsage(changeInfo: JetChangeInfo, element: JetElement): Boolean {
override fun processUsage(changeInfo: JetChangeInfo, element: JetElement, allUsages: Array<out UsageInfo>): Boolean {
val newQualifiedCall = JetPsiFactory(element.getProject()).createExpression(
"${getNewReceiverText()}.${element.getText()}"
) as JetQualifiedExpression
@@ -53,7 +54,7 @@ public class JetImplicitThisToParameterUsage(
}
}
public class JetImplicitOuterThisToQualifiedThisUsage(
public class JetImplicitThisUsage(
callElement: JetElement,
val targetDescriptor: DeclarationDescriptor
): JetImplicitReceiverUsage(callElement) {
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.idea.refactoring.changeSignature.usages
import com.intellij.usageView.UsageInfo
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
import org.jetbrains.kotlin.psi.JetPsiFactory
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo
@@ -35,7 +36,7 @@ public abstract class JetExplicitReferenceUsage<T: JetElement>(element: T) : Jet
}
override fun processUsage(changeInfo: JetChangeInfo, element: T): Boolean {
override fun processUsage(changeInfo: JetChangeInfo, element: T, allUsages: Array<out UsageInfo>): Boolean {
val newElement = JetPsiFactory(element.getProject()).createExpression(getReplacementText(changeInfo))
val elementToReplace = (element.getParent() as? JetThisExpression) ?: element
processReplacedElement(elementToReplace.replace(newElement) as JetElement)
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.idea.refactoring.changeSignature.usages
import com.intellij.usageView.UsageInfo
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo
import org.jetbrains.kotlin.psi.JetPsiFactory
@@ -29,7 +30,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
public class JetPropertyCallUsage(element: JetSimpleNameExpression): JetUsageInfo<JetSimpleNameExpression>(element) {
private val resolvedCall = element.getResolvedCall(element.analyze())
override fun processUsage(changeInfo: JetChangeInfo, element: JetSimpleNameExpression): Boolean {
override fun processUsage(changeInfo: JetChangeInfo, element: JetSimpleNameExpression, allUsages: Array<out UsageInfo>): Boolean {
updateName(changeInfo, element)
updateReceiver(changeInfo, element)
return true
@@ -28,5 +28,5 @@ public abstract class JetUsageInfo<T : PsiElement> : UsageInfo {
@suppress("UNCHECKED_CAST")
override fun getElement() = super.getElement() as T?
public abstract fun processUsage(changeInfo: JetChangeInfo, element: T): Boolean
public abstract fun processUsage(changeInfo: JetChangeInfo, element: T, allUsages: Array<out UsageInfo>): Boolean
}
@@ -0,0 +1,77 @@
/*
* Copyright 2010-2015 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 com.intellij.usageView.UsageInfo
import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo
import org.jetbrains.kotlin.idea.refactoring.changeSignature.getAffectedCallables
import org.jetbrains.kotlin.idea.refactoring.changeSignature.isInsideOfCallerBody
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getValueParameterList
public class KotlinCallerUsage(element: JetNamedDeclaration): JetUsageInfo<JetNamedDeclaration>(element) {
override fun processUsage(changeInfo: JetChangeInfo, element: JetNamedDeclaration, allUsages: Array<out UsageInfo>): Boolean {
// Do not process function twice
if (changeInfo.getAffectedCallables().any { it is JetCallableDefinitionUsage<*> && it.getElement() == element }) return true
val parameterList = when (element) {
is JetFunction -> element.getValueParameterList()
is JetClass -> element.createPrimaryConstructorParameterListIfAbsent()
else -> null
} ?: return true
val psiFactory = JetPsiFactory(getProject())
changeInfo.getNonReceiverParameters()
.withIndex()
.filter { it.value.isNewParameter }
.forEach {
val parameterText = it.value.getDeclarationSignature(it.index, changeInfo.methodDescriptor.originalPrimaryCallable)
parameterList
.addParameter(psiFactory.createParameter(parameterText))
.addToShorteningWaitSet()
}
return true
}
}
public class KotlinCallerCallUsage(element: JetCallElement): JetUsageInfo<JetCallElement>(element) {
override fun processUsage(changeInfo: JetChangeInfo, element: JetCallElement, allUsages: Array<out UsageInfo>): Boolean {
val argumentList = element.getValueArgumentList() ?: return true
val psiFactory = JetPsiFactory(getProject())
val isNamedCall = argumentList.getArguments().any { it.getArgumentName() != null }
changeInfo.getNonReceiverParameters()
.filter { it.isNewParameter }
.forEach {
val parameterName = it.getName()
val argumentExpression = if (element.isInsideOfCallerBody(allUsages)) {
psiFactory.createExpression(parameterName)
}
else {
it.defaultValueForCall ?: psiFactory.createExpression("_")
}
val argument = psiFactory.createArgument(
expression = argumentExpression,
name = if (isNamedCall) Name.identifier(parameterName) else null
)
argumentList.addArgument(argument)
}
return true
}
}
@@ -100,7 +100,7 @@ public class KotlinIntroduceParameterMethodUsageProcessor : IntroduceParameterMe
.map { it.unwrapped }
.filterIsInstance<JetFunction>()
return (kotlinFunctions + element).all {
JetCallableDefinitionUsage(it, changeInfo.originalBaseFunctionDescriptor, null, null).processUsage(changeInfo, it)
JetCallableDefinitionUsage(it, changeInfo.originalBaseFunctionDescriptor, null, null).processUsage(changeInfo, it, usages)
}
}
@@ -116,7 +116,7 @@ public class KotlinIntroduceParameterMethodUsageProcessor : IntroduceParameterMe
else {
JetFunctionCallUsage(callElement, changeInfo.methodDescriptor.originalPrimaryCallable)
}
return delegateUsage.processUsage(changeInfo, callElement)
return delegateUsage.processUsage(changeInfo, callElement, usages)
}
override fun processAddSuperCall(data: IntroduceParameterData, usage: UsageInfo, usages: Array<out UsageInfo>): Boolean = true
@@ -0,0 +1,18 @@
open class C(n: Int) : A(n) {
}
open class D: A {
constructor(n: Int): super(n)
constructor(b: Boolean, n: Int) : super(n)
}
fun test(n: Int) {
A(n)
A(false, n)
B(n)
B(false, n)
C(n)
D(n)
D(false, n)
}
@@ -0,0 +1,32 @@
class A {
public <caret>A(int n) {
}
public A(boolean b, int n) {
this(n);
}
}
class B extends A {
public B(int n) {
super(n);
}
public B(boolean b, int n) {
super(n);
}
}
class Test {
void test(int n) {
new A(n);
new A(true, n);
new B(n);
new B(true, n);
new C(n);
new D(n);
new D(true, n);
}
}
@@ -0,0 +1,18 @@
open class C: A() {
}
open class D: A {
constructor(): super()
constructor(b: Boolean)
}
fun test() {
A()
A(false)
B()
B(false)
C()
D()
D(false)
}
@@ -0,0 +1,31 @@
class A {
public <caret>A() {
}
public A(boolean b) {
this();
}
}
class B extends A {
public B() {
}
public B(boolean b) {
super();
}
}
class Test {
void test() {
new A();
new A(true);
new B();
new B(true);
new C();
new D();
new D(true);
}
}
@@ -0,0 +1,28 @@
open class C: A() {
override fun foo(n: Int, s: String): Unit {
}
override fun bar(b: Boolean, n: Int, s: String) {
foo(n, s)
}
override fun baz() {
foo(1, "abc")
bar(false, 1, "abc")
}
}
fun test(n: Int, s: String) {
A().foo(n, s)
A().bar(true, n, s)
A().baz()
B().foo(n, s)
B().bar(true, n, s)
B().baz()
C().foo(n, s)
C().bar(true, n, s)
C().baz()
}
@@ -0,0 +1,45 @@
class A {
public void foo(int n, String s) {
}
public void bar(boolean b, int n, String s) {
foo(n, s);
}
public void baz() {
foo(1, "abc");
bar(false, 1, "abc");
}
}
class B extends A {
public void foo(int n, String s) {
}
public void bar(boolean b, int n, String s) {
foo(1, "abc");
}
public void baz() {
foo(1, "abc");
bar(false, 1, "abc");
}
}
class Test {
void test() {
new A().foo(1, "abc");
new A().bar(true, 1, "abc");
new A().baz();
new B().foo(1, "abc");
new B().bar(true, 1, "abc");
new B().baz();
new C().foo(1, "abc");
new C().bar(true, 1, "abc");
new C().baz();
}
}
@@ -0,0 +1,28 @@
open class C: A() {
override fun foo() {
}
override fun bar(b: Boolean) {
foo()
}
override fun baz() {
foo()
bar(false)
}
}
fun test() {
A().foo()
A().bar(true)
A().baz()
B().foo()
B().bar(true)
B().baz()
C().foo()
C().bar(true)
C().baz()
}
@@ -0,0 +1,45 @@
class A {
public void <caret>foo() {
}
public void bar(boolean b) {
foo();
}
public void baz() {
foo();
bar(false);
}
}
class B extends A {
public void foo() {
}
public void bar(boolean b) {
foo();
}
public void baz() {
foo();
bar(false);
}
}
class Test {
void test() {
new A().foo();
new A().bar(true);
new A().baz();
new B().foo();
new B().bar(true);
new B().baz();
new C().foo();
new C().bar(true);
new C().baz();
}
}
@@ -0,0 +1,35 @@
import org.jetbrains.annotations.NotNull;
class J extends A {
@Override
public void foo(int n, @NotNull String s) {
}
@Override
public void bar(boolean b, int n, String s) {
foo(1, "abc"); // Propagated parameters are not passed to calles in overriding methods
}
@Override
public void baz() {
foo(1, "abc");
bar(false, 1, "abc");
}
}
class Test {
void test() {
new A().foo(1, "abc");
new A().bar(true, 1, "abc");
new A().baz();
new B().foo(1, "abc");
new B().bar(true, 1, "abc");
new B().baz();
new J().foo(1, "abc");
new J().bar(true, 1, "abc");
new J().baz();
}
}
@@ -0,0 +1,43 @@
open class A {
open fun <caret>foo(n: Int, s: String) {
}
open fun bar(b: Boolean, n: Int, s: String) {
foo(n, s)
}
open fun baz() {
foo(1, "abc")
bar(false, 1, "abc")
}
}
class B : A() {
override fun foo(n: Int, s: String) {
}
override fun bar(b: Boolean, n: Int, s: String) {
foo(n, s)
}
override fun baz() {
foo(1, "abc")
bar(false, 1, "abc")
}
}
fun test(n: Int, s: String) {
A().foo(n, s)
A().bar(true, n, s)
A().baz()
B().foo(n, s)
B().bar(true, n, s)
B().baz()
J().foo(n, s)
J().bar(true, n, s)
J().baz()
}
@@ -0,0 +1,33 @@
class J extends A {
@Override
public void foo() {
}
@Override
public void bar(boolean b) {
foo(); // Propagated parameters are not passed to calles in overriding methods
}
@Override
public void baz() {
foo();
bar(false);
}
}
class Test {
void test() {
new A().foo();
new A().bar(true);
new A().baz();
new B().foo();
new B().bar(true);
new B().baz();
new J().foo();
new J().bar(true);
new J().baz();
}
}
@@ -0,0 +1,43 @@
open class A {
open fun <caret>foo() {
}
open fun bar(b: Boolean) {
foo()
}
open fun baz() {
foo()
bar(false)
}
}
class B : A() {
override fun foo() {
}
override fun bar(b: Boolean) {
foo()
}
override fun baz() {
foo()
bar(false)
}
}
fun test() {
A().foo()
A().bar(true)
A().baz()
B().foo()
B().bar(true)
B().baz()
J().foo()
J().bar(true)
J().baz()
}
@@ -0,0 +1,22 @@
class J extends A {
public J(int n) {
super(n);
}
public J(boolean b, int n) {
super(n);
}
}
class Test {
void test(int n) {
new A(n);
new A(true, n);
new B(n);
new B(true, n);
new C(true, n);
new J(n);
new J(true, n);
}
}
@@ -0,0 +1,21 @@
open class <caret>A(n: Int) {
constructor(b: Boolean, n: Int): this(n)
}
open class B: A {
constructor(n: Int) : super(n)
constructor(b: Boolean, n: Int): super(n)
}
open class C(b: Boolean, n: Int): A(n)
fun test(n: Int) {
A(n)
A(false, n)
B(n)
B(false, n)
C(false, n)
J(n)
J(false, n)
}
@@ -0,0 +1,21 @@
class J extends A {
public J() {
}
public J(boolean b) {
super();
}
}
class Test {
void test() {
new A();
new A(true);
new B();
new B(true);
new C(true);
new J();
new J(true);
}
}
@@ -0,0 +1,20 @@
open class <caret>A() {
constructor(b: Boolean): this()
}
open class B: A {
constructor()
constructor(b: Boolean): super()
}
open class C(b: Boolean): A()
fun test() {
A()
A(false)
B()
B(false)
C(false)
J()
J(false)
}
@@ -0,0 +1,5 @@
fun <caret>foo() = 1
fun bar(n: Int): Int {
return foo() + n
}
@@ -0,0 +1 @@
There is already a parameter 'n' in fun bar(n: Int): Int. It will conflict with the new parameter.
@@ -0,0 +1,7 @@
fun <caret>foo(n: Int): Int = 1
class A(val n: Int) {
fun bar(n: Int): Int {
return foo(n) + this.n
}
}
@@ -0,0 +1,7 @@
fun <caret>foo(): Int = 1
class A(val n: Int) {
fun bar(): Int {
return foo() + n
}
}
@@ -0,0 +1,7 @@
fun <caret>foo(n: Int): Int = 1
class A(val n: Int)
fun A.bar(n: Int): Int {
return foo(n) + this.n
}
@@ -0,0 +1,7 @@
fun <caret>foo(): Int = 1
class A(val n: Int)
fun A.bar(): Int {
return foo() + n
}
@@ -0,0 +1,7 @@
fun <caret>foo() = 1
val n = 1
fun bar(): Int {
return foo() + n
}
@@ -0,0 +1 @@
There is already a variable 'n' in fun bar(): Int. It will conflict with the new parameter.
@@ -0,0 +1,22 @@
class J extends A {
public J(int n) {
super(n);
}
public J(boolean b, int n) {
super(n);
}
}
class Test {
void test(int n) {
new A(n);
new A(true, n);
new B(n);
new B(true, n);
new C(true, n);
new J(n);
new J(true, n);
}
}
@@ -0,0 +1,21 @@
open class A {
<caret>constructor(n: Int)
constructor(b: Boolean, n: Int): this(n)
}
open class B: A {
constructor(n: Int) : super(n)
constructor(b: Boolean, n: Int): super(n)
}
open class C(b: Boolean, n: Int): A(n)
fun test(n: Int) {
A(n)
A(false, n)
B(n)
B(false, n)
C(false, n)
J(n)
}
@@ -0,0 +1,21 @@
class J extends A {
public J() {
}
public J(boolean b) {
super();
}
}
class Test {
void test() {
new A();
new A(true);
new B();
new B(true);
new C(true);
new J();
new J(true);
}
}
@@ -0,0 +1,20 @@
open class A {
<caret>constructor()
constructor(b: Boolean): this()
}
open class B: A {
constructor()
constructor(b: Boolean): super()
}
open class C(b: Boolean): A()
fun test() {
A()
A(false)
B()
B(false)
C(false)
J()
}
@@ -22,27 +22,32 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.java.stubs.index.JavaFullClassNameIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.refactoring.BaseRefactoringProcessor;
import com.intellij.refactoring.changeSignature.ChangeSignatureProcessor;
import com.intellij.refactoring.changeSignature.ParameterInfoImpl;
import com.intellij.refactoring.changeSignature.ThrownExceptionInfo;
import com.intellij.refactoring.util.CanonicalTypes;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.VisibilityUtil;
import kotlin.KotlinPackage;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.asJava.AsJavaPackage;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
import org.jetbrains.kotlin.descriptors.Visibilities;
import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage;
import org.jetbrains.kotlin.idea.refactoring.JetRefactoringBundle;
import org.jetbrains.kotlin.idea.refactoring.changeSignature.ui.KotlinMethodNode;
import org.jetbrains.kotlin.idea.stubindex.JetFullClassNameIndex;
import org.jetbrains.kotlin.idea.stubindex.JetTopLevelFunctionFqnNameIndex;
import org.jetbrains.kotlin.idea.test.DirectiveBasedActionUtils;
import org.jetbrains.kotlin.idea.test.KotlinCodeInsightTestCase;
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase;
import org.jetbrains.kotlin.psi.JetElement;
import org.jetbrains.kotlin.psi.JetFile;
import org.jetbrains.kotlin.psi.JetPsiFactory;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.dataClassUtils.DataClassUtilsPackage;
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode;
@@ -544,7 +549,7 @@ public class JetChangeSignatureTest extends KotlinCodeInsightTestCase {
public void testSAMChangeMethodReturnType() throws Exception {
doJavaTest(
new JavaRefactoringProvider() {
@Nullable
@NotNull
@Override
PsiType getNewReturnType(@NotNull PsiMethod method) {
return PsiType.getJavaLangObject(getPsiManager(), GlobalSearchScope.allScope(getProject()));
@@ -567,7 +572,7 @@ public class JetChangeSignatureTest extends KotlinCodeInsightTestCase {
return newParameters;
}
@Nullable
@NotNull
@Override
PsiType getNewReturnType(@NotNull PsiMethod method) {
return factory.createTypeFromText("X<java.util.List<A>>", method);
@@ -978,7 +983,7 @@ public class JetChangeSignatureTest extends KotlinCodeInsightTestCase {
public void testJavaMethodOverridesReplaceParam() throws Exception {
doJavaTest(
new JavaRefactoringProvider() {
@Nullable
@NotNull
@Override
PsiType getNewReturnType(@NotNull PsiMethod method) {
return PsiType.getJavaLangString(getPsiManager(), GlobalSearchScope.allScope(getProject()));
@@ -998,7 +1003,7 @@ public class JetChangeSignatureTest extends KotlinCodeInsightTestCase {
public void testJavaMethodOverridesChangeParam() throws Exception {
doJavaTest(
new JavaRefactoringProvider() {
@Nullable
@NotNull
@Override
PsiType getNewReturnType(@NotNull PsiMethod method) {
return PsiType.getJavaLangString(getPsiManager(), GlobalSearchScope.allScope(getProject()));
@@ -1084,6 +1089,233 @@ public class JetChangeSignatureTest extends KotlinCodeInsightTestCase {
doTest(changeInfo);
}
public void testParameterPropagation() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
JetParameterInfo newParameter1 = new JetParameterInfo(changeInfo.getMethodDescriptor().getBaseDescriptor(),
-1, "n", null, null,
new JetPsiFactory(getProject()).createExpression("1"), JetValVar.None, null);
newParameter1.setCurrentTypeText("kotlin.Int");
changeInfo.addParameter(newParameter1);
JetParameterInfo newParameter2 = new JetParameterInfo(changeInfo.getMethodDescriptor().getBaseDescriptor(),
-1, "s", null, null,
new JetPsiFactory(getProject()).createExpression("\"abc\""), JetValVar.None, null);
newParameter2.setCurrentTypeText("kotlin.String");
changeInfo.addParameter(newParameter2);
JetClassOrObject classA =
JetFullClassNameIndex.getInstance().get("A", getProject(), GlobalSearchScope.allScope(getProject()))
.iterator().next();
JetDeclaration functionBar = KotlinPackage.first(
classA.getDeclarations(),
new Function1<JetDeclaration, Boolean>() {
@Override
public Boolean invoke(JetDeclaration declaration) {
return declaration instanceof JetNamedFunction && "bar".equals(declaration.getName());
}
}
);
JetNamedFunction functionTest =
JetTopLevelFunctionFqnNameIndex.getInstance().get("test", getProject(), GlobalSearchScope.allScope(getProject()))
.iterator().next();
changeInfo.setPrimaryPropagationTargets(Arrays.asList(functionBar, functionTest));
doTest(changeInfo);
}
public void testJavaParameterPropagation() throws Exception {
doJavaTest(
new JavaRefactoringProvider() {
@NotNull
@Override
ParameterInfoImpl[] getNewParameters(@NotNull PsiMethod method) {
return new ParameterInfoImpl[] {
new ParameterInfoImpl(-1, "n", PsiType.INT, "1"),
new ParameterInfoImpl(-1,
"s",
PsiType.getJavaLangString(getPsiManager(), GlobalSearchScope.allScope(getProject())),
"\"abc\"")
};
}
@NotNull
@Override
Set<PsiMethod> getParameterPropagationTargets(@NotNull PsiMethod method) {
PsiClass classA = KotlinPackage.first(
JavaFullClassNameIndex.getInstance()
.get("A".hashCode(), getProject(), GlobalSearchScope.allScope(getProject())),
new Function1<PsiClass, Boolean>() {
@Override
public Boolean invoke(PsiClass aClass) {
return "A".equals(aClass.getName());
}
}
);
PsiMethod methodBar = KotlinPackage.first(
classA.getMethods(),
new Function1<PsiMethod, Boolean>() {
@Override
public Boolean invoke(PsiMethod method) {
return "bar".equals(method.getName());
}
}
);
JetNamedFunction functionTest =
JetTopLevelFunctionFqnNameIndex.getInstance().get("test", getProject(), GlobalSearchScope.allScope(getProject()))
.iterator().next();
return KotlinPackage.setOf(methodBar, AsJavaPackage.getRepresentativeLightMethod(functionTest));
}
}
);
}
public void testPropagateWithParameterDuplication() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
JetParameterInfo newParameter = new JetParameterInfo(changeInfo.getMethodDescriptor().getBaseDescriptor(),
-1, "n", KotlinBuiltIns.getInstance().getIntType(), null,
new JetPsiFactory(getProject()).createExpression("1"), JetValVar.None, null);
changeInfo.addParameter(newParameter);
JetNamedFunction functionBar =
JetTopLevelFunctionFqnNameIndex.getInstance().get("bar", getProject(), GlobalSearchScope.allScope(getProject()))
.iterator().next();
changeInfo.setPrimaryPropagationTargets(Collections.singletonList(functionBar));
doTestConflict(changeInfo);
}
public void testPropagateWithVariableDuplication() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
JetParameterInfo newParameter = new JetParameterInfo(changeInfo.getMethodDescriptor().getBaseDescriptor(),
-1, "n", KotlinBuiltIns.getInstance().getIntType(), null,
new JetPsiFactory(getProject()).createExpression("1"), JetValVar.None, null);
changeInfo.addParameter(newParameter);
JetNamedFunction functionBar =
JetTopLevelFunctionFqnNameIndex.getInstance().get("bar", getProject(), GlobalSearchScope.allScope(getProject()))
.iterator().next();
changeInfo.setPrimaryPropagationTargets(Collections.singletonList(functionBar));
doTestConflict(changeInfo);
}
public void testPropagateWithThisQualificationInClassMember() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
JetParameterInfo newParameter = new JetParameterInfo(changeInfo.getMethodDescriptor().getBaseDescriptor(),
-1, "n", KotlinBuiltIns.getInstance().getIntType(), null,
new JetPsiFactory(getProject()).createExpression("1"), JetValVar.None, null);
changeInfo.addParameter(newParameter);
JetClassOrObject classA =
JetFullClassNameIndex.getInstance().get("A", getProject(), GlobalSearchScope.allScope(getProject()))
.iterator().next();
JetDeclaration functionBar = KotlinPackage.first(
classA.getDeclarations(),
new Function1<JetDeclaration, Boolean>() {
@Override
public Boolean invoke(JetDeclaration declaration) {
return declaration instanceof JetNamedFunction && "bar".equals(declaration.getName());
}
}
);
changeInfo.setPrimaryPropagationTargets(Collections.singletonList(functionBar));
doTest(changeInfo);
}
public void testPropagateWithThisQualificationInExtension() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
JetParameterInfo newParameter = new JetParameterInfo(changeInfo.getMethodDescriptor().getBaseDescriptor(),
-1, "n", KotlinBuiltIns.getInstance().getIntType(), null,
new JetPsiFactory(getProject()).createExpression("1"), JetValVar.None, null);
changeInfo.addParameter(newParameter);
JetNamedFunction functionBar =
JetTopLevelFunctionFqnNameIndex.getInstance().get("bar", getProject(), GlobalSearchScope.allScope(getProject()))
.iterator().next();
changeInfo.setPrimaryPropagationTargets(Collections.singletonList(functionBar));
doTest(changeInfo);
}
public void testJavaConstructorParameterPropagation() throws Exception {
doJavaTest(
new JavaRefactoringProvider() {
@NotNull
@Override
ParameterInfoImpl[] getNewParameters(@NotNull PsiMethod method) {
return new ParameterInfoImpl[] { new ParameterInfoImpl(-1, "n", PsiType.INT, "1") };
}
@NotNull
@Override
Set<PsiMethod> getParameterPropagationTargets(@NotNull PsiMethod method) {
return findCallers(method);
}
}
);
}
public void testPrimaryConstructorParameterPropagation() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
JetParameterInfo newParameter = new JetParameterInfo(changeInfo.getMethodDescriptor().getBaseDescriptor(),
-1, "n", KotlinBuiltIns.getInstance().getIntType(), null,
new JetPsiFactory(getProject()).createExpression("1"), JetValVar.None, null);
changeInfo.addParameter(newParameter);
PsiMethod constructor = AsJavaPackage.getRepresentativeLightMethod(changeInfo.getMethod());
assert constructor != null;
changeInfo.setPrimaryPropagationTargets(findCallers(constructor));
doTest(changeInfo);
}
public void testSecondaryConstructorParameterPropagation() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
JetParameterInfo newParameter = new JetParameterInfo(changeInfo.getMethodDescriptor().getBaseDescriptor(),
-1, "n", KotlinBuiltIns.getInstance().getIntType(), null,
new JetPsiFactory(getProject()).createExpression("1"), JetValVar.None, null);
changeInfo.addParameter(newParameter);
PsiMethod constructor = AsJavaPackage.getRepresentativeLightMethod(changeInfo.getMethod());
assert constructor != null;
changeInfo.setPrimaryPropagationTargets(findCallers(constructor));
doTest(changeInfo);
}
@NotNull
private LinkedHashSet<PsiMethod> findCallers(@NotNull PsiMethod method) {
KotlinMethodNode rootNode =
new KotlinMethodNode(method,
new HashSet<PsiElement>(),
getProject(),
new Runnable() {
@Override
public void run() {
}
});
LinkedHashSet<PsiMethod> callers = new LinkedHashSet<PsiMethod>();
for (int i = 0; i < rootNode.getChildCount(); i++) {
PsiElement element = ((KotlinMethodNode) rootNode.getChildAt(i)).getMethod();
callers.addAll(AsJavaPackage.toLightMethods(element));
}
return callers;
}
@NotNull
@Override
protected String getTestDataPath() {
@@ -1142,9 +1374,10 @@ public class JetChangeSignatureTest extends KotlinCodeInsightTestCase {
return method.getName();
}
@Nullable
@NotNull
PsiType getNewReturnType(@NotNull PsiMethod method) {
return method.getReturnType();
PsiType type = method.getReturnType();
return type != null ? type : PsiType.VOID;
}
@NotNull
@@ -1158,6 +1391,11 @@ public class JetChangeSignatureTest extends KotlinCodeInsightTestCase {
return parameterInfos;
}
@NotNull
Set<PsiMethod> getParameterPropagationTargets(@NotNull PsiMethod method) {
return Collections.emptySet();
}
@NotNull
final ChangeSignatureProcessor getProcessor(@NotNull PsiMethod method) {
return new ChangeSignatureProcessor(
@@ -1166,9 +1404,11 @@ public class JetChangeSignatureTest extends KotlinCodeInsightTestCase {
false,
VisibilityUtil.getVisibilityModifier(method.getModifierList()),
getNewName(method),
getNewReturnType(method),
CanonicalTypes.createTypeWrapper(getNewReturnType(method)),
getNewParameters(method),
new ThrownExceptionInfo[0]);
new ThrownExceptionInfo[0],
getParameterPropagationTargets(method),
Collections.<PsiMethod>emptySet());
}
}