diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt index 499a4ac6dbc..1628d3790cf 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt @@ -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 val receiverTypeCandidate: TypeCandidate? val mandatoryTypeParametersAsCandidates: List @@ -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) diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromUsageFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromUsageFix.kt index a281a714676..2d5654e9393 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromUsageFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromUsageFix.kt @@ -73,7 +73,7 @@ public abstract class CreateCallableFromUsageFixBase( 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( false isFunction && insertToJavaInterface && receiverInfo.staticContextRequired -> false + !isExtension && declaration is KtTypeParameter -> false else -> declaration != null } diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/extensionWithTypeParameterAsReceiver.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/extensionWithTypeParameterAsReceiver.kt new file mode 100644 index 00000000000..acc1ce69bc0 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/extensionWithTypeParameterAsReceiver.kt @@ -0,0 +1,4 @@ +// "Create extension function 'bar'" "true" +fun foo(t: T) { + t.bar() +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/extensionWithTypeParameterAsReceiver.kt.after b/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/extensionWithTypeParameterAsReceiver.kt.after new file mode 100644 index 00000000000..c32294b75f4 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/extensionWithTypeParameterAsReceiver.kt.after @@ -0,0 +1,8 @@ +// "Create extension function 'bar'" "true" +fun foo(t: T) { + t.bar() +} + +fun T.bar() { + 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/memberWithTypeParameterAsReceiver.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/memberWithTypeParameterAsReceiver.kt new file mode 100644 index 00000000000..4473bc70fe1 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments/memberWithTypeParameterAsReceiver.kt @@ -0,0 +1,7 @@ +// "Create member function 'bar'" "false" +// ACTION: Create extension function 'bar' +// ACTION: Rename reference +// ERROR: Unresolved reference: bar +fun foo(t: T) { + t.bar() +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/extensionWithTypeParameterAsReceiver.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/extensionWithTypeParameterAsReceiver.kt new file mode 100644 index 00000000000..aca0809f4de --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/extensionWithTypeParameterAsReceiver.kt @@ -0,0 +1,7 @@ +// "Create extension property 'bar'" "true" +// ERROR: Property must be initialized +fun consume(n: Int) {} + +fun foo(t: T) { + consume(t.bar) +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/extensionWithTypeParameterAsReceiver.kt.after b/idea/testData/quickfix/createFromUsage/createVariable/property/extensionWithTypeParameterAsReceiver.kt.after new file mode 100644 index 00000000000..ba44d547c1d --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/extensionWithTypeParameterAsReceiver.kt.after @@ -0,0 +1,9 @@ +// "Create extension property 'bar'" "true" +// ERROR: Property must be initialized +fun consume(n: Int) {} + +val T.bar: Int + +fun foo(t: T) { + consume(t.bar) +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/memberWithTypeParameterAsReceiver.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/memberWithTypeParameterAsReceiver.kt new file mode 100644 index 00000000000..4a712a1fcd2 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/memberWithTypeParameterAsReceiver.kt @@ -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 foo(t: T) { + consume(t.bar) +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index fff2effa529..0b1cb8c6707 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -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");