Create from Usage: Allow type parameters in the receiver position

#KT-7497 Fixed
This commit is contained in:
Alexey Sedunov
2015-12-08 14:50:06 +03:00
parent 76cf284b77
commit 44743aade5
9 changed files with 76 additions and 4 deletions
@@ -72,10 +72,12 @@ import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
import org.jetbrains.kotlin.resolve.scopes.utils.memberScopeAsImportingScope
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.types.typeUtil.makeNullable
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
import java.util.*
import kotlin.properties.Delegates
@@ -223,7 +225,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
val containingFileEditor: Editor
val containingElement: PsiElement
val dialogWithEditor: DialogWithEditor?
val receiverClassDescriptor: ClassDescriptor?
val receiverClassDescriptor: ClassifierDescriptor?
val typeParameterNameMap: Map<TypeParameterDescriptor, String>
val receiverTypeCandidate: TypeCandidate?
val mandatoryTypeParametersAsCandidates: List<TypeCandidate>
@@ -247,7 +249,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
}
is CallablePlacement.WithReceiver -> {
receiverClassDescriptor =
placement.receiverTypeCandidate.theType.getConstructor().getDeclarationDescriptor() as? ClassDescriptor
placement.receiverTypeCandidate.theType.getConstructor().getDeclarationDescriptor()
val classDeclaration = receiverClassDescriptor?.let { DescriptorToSourceUtils.getSourceFromDescriptor(it) }
containingElement = if (!config.isExtension && classDeclaration != null) classDeclaration else config.currentFile
}
@@ -350,7 +352,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
assert (receiverClassDescriptor is JavaClassDescriptor) { "Unexpected receiver class: $receiverClassDescriptor" }
val projections = receiverClassDescriptor.declaredTypeParameters
val projections = ((receiverClassDescriptor as JavaClassDescriptor).declaredTypeParameters)
.map { TypeProjectionImpl(it.getDefaultType()) }
val memberScope = receiverClassDescriptor.getMemberScope(projections)
@@ -73,7 +73,7 @@ public abstract class CreateCallableFromUsageFixBase<E : KtElement>(
private fun getDeclarationIfApplicable(project: Project, candidate: TypeCandidate): PsiElement? {
val descriptor = candidate.theType.constructor.declarationDescriptor ?: return null
val declaration = getDeclaration(descriptor, project) ?: return null
if (declaration !is KtClassOrObject && declaration !is PsiClass) return null
if (declaration !is KtClassOrObject && declaration !is KtTypeParameter && declaration !is PsiClass) return null
return if (isExtension || declaration.canRefactor()) declaration else null
}
@@ -125,6 +125,7 @@ public abstract class CreateCallableFromUsageFixBase<E : KtElement>(
false
isFunction && insertToJavaInterface && receiverInfo.staticContextRequired ->
false
!isExtension && declaration is KtTypeParameter -> false
else ->
declaration != null
}
@@ -0,0 +1,4 @@
// "Create extension function 'bar'" "true"
fun <T> foo(t: T) {
t.<caret>bar()
}
@@ -0,0 +1,8 @@
// "Create extension function 'bar'" "true"
fun <T> foo(t: T) {
t.bar()
}
fun <T> T.bar() {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
@@ -0,0 +1,7 @@
// "Create member function 'bar'" "false"
// ACTION: Create extension function 'bar'
// ACTION: Rename reference
// ERROR: Unresolved reference: bar
fun <T> foo(t: T) {
t.<caret>bar()
}
@@ -0,0 +1,7 @@
// "Create extension property 'bar'" "true"
// ERROR: Property must be initialized
fun consume(n: Int) {}
fun <T> foo(t: T) {
consume(t.<caret>bar)
}
@@ -0,0 +1,9 @@
// "Create extension property 'bar'" "true"
// ERROR: Property must be initialized
fun consume(n: Int) {}
val <T> T.bar: Int
fun <T> foo(t: T) {
consume(t.bar)
}
@@ -0,0 +1,10 @@
// "Create member property 'bar'" "false"
// ACTION: Create extension property 'bar'
// ACTION: Rename reference
// ACTION: Convert to expression body
// ERROR: Unresolved reference: bar
fun consume(n: Int) {}
fun <T> foo(t: T) {
consume(t.<caret>bar)
}
@@ -2119,6 +2119,18 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
doTest(fileName);
}
@TestMetadata("extensionWithTypeParameterAsReceiver.kt")
public void testExtensionWithTypeParameterAsReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/extensionWithTypeParameterAsReceiver.kt");
doTest(fileName);
}
@TestMetadata("memberWithTypeParameterAsReceiver.kt")
public void testMemberWithTypeParameterAsReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/memberWithTypeParameterAsReceiver.kt");
doTest(fileName);
}
@TestMetadata("noReceiver.kt")
public void testNoReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/noReceiver.kt");
@@ -3065,6 +3077,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
doTest(fileName);
}
@TestMetadata("extensionWithTypeParameterAsReceiver.kt")
public void testExtensionWithTypeParameterAsReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/property/extensionWithTypeParameterAsReceiver.kt");
doTest(fileName);
}
@TestMetadata("inBinaryOperation.kt")
public void testInBinaryOperation() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/property/inBinaryOperation.kt");
@@ -3113,6 +3131,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
doTest(fileName);
}
@TestMetadata("memberWithTypeParameterAsReceiver.kt")
public void testMemberWithTypeParameterAsReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/property/memberWithTypeParameterAsReceiver.kt");
doTest(fileName);
}
@TestMetadata("objectMemberValNoReceiver.kt")
public void testObjectMemberValNoReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/property/objectMemberValNoReceiver.kt");