Change Signature: Match calls of different overloads generated due to @JvmOverloads annotation

#KT-9020 Fixed
This commit is contained in:
Alexey Sedunov
2015-10-27 21:25:09 +03:00
parent 6b346d9e77
commit 5e223927ea
65 changed files with 880 additions and 26 deletions
@@ -108,3 +108,8 @@ public fun <T> Collection<T>.toReadOnlyList(): List<T> =
public fun <T: Any> T?.singletonOrEmptyList(): List<T> =
if (this != null) listOf(this) else emptyList()
public fun <T> MutableList<T>.removeLast(condition: (T) -> Boolean): T? {
val index = indexOfLast(condition)
return if (index >= 0) removeAt(index) else null
}
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.idea.KotlinLanguage
@@ -44,11 +45,12 @@ import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.jvm.annotations.hasJvmOverloadsAnnotation
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
import java.util.ArrayList
import java.util.HashMap
import java.util.LinkedHashSet
import org.jetbrains.kotlin.utils.keysToMap
import org.jetbrains.kotlin.utils.removeLast
import java.util.*
public open class JetChangeInfo(
val methodDescriptor: JetMethodDescriptor,
@@ -60,7 +62,17 @@ public open class JetChangeInfo(
receiver: JetParameterInfo? = methodDescriptor.receiver,
val context: PsiElement,
primaryPropagationTargets: Collection<PsiElement> = emptyList()
): ChangeInfo {
) : ChangeInfo {
private class JvmOverloadSignature(
val method: PsiMethod,
val mandatoryParams: Set<KtParameter>,
val defaultValues: Set<KtExpression>
) {
fun constrainBy(other: JvmOverloadSignature): JvmOverloadSignature {
return JvmOverloadSignature(method, mandatoryParams.intersect(other.mandatoryParams), defaultValues.intersect(other.defaultValues))
}
}
var receiverParameterInfo: JetParameterInfo? = receiver
set(value: JetParameterInfo?) {
if (value != null && value !in newParameters) {
@@ -70,7 +82,10 @@ public open class JetChangeInfo(
}
private val newParameters = parameterInfos.toArrayList()
private val originalPsiMethods: List<PsiMethod> = getMethod().toLightMethods()
private val originalPsiMethods = method.toLightMethods()
private val originalParameters = (method as? KtFunction)?.valueParameters ?: emptyList()
private val originalSignatures = makeSignatures(originalParameters, originalPsiMethods, { it }, { it.defaultValue })
private val oldNameToParameterIndex: Map<String, Int> by lazy {
val map = HashMap<String, Int>()
@@ -90,6 +105,8 @@ public open class JetChangeInfo(
private var isPrimaryMethodUpdated: Boolean = false
private var javaChangeInfos: List<JavaChangeInfo>? = null
var originalToCurrentMethods: Map<PsiMethod, PsiMethod> = emptyMap()
private set
public fun getOldParameterIndex(oldParameterName: String): Int? = oldNameToParameterIndex[oldParameterName]
@@ -114,8 +131,14 @@ public open class JetChangeInfo(
newParameters.set(index, parameterInfo)
}
public fun addParameter(parameterInfo: JetParameterInfo) {
newParameters.add(parameterInfo)
@JvmOverloads
public fun addParameter(parameterInfo: JetParameterInfo, atIndex: Int = -1) {
if (atIndex >= 0) {
newParameters.add(atIndex, parameterInfo)
}
else {
newParameters.add(parameterInfo)
}
}
public fun removeParameter(index: Int) {
@@ -264,7 +287,56 @@ public open class JetChangeInfo(
javaChangeInfos = null
}
private fun <Parameter> makeSignatures(
parameters: List<Parameter>,
psiMethods: List<PsiMethod>,
getPsi: (Parameter) -> KtParameter,
getDefaultValue: (Parameter) -> KtExpression?
): List<JvmOverloadSignature> {
val defaultValueCount = parameters.count { getDefaultValue(it) != null }
if (psiMethods.size != defaultValueCount + 1) return emptyList()
val mandatoryParams = parameters.toArrayList()
val defaultValues = ArrayList<KtExpression>()
return psiMethods.map {
JvmOverloadSignature(it, mandatoryParams.map(getPsi).toSet(), defaultValues.toSet()).apply {
val param = mandatoryParams.removeLast { getDefaultValue(it) != null } ?: return@apply
defaultValues.add(getDefaultValue(param)!!)
}
}
}
public fun getOrCreateJavaChangeInfos(): List<JavaChangeInfo>? {
fun initCurrentSignatures(currentPsiMethods: List<PsiMethod>): List<JvmOverloadSignature> {
val parameterInfoToPsi = methodDescriptor.original.parameters.zip(originalParameters).toMap()
val dummyParameter = KtPsiFactory(method).createParameter("dummy")
return makeSignatures(newParameters,
currentPsiMethods,
{ parameterInfoToPsi[it] ?: dummyParameter },
{ it.defaultValueForParameter })
}
fun matchOriginalAndCurrentMethods(currentPsiMethods: List<PsiMethod>): Map<PsiMethod, PsiMethod> {
if (!(isPrimaryMethodUpdated
&& originalBaseFunctionDescriptor is FunctionDescriptor
&& originalBaseFunctionDescriptor.hasJvmOverloadsAnnotation())) {
return (originalPsiMethods zip currentPsiMethods).toMap()
}
if (originalPsiMethods.isEmpty() || currentPsiMethods.isEmpty()) return emptyMap()
currentPsiMethods.singleOrNull()?.let { method -> return originalPsiMethods.keysToMap { method } }
val currentSignatures = initCurrentSignatures(currentPsiMethods)
return originalSignatures.toMap({ it.method }) { originalSignature ->
var constrainedCurrentSignatures = currentSignatures.map { it.constrainBy(originalSignature) }
val maxMandatoryCount = constrainedCurrentSignatures.maxBy { it.mandatoryParams.size }!!.mandatoryParams.size
constrainedCurrentSignatures = constrainedCurrentSignatures.filter { it.mandatoryParams.size == maxMandatoryCount }
val maxDefaultCount = constrainedCurrentSignatures.maxBy { it.defaultValues.size }!!.defaultValues.size
constrainedCurrentSignatures.last { it.defaultValues.size == maxDefaultCount }.method
}
}
/*
* When primaryMethodUpdated is false, changes to the primary Kotlin declaration are already confirmed, but not yet applied.
* It means that originalPsiMethod has already expired, but new one can't be created until Kotlin declaration is updated
@@ -309,12 +381,27 @@ public open class JetChangeInfo(
currentPsiMethod: PsiMethod,
newParameterList: List<JetParameterInfo>
): MutableList<ParameterInfoImpl> {
val defaultValuesToSkip = newParameterList.size - currentPsiMethod.parameterList.parametersCount
val defaultValuesToRetain = newParameterList.count { it.defaultValueForParameter != null } - defaultValuesToSkip
val oldIndices = newParameterList.map { it.oldIndex }.toIntArray()
// TODO: Ugly code, need to refactor Change Signature data model
var defaultValuesRemained = defaultValuesToRetain
for (param in newParameterList) {
if (param.isNewParameter || param.defaultValueForParameter == null || defaultValuesRemained-- > 0) continue
newParameterList.withIndex().filter { it.value.oldIndex >= param.oldIndex }.forEach { oldIndices[it.index]-- }
}
defaultValuesRemained = defaultValuesToRetain
val oldParameterCount = originalPsiMethod.parameterList.parametersCount
var indexInCurrentPsiMethod = 0
return newParameterList.withIndex()
.map { pair ->
val (i, info) = pair
val oldIndex = info.oldIndex
if (info.defaultValueForParameter != null && defaultValuesRemained-- <= 0) return@map null
val oldIndex = oldIndices[i]
val javaOldIndex = when {
methodDescriptor.receiver == null -> oldIndex
info == methodDescriptor.receiver -> 0
@@ -324,11 +411,12 @@ public open class JetChangeInfo(
if (javaOldIndex >= oldParameterCount) return@map null
val type = if (isPrimaryMethodUpdated)
currentPsiMethod.getParameterList().getParameters()[i].getType()
currentPsiMethod.getParameterList().getParameters()[indexInCurrentPsiMethod++].getType()
else
PsiType.VOID
ParameterInfoImpl(javaOldIndex, info.getName(), type, info.defaultValueForCall?.getText() ?: "")
val defaultValue = info.defaultValueForCall ?: info.defaultValueForParameter
ParameterInfoImpl(javaOldIndex, info.getName(), type, defaultValue?.getText() ?: "")
}
.filterNotNullTo(ArrayList())
}
@@ -364,7 +452,8 @@ public open class JetChangeInfo(
if (javaChangeInfos == null) {
val method = getMethod()
javaChangeInfos = (originalPsiMethods zip method.toLightMethods()).map {
originalToCurrentMethods = matchOriginalAndCurrentMethods(method.toLightMethods())
javaChangeInfos = originalToCurrentMethods.entries.map {
val (originalPsiMethod, currentPsiMethod) = it
when (method) {
@@ -439,11 +528,11 @@ public fun ChangeInfo.toJetChangeInfo(originalChangeSignatureDescriptor: JetMeth
val returnTypeText = if (returnType != null) IdeDescriptorRenderers.SOURCE_CODE.renderType(returnType) else ""
return JetChangeInfo(originalChangeSignatureDescriptor,
getNewName(),
returnType,
returnTypeText,
functionDescriptor.getVisibility(),
newParameters,
null,
method)
getNewName(),
returnType,
returnTypeText,
functionDescriptor.getVisibility(),
newParameters,
null,
method)
}
@@ -800,14 +800,12 @@ class JetChangeSignatureUsageProcessor : ChangeSignatureUsageProcessor {
val javaChangeInfos = (changeInfo as JetChangeInfo).getOrCreateJavaChangeInfos()
assert(javaChangeInfos != null) { "JavaChangeInfo not found: " + method.text }
val javaUsageInfos = usageInfo.javaUsageInfos
val processors = ChangeSignatureUsageProcessor.EP_NAME.extensions
for (javaChangeInfo in javaChangeInfos!!) {
// Match names so that getter/setter usages are not confused with each other
if (javaChangeInfo.oldName != usageInfo.javaChangeInfo.oldName) continue
javaChangeInfos!!.firstOrNull {
changeInfo.originalToCurrentMethods[usageInfo.javaChangeInfo.method] == it.method
}?.let { javaChangeInfo ->
val nullabilityPropagator = NullabilityPropagator(javaChangeInfo.method)
val javaUsageInfos = usageInfo.javaUsageInfos
val processors = ChangeSignatureUsageProcessor.EP_NAME.extensions
for (usage in javaUsageInfos) {
if (isOverriderOrCaller(usage) && beforeMethodChange) continue
@@ -37,7 +37,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver
import org.jetbrains.kotlin.types.KotlinType
import java.util.*
public class JetParameterInfo(
public class JetParameterInfo @JvmOverloads constructor (
val callableDescriptor: CallableDescriptor,
val originalIndex: Int = -1,
private var name: String,
@@ -0,0 +1,17 @@
class Usages {
void foo() {
Foo.foo();
}
void fooX() {
Foo.foo(2, 1);
}
void fooXY() {
Foo.foo(2, 1, 1.0);
}
void fooXYZ() {
Foo.foo(2, 1, 1.0, "1");
}
}
@@ -0,0 +1,6 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(n: Int = 2, x: Int = 0, y: Double = 0.0, z: String = "0") {
}
@@ -0,0 +1,17 @@
class Usages {
void foo() {
Foo.foo();
}
void fooX() {
Foo.foo(1);
}
void fooXY() {
Foo.foo(1, 1.0);
}
void fooXYZ() {
Foo.foo(1, 1.0, "1");
}
}
@@ -0,0 +1,6 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(x: Int = 0, y: Double = 0.0, z: String = "0") {
}
@@ -0,0 +1,17 @@
class Usages {
void foo() {
Foo.foo();
}
void fooX() {
Foo.foo(1);
}
void fooXY() {
Foo.foo(1, 2, 1.0);
}
void fooXYZ() {
Foo.foo(1, 2, 1.0, "1");
}
}
@@ -0,0 +1,6 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(x: Int = 0, n: Int = 2, y: Double = 0.0, z: String = "0") {
}
@@ -0,0 +1,17 @@
class Usages {
void foo() {
Foo.foo();
}
void fooX() {
Foo.foo(1);
}
void fooXY() {
Foo.foo(1, 1.0);
}
void fooXYZ() {
Foo.foo(1, 1.0, "1");
}
}
@@ -0,0 +1,6 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(x: Int = 0, y: Double = 0.0, z: String = "0") {
}
@@ -0,0 +1,17 @@
class Usages {
void foo() {
Foo.foo();
}
void fooX() {
Foo.foo(1);
}
void fooXY() {
Foo.foo(1, 1.0);
}
void fooXYZ() {
Foo.foo(1, 1.0, "1");
}
}
@@ -0,0 +1,6 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(x: Int = 0, y: Double = 0.0, z: String = "0", n: Int = 2) {
}
@@ -0,0 +1,17 @@
class Usages {
void foo() {
Foo.foo();
}
void fooX() {
Foo.foo(1);
}
void fooXY() {
Foo.foo(1, 1.0);
}
void fooXYZ() {
Foo.foo(1, 1.0, "1");
}
}
@@ -0,0 +1,6 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(x: Int = 0, y: Double = 0.0, z: String = "0") {
}
@@ -0,0 +1,17 @@
class Usages {
void foo() {
Foo.foo(2);
}
void fooX() {
Foo.foo(2, 1);
}
void fooXY() {
Foo.foo(2, 1, 1.0);
}
void fooXYZ() {
Foo.foo(2, 1, 1.0, "1");
}
}
@@ -0,0 +1,6 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(n: Int, x: Int = 0, y: Double = 0.0, z: String = "0") {
}
@@ -0,0 +1,17 @@
class Usages {
void foo() {
Foo.foo();
}
void fooX() {
Foo.foo(1);
}
void fooXY() {
Foo.foo(1, 1.0);
}
void fooXYZ() {
Foo.foo(1, 1.0, "1");
}
}
@@ -0,0 +1,6 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(x: Int = 0, y: Double = 0.0, z: String = "0") {
}
@@ -0,0 +1,17 @@
class Usages {
void foo() {
Foo.foo(2);
}
void fooX() {
Foo.foo(1, 2);
}
void fooXY() {
Foo.foo(1, 2, 1.0);
}
void fooXYZ() {
Foo.foo(1, 2, 1.0, "1");
}
}
@@ -0,0 +1,6 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(x: Int = 0, n: Int, y: Double = 0.0, z: String = "0") {
}
@@ -0,0 +1,17 @@
class Usages {
void foo() {
Foo.foo();
}
void fooX() {
Foo.foo(1);
}
void fooXY() {
Foo.foo(1, 1.0);
}
void fooXYZ() {
Foo.foo(1, 1.0, "1");
}
}
@@ -0,0 +1,6 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(x: Int = 0, y: Double = 0.0, z: String = "0") {
}
@@ -0,0 +1,17 @@
class Usages {
void foo() {
Foo.foo(2);
}
void fooX() {
Foo.foo(1, 2);
}
void fooXY() {
Foo.foo(1, 1.0, 2);
}
void fooXYZ() {
Foo.foo(1, 1.0, "1", 2);
}
}
@@ -0,0 +1,6 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(x: Int = 0, y: Double = 0.0, z: String = "0", n: Int) {
}
@@ -0,0 +1,17 @@
class Usages {
void foo() {
Foo.foo();
}
void fooX() {
Foo.foo(1);
}
void fooXY() {
Foo.foo(1, 1.0);
}
void fooXYZ() {
Foo.foo(1, 1.0, "1");
}
}
@@ -0,0 +1,6 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(x: Int = 0, y: Double = 0.0, z: String = "0") {
}
@@ -0,0 +1,17 @@
class Usages {
void foo() {
new A();
}
void fooX() {
new A(1);
}
void fooXY() {
new A(1, "0", 1.0);
}
void fooXYZ() {
new A(1, "1", 1.0);
}
}
@@ -0,0 +1,5 @@
public class A @JvmOverloads constructor(
public val x: Int = 0,
public val z: String = "0",
public val y: Double = 0.0
)
@@ -0,0 +1,17 @@
class Usages {
void foo() {
new A();
}
void fooX() {
new A(1);
}
void fooXY() {
new A(1, 1.0);
}
void fooXYZ() {
new A(1, 1.0, "1");
}
}
@@ -0,0 +1,5 @@
public class A @JvmOverloads constructor<caret>(
public val x: Int = 0,
public val y: Double = 0.0,
public val z: String = "0"
)
@@ -0,0 +1,17 @@
class Usages {
void foo() {
Foo.foo();
}
void fooX() {
Foo.foo();
}
void fooXY() {
Foo.foo(1.0);
}
void fooXYZ() {
Foo.foo(1.0, "1");
}
}
@@ -0,0 +1,6 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(y: Double = 0.0, z: String = "0") {
}
@@ -0,0 +1,17 @@
class Usages {
void foo() {
Foo.foo();
}
void fooX() {
Foo.foo(1);
}
void fooXY() {
Foo.foo(1, 1.0);
}
void fooXYZ() {
Foo.foo(1, 1.0, "1");
}
}
@@ -0,0 +1,6 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(x: Int = 0, y: Double = 0.0, z: String = "0") {
}
@@ -0,0 +1,17 @@
class Usages {
void foo() {
Foo.foo();
}
void fooX() {
Foo.foo(1);
}
void fooXY() {
Foo.foo(1);
}
void fooXYZ() {
Foo.foo(1, "1");
}
}
@@ -0,0 +1,6 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(x: Int = 0, z: String = "0") {
}
@@ -0,0 +1,17 @@
class Usages {
void foo() {
Foo.foo();
}
void fooX() {
Foo.foo(1);
}
void fooXY() {
Foo.foo(1, 1.0);
}
void fooXYZ() {
Foo.foo(1, 1.0, "1");
}
}
@@ -0,0 +1,6 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(x: Int = 0, y: Double = 0.0, z: String = "0") {
}
@@ -0,0 +1,17 @@
class Usages {
void foo() {
Foo.foo();
}
void fooX() {
Foo.foo(1);
}
void fooXY() {
Foo.foo(1, 1.0);
}
void fooXYZ() {
Foo.foo(1, 1.0);
}
}
@@ -0,0 +1,6 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(x: Int = 0, y: Double = 0.0) {
}
@@ -0,0 +1,17 @@
class Usages {
void foo() {
Foo.foo();
}
void fooX() {
Foo.foo(1);
}
void fooXY() {
Foo.foo(1, 1.0);
}
void fooXYZ() {
Foo.foo(1, 1.0, "1");
}
}
@@ -0,0 +1,6 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(x: Int = 0, y: Double = 0.0, z: String = "0") {
}
@@ -0,0 +1,13 @@
class Usages {
void foo() {
Foo.foo();
}
void fooY() {
Foo.foo(1.0);
}
void fooYZ() {
Foo.foo(1.0, "1");
}
}
@@ -0,0 +1,6 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(y: Double = 0.0, z: String = "0") {
}
@@ -0,0 +1,13 @@
class Usages {
void foo() {
Foo.foo(1);
}
void fooY() {
Foo.foo(1, 1.0);
}
void fooYZ() {
Foo.foo(1, 1.0, "1");
}
}
@@ -0,0 +1,6 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(x: Int, y: Double = 0.0, z: String = "0") {
}
@@ -0,0 +1,13 @@
class Usages {
void foo() {
Foo.foo();
}
void fooX() {
Foo.foo(1);
}
void fooXZ() {
Foo.foo(1, "1");
}
}
@@ -0,0 +1,6 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(x: Int = 0, z: String = "0") {
}
@@ -0,0 +1,13 @@
class Usages {
void foo() {
Foo.foo(1.0);
}
void fooX() {
Foo.foo(1, 1.0);
}
void fooXZ() {
Foo.foo(1, 1.0, "1");
}
}
@@ -0,0 +1,6 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(x: Int = 0, y: Double, z: String = "0") {
}
@@ -0,0 +1,13 @@
class Usages {
void foo() {
Foo.foo();
}
void fooX() {
Foo.foo(1);
}
void fooXY() {
Foo.foo(1, 1.0);
}
}
@@ -0,0 +1,6 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(x: Int = 0, y: Double = 0.0) {
}
@@ -0,0 +1,13 @@
class Usages {
void foo() {
Foo.foo("1");
}
void fooX() {
Foo.foo(1, "1");
}
void fooXY() {
Foo.foo(1, 1.0, "1");
}
}
@@ -0,0 +1,6 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(x: Int = 0, y: Double = 0.0, z: String) {
}
@@ -0,0 +1,17 @@
class Usages {
void foo() {
Foo.foo();
}
void fooX() {
Foo.foo(1);
}
void fooXY() {
Foo.foo(1, "0", 1.0);
}
void fooXYZ() {
Foo.foo(1, "1", 1.0);
}
}
@@ -0,0 +1,10 @@
@file:JvmName("Foo")
@JvmOverloads
fun foo(
x: Int = 0,
z: String = "0",
y: Double = 0.0
) {
}
@@ -0,0 +1,17 @@
class Usages {
void foo() {
Foo.foo();
}
void fooX() {
Foo.foo(1);
}
void fooXY() {
Foo.foo(1, 1.0);
}
void fooXYZ() {
Foo.foo(1, 1.0, "1");
}
}
@@ -0,0 +1,10 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(
x: Int = 0,
y: Double = 0.0,
z: String = "0"
) {
}
@@ -0,0 +1,13 @@
class Usages {
void foo() {
Foo.foo(1);
}
void fooY() {
Foo.foo("0", 1.0, 1);
}
void fooYZ() {
Foo.foo("1", 1.0, 1);
}
}
@@ -0,0 +1,10 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(
z: String = "0",
y: Double = 0.0,
x: Int
) {
}
@@ -0,0 +1,13 @@
class Usages {
void foo() {
Foo.foo(1);
}
void fooY() {
Foo.foo(1, 1.0);
}
void fooYZ() {
Foo.foo(1, 1.0, "1");
}
}
@@ -0,0 +1,10 @@
@file:JvmName("Foo")
@JvmOverloads
fun <caret>foo(
x: Int,
y: Double = 0.0,
z: String = "0"
) {
}
@@ -1347,6 +1347,96 @@ public class JetChangeSignatureTest extends KotlinCodeInsightTestCase {
doTest(changeInfo);
}
public void testJvmOverloadedSwapParams1() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
JetParameterInfo param = changeInfo.getNewParameters()[1];
changeInfo.setNewParameter(1, changeInfo.getNewParameters()[2]);
changeInfo.setNewParameter(2, param);
doTest(changeInfo);
}
public void testJvmOverloadedSwapParams2() throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
JetParameterInfo param = changeInfo.getNewParameters()[0];
changeInfo.setNewParameter(0, changeInfo.getNewParameters()[2]);
changeInfo.setNewParameter(2, param);
doTest(changeInfo);
}
private void doTestJvmOverloadedAddDefault(int index) throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
KtExpression defaultValue = new KtPsiFactory(getProject()).createExpression("2");
CallableDescriptor descriptor = changeInfo.getMethodDescriptor().getBaseDescriptor();
changeInfo.addParameter(new JetParameterInfo(descriptor, -1, "n", BUILT_INS.getIntType(), defaultValue, defaultValue), index);
doTest(changeInfo);
}
private void doTestJvmOverloadedAddNonDefault(int index) throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
KtExpression defaultValue = new KtPsiFactory(getProject()).createExpression("2");
CallableDescriptor descriptor = changeInfo.getMethodDescriptor().getBaseDescriptor();
changeInfo.addParameter(new JetParameterInfo(descriptor, -1, "n", BUILT_INS.getIntType(), null, defaultValue), index);
doTest(changeInfo);
}
private void doTestRemoveAt(int index) throws Exception {
JetChangeInfo changeInfo = getChangeInfo();
changeInfo.removeParameter(index >= 0 ? index : changeInfo.getNewParametersCount() - 1);
doTest(changeInfo);
}
public void testJvmOverloadedAddDefault1() throws Exception {
doTestJvmOverloadedAddDefault(0);
}
public void testJvmOverloadedAddDefault2() throws Exception {
doTestJvmOverloadedAddDefault(1);
}
public void testJvmOverloadedAddDefault3() throws Exception {
doTestJvmOverloadedAddDefault(-1);
}
public void testJvmOverloadedAddNonDefault1() throws Exception {
doTestJvmOverloadedAddNonDefault(0);
}
public void testJvmOverloadedAddNonDefault2() throws Exception {
doTestJvmOverloadedAddNonDefault(1);
}
public void testJvmOverloadedAddNonDefault3() throws Exception {
doTestJvmOverloadedAddNonDefault(-1);
}
public void testJvmOverloadedRemoveDefault1() throws Exception {
doTestRemoveAt(0);
}
public void testJvmOverloadedRemoveDefault2() throws Exception {
doTestRemoveAt(1);
}
public void testJvmOverloadedRemoveDefault3() throws Exception {
doTestRemoveAt(-1);
}
public void testJvmOverloadedRemoveNonDefault1() throws Exception {
doTestRemoveAt(0);
}
public void testJvmOverloadedRemoveNonDefault2() throws Exception {
doTestRemoveAt(1);
}
public void testJvmOverloadedRemoveNonDefault3() throws Exception {
doTestRemoveAt(-1);
}
public void testJvmOverloadedConstructorSwapParams() throws Exception {
testJvmOverloadedSwapParams1();
}
private List<Editor> editors = null;
private static final String[] EXTENSIONS = {".kt", ".java"};