Create from Usage: Allow type parameters in the receiver position
#KT-7497 Fixed
This commit is contained in:
+5
-3
@@ -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)
|
||||
|
||||
|
||||
+2
-1
@@ -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
|
||||
}
|
||||
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// "Create extension function 'bar'" "true"
|
||||
fun <T> foo(t: T) {
|
||||
t.<caret>bar()
|
||||
}
|
||||
+8
@@ -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.
|
||||
}
|
||||
+7
@@ -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()
|
||||
}
|
||||
+7
@@ -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)
|
||||
}
|
||||
+9
@@ -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)
|
||||
}
|
||||
Vendored
+10
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user