diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt index 7392650f740..cf02cf49e61 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt @@ -330,17 +330,20 @@ class CallableBuilder(val config: CallableBuilderConfiguration) { CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE ) + val validator = CollectingValidator { scope.getClassifier(Name.identifier(it)) == null } + val parameterNames = JetNameSuggester.suggestNamesForTypeParameters(typeParameterCount, validator) val typeParameters = typeParameterCount.indices.map { TypeParameterDescriptorImpl.createWithDefaultBound( fakeFunction, Annotations.EMPTY, false, Variance.INVARIANT, - Name.identifier(validator.validateName("T")), + Name.identifier(parameterNames[it]), it ) } + return fakeFunction.initialize(null, null, typeParameters, Collections.emptyList(), null, null, Visibilities.INTERNAL) } diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/JetNameSuggester.java b/idea/src/org/jetbrains/jet/plugin/refactoring/JetNameSuggester.java index a7efdec3eaa..46221b4831b 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/JetNameSuggester.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/JetNameSuggester.java @@ -22,6 +22,7 @@ import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.name.Name; @@ -96,6 +97,16 @@ public class JetNameSuggester { return ArrayUtil.toStringArray(result); } + private static final String[] COMMON_TYPE_PARAMETER_NAMES = {"T", "U", "V", "W", "X", "Y", "Z"}; + + public static @NotNull String[] suggestNamesForTypeParameters(int count, @NotNull JetNameValidator validator) { + ArrayList result = new ArrayList(); + for (int i = 0; i < count; i++) { + result.add(validator.validateNameWithVariants(COMMON_TYPE_PARAMETER_NAMES)); + } + return ArrayUtil.toStringArray(result); + } + private static void addNamesForType(ArrayList result, JetType jetType, JetNameValidator validator) { KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance(); JetTypeChecker typeChecker = JetTypeChecker.DEFAULT; diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/JetNameValidator.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/JetNameValidator.kt index bb162b8e7be..b074e00e9e5 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/JetNameValidator.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/JetNameValidator.kt @@ -35,6 +35,23 @@ public abstract class JetNameValidator { return name + i } + /** + * Validates name using set of variants which are tried in succession (and extended with suffixes if necessary) + * For example, when given sequence of a, b, c possible names are tried out in the following order: a, b, c, a1, b1, c1, a2, b2, c2, ... + * @param names to check it in scope + * @return name or nameI, where name is one of variants and I is a number + */ + public fun validateNameWithVariants(vararg names: String): String { + var i = 0 + while (true) { + for (name in names) { + val candidate = if (i > 0) name + i else name + if (validateInner(candidate)) return candidate + } + i++ + } + } + protected abstract fun validateInner(name: String): Boolean } @@ -48,12 +65,12 @@ public open class CollectingValidator( ): JetNameValidator() { private val suggestedSet = HashSet(existingNames) - override fun validateInner(name: String): Boolean = name !in suggestedSet && filter(name) - - override fun validateName(name: String): String { - val validatedName = super.validateName(name) - suggestedSet.add(validatedName) - return validatedName + override fun validateInner(name: String): Boolean { + if (name !in suggestedSet && filter(name)) { + suggestedSet.add(name) + return true + } + return false } } diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterClassMember.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterClassMember.kt index cf935b5fc63..3cbcf13e7cd 100644 --- a/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterClassMember.kt +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterClassMember.kt @@ -1,7 +1,7 @@ // "Create function 'foo'" "true" class B(val t: T) { - fun foo(arg: T1, arg1: T2): T1 { + fun foo(arg: U, arg1: V): U { throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. } diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterClassMemberPartialSubstitution.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterClassMemberPartialSubstitution.kt index 7e74fdd8f30..bb4e54faa1c 100644 --- a/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterClassMemberPartialSubstitution.kt +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterClassMemberPartialSubstitution.kt @@ -1,7 +1,7 @@ // "Create function 'foo'" "true" class B(val t: T) { - fun foo(i: Int, arg: T1): Int { + fun foo(i: Int, arg: U): Int { throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. } diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterClassMemberWithReceiverArg.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterClassMemberWithReceiverArg.kt index cf935b5fc63..3cbcf13e7cd 100644 --- a/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterClassMemberWithReceiverArg.kt +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterClassMemberWithReceiverArg.kt @@ -1,7 +1,7 @@ // "Create function 'foo'" "true" class B(val t: T) { - fun foo(arg: T1, arg1: T2): T1 { + fun foo(arg: U, arg1: V): U { throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. } diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterExtension.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterExtension.kt index cb3baa2e558..4604c35b4cd 100644 --- a/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterExtension.kt +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterExtension.kt @@ -6,6 +6,6 @@ class A(val items: List) { } } -fun List.foo(arg: T, arg1: T1): T { +fun List.foo(arg: T, arg1: U): T { throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. } \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterExtensionWithReceiverArg.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterExtensionWithReceiverArg.kt index cb3baa2e558..4604c35b4cd 100644 --- a/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterExtensionWithReceiverArg.kt +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterExtensionWithReceiverArg.kt @@ -6,6 +6,6 @@ class A(val items: List) { } } -fun List.foo(arg: T, arg1: T1): T { +fun List.foo(arg: T, arg1: U): T { throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. } \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterNoReceiver.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterNoReceiver.kt index f9d5624a6cf..04deac22c69 100644 --- a/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterNoReceiver.kt +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterNoReceiver.kt @@ -4,6 +4,6 @@ fun test(): Int { return foo(2, "2") } -fun foo(arg: T1, arg1: T): T1 { +fun foo(arg: U, arg1: T): U { throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. } \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterNoReceiverExtraArgs.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterNoReceiverExtraArgs.kt index 27672f4be3e..1415f4e5562 100644 --- a/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterNoReceiverExtraArgs.kt +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterNoReceiverExtraArgs.kt @@ -4,6 +4,6 @@ fun test(): Int { return foo(2, "2") } -fun foo(arg: T1, arg1: T): T1 { +fun foo(arg: U, arg1: T): U { throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. } \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterNoReceiverLongName.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterNoReceiverLongName.kt index f9d5624a6cf..04deac22c69 100644 --- a/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterNoReceiverLongName.kt +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/afterNoReceiverLongName.kt @@ -4,6 +4,6 @@ fun test(): Int { return foo(2, "2") } -fun foo(arg: T1, arg1: T): T1 { +fun foo(arg: U, arg1: T): U { throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. } \ No newline at end of file