Name suggester: Improve name suggestion strategy for type parameters

This commit is contained in:
Alexey Sedunov
2014-10-31 15:03:08 +03:00
parent 7cb77314bc
commit f81c2d5ff7
11 changed files with 46 additions and 15 deletions
@@ -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)
}
@@ -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<String> result = new ArrayList<String>();
for (int i = 0; i < count; i++) {
result.add(validator.validateNameWithVariants(COMMON_TYPE_PARAMETER_NAMES));
}
return ArrayUtil.toStringArray(result);
}
private static void addNamesForType(ArrayList<String> result, JetType jetType, JetNameValidator validator) {
KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
JetTypeChecker typeChecker = JetTypeChecker.DEFAULT;
@@ -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
}
}
@@ -1,7 +1,7 @@
// "Create function 'foo'" "true"
class B<T>(val t: T) {
fun <T1, T2> foo(arg: T1, arg1: T2): T1 {
fun <U, V> foo(arg: U, arg1: V): U {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
@@ -1,7 +1,7 @@
// "Create function 'foo'" "true"
class B<T>(val t: T) {
fun <T1> foo(i: Int, arg: T1): Int {
fun <U> foo(i: Int, arg: U): Int {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
@@ -1,7 +1,7 @@
// "Create function 'foo'" "true"
class B<T>(val t: T) {
fun <T1, T2> foo(arg: T1, arg1: T2): T1 {
fun <U, V> foo(arg: U, arg1: V): U {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
@@ -6,6 +6,6 @@ class A<T>(val items: List<T>) {
}
}
fun <E, T, T1> List<E>.foo(arg: T, arg1: T1): T {
fun <E, T, U> List<E>.foo(arg: T, arg1: U): T {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
@@ -6,6 +6,6 @@ class A<T>(val items: List<T>) {
}
}
fun <E, T, T1> List<E>.foo(arg: T, arg1: T1): T {
fun <E, T, U> List<E>.foo(arg: T, arg1: U): T {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
@@ -4,6 +4,6 @@ fun test(): Int {
return foo<String, Int>(2, "2")
}
fun <T, T1> foo(arg: T1, arg1: T): T1 {
fun <T, U> foo(arg: U, arg1: T): U {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
@@ -4,6 +4,6 @@ fun test(): Int {
return foo<String, Int, Boolean>(2, "2")
}
fun <T, T1, T2> foo(arg: T1, arg1: T): T1 {
fun <T, U, V> foo(arg: U, arg1: T): U {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
@@ -4,6 +4,6 @@ fun test(): Int {
return foo<String, Int>(2, "2")
}
fun <T, T1> foo(arg: T1, arg1: T): T1 {
fun <T, U> foo(arg: U, arg1: T): U {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}