From 6560ecc82b64eee42f62a2a7e2f92671db1e7388 Mon Sep 17 00:00:00 2001 From: Roman Golyshev Date: Mon, 7 Oct 2019 12:18:32 +0300 Subject: [PATCH] KT-15286: Provide object member extensions in the completion - Add extensions only when completion of static members is enabled (double ctrl + space and nonempty prefix) - Add full import for callables with receiver in `LookupElement.decorateAsStaticMember` --- .../idea/completion/BasicCompletionSession.kt | 15 +++++- .../kotlin/idea/completion/CompletionUtils.kt | 11 +++- .../completion/StaticMembersCompletion.kt | 46 ++++++++++++++++ .../CompanionObjectExplicitReceiver.kt | 16 ++++++ .../CompanionObjectImplicitReceiver.kt | 16 ++++++ .../CorrectTypeExplicitReceiver.kt | 35 ++++++++++++ .../CorrectTypeImplicitReceiver.kt | 36 +++++++++++++ .../MultipleImplicitReceivers.kt | 24 +++++++++ .../ObjectExplicitReceiver.kt | 14 +++++ .../ObjectImplicitReceiver.kt | 14 +++++ .../OverridenExtensionsInObject.kt | 19 +++++++ ...mpanionObjectInSameFileExplicitReceiver.kt | 12 +++++ ...nObjectInSameFileExplicitReceiver.kt.after | 14 +++++ ...mpanionObjectInSameFileImplicitReceiver.kt | 12 +++++ ...nObjectInSameFileImplicitReceiver.kt.after | 14 +++++ ...mpanionObjectInSameFileExplicitReceiver.kt | 16 ++++++ ...nObjectInSameFileExplicitReceiver.kt.after | 18 +++++++ ...mpanionObjectInSameFileImplicitReceiver.kt | 16 ++++++ ...nObjectInSameFileImplicitReceiver.kt.after | 18 +++++++ .../NestedObjectInSameFileExplicitReceiver.kt | 14 +++++ ...dObjectInSameFileExplicitReceiver.kt.after | 16 ++++++ .../NestedObjectInSameFileImplicitReceiver.kt | 14 +++++ ...dObjectInSameFileImplicitReceiver.kt.after | 16 ++++++ .../ObjectInSameFileExplicitReceiver.kt | 12 +++++ .../ObjectInSameFileExplicitReceiver.kt.after | 14 +++++ .../ObjectInSameFileImplicitReceiver.kt | 12 +++++ .../ObjectInSameFileImplicitReceiver.kt.after | 14 +++++ .../test/JSBasicCompletionTestGenerated.java | 53 +++++++++++++++++++ .../test/JvmBasicCompletionTestGenerated.java | 53 +++++++++++++++++++ .../BasicCompletionHandlerTestGenerated.java | 53 +++++++++++++++++++ ...ceBasicCompletionHandlerTestGenerated.java | 53 +++++++++++++++++++ 31 files changed, 686 insertions(+), 4 deletions(-) create mode 100644 idea/idea-completion/testData/basic/common/extensionMethodInObject/CompanionObjectExplicitReceiver.kt create mode 100644 idea/idea-completion/testData/basic/common/extensionMethodInObject/CompanionObjectImplicitReceiver.kt create mode 100644 idea/idea-completion/testData/basic/common/extensionMethodInObject/CorrectTypeExplicitReceiver.kt create mode 100644 idea/idea-completion/testData/basic/common/extensionMethodInObject/CorrectTypeImplicitReceiver.kt create mode 100644 idea/idea-completion/testData/basic/common/extensionMethodInObject/MultipleImplicitReceivers.kt create mode 100644 idea/idea-completion/testData/basic/common/extensionMethodInObject/ObjectExplicitReceiver.kt create mode 100644 idea/idea-completion/testData/basic/common/extensionMethodInObject/ObjectImplicitReceiver.kt create mode 100644 idea/idea-completion/testData/basic/common/extensionMethodInObject/OverridenExtensionsInObject.kt create mode 100644 idea/idea-completion/testData/handlers/basic/extensionMethodInObject/CompanionObjectInSameFileExplicitReceiver.kt create mode 100644 idea/idea-completion/testData/handlers/basic/extensionMethodInObject/CompanionObjectInSameFileExplicitReceiver.kt.after create mode 100644 idea/idea-completion/testData/handlers/basic/extensionMethodInObject/CompanionObjectInSameFileImplicitReceiver.kt create mode 100644 idea/idea-completion/testData/handlers/basic/extensionMethodInObject/CompanionObjectInSameFileImplicitReceiver.kt.after create mode 100644 idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedCompanionObjectInSameFileExplicitReceiver.kt create mode 100644 idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedCompanionObjectInSameFileExplicitReceiver.kt.after create mode 100644 idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedCompanionObjectInSameFileImplicitReceiver.kt create mode 100644 idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedCompanionObjectInSameFileImplicitReceiver.kt.after create mode 100644 idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedObjectInSameFileExplicitReceiver.kt create mode 100644 idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedObjectInSameFileExplicitReceiver.kt.after create mode 100644 idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedObjectInSameFileImplicitReceiver.kt create mode 100644 idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedObjectInSameFileImplicitReceiver.kt.after create mode 100644 idea/idea-completion/testData/handlers/basic/extensionMethodInObject/ObjectInSameFileExplicitReceiver.kt create mode 100644 idea/idea-completion/testData/handlers/basic/extensionMethodInObject/ObjectInSameFileExplicitReceiver.kt.after create mode 100644 idea/idea-completion/testData/handlers/basic/extensionMethodInObject/ObjectInSameFileImplicitReceiver.kt create mode 100644 idea/idea-completion/testData/handlers/basic/extensionMethodInObject/ObjectInSameFileImplicitReceiver.kt.after diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt index b1009b9c19b..008c0acd218 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt @@ -339,8 +339,19 @@ class BasicCompletionSession( } } - if (configuration.staticMembers && callTypeAndReceiver is CallTypeAndReceiver.DEFAULT && prefix.isNotEmpty()) { - staticMembersCompletion.completeFromIndices(indicesHelper(false), collector) + if (configuration.staticMembers && prefix.isNotEmpty()) { + if (!receiverTypes.isNullOrEmpty()) { + staticMembersCompletion.completeObjectMemberExtensionsFromIndices( + indicesHelper(false), + receiverTypes.map { it.type }, + callTypeAndReceiver.callType, + collector + ) + } + + if (callTypeAndReceiver is CallTypeAndReceiver.DEFAULT) { + staticMembersCompletion.completeFromIndices(indicesHelper(false), collector) + } } } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt index b2248ae6745..24a4e1410c5 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt @@ -374,6 +374,7 @@ fun LookupElement.decorateAsStaticMember( val qualifierPresentation = classDescriptor.name.asString() return object : LookupElementDecorator(this) { + private val descriptorIsCallableExtension = (memberDescriptor as? CallableDescriptor)?.extensionReceiverParameter != null override fun getAllLookupStrings(): Set { return if (classNameAsLookupString) setOf(delegate.lookupString, qualifierPresentation) else super.getAllLookupStrings() } @@ -381,7 +382,9 @@ fun LookupElement.decorateAsStaticMember( override fun renderElement(presentation: LookupElementPresentation) { delegate.renderElement(presentation) - presentation.itemText = qualifierPresentation + "." + presentation.itemText + if (!descriptorIsCallableExtension) { + presentation.itemText = qualifierPresentation + "." + presentation.itemText + } val tailText = " (" + DescriptorUtils.getFqName(classDescriptor.containingDeclaration) + ")" if (memberDescriptor is FunctionDescriptor) { @@ -399,7 +402,11 @@ fun LookupElement.decorateAsStaticMember( val psiDocumentManager = PsiDocumentManager.getInstance(context.project) val file = context.file as KtFile - val addMemberImport = file.importDirectives.any { !it.isAllUnder && it.importPath?.fqName?.parent() == containerFqName } + fun importFromSameParentIsPresent() = file.importDirectives.any { + !it.isAllUnder && it.importPath?.fqName?.parent() == containerFqName + } + + val addMemberImport = descriptorIsCallableExtension || importFromSameParentIsPresent() if (addMemberImport) { psiDocumentManager.commitAllDocuments() diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/StaticMembersCompletion.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/StaticMembersCompletion.kt index 4e879cd24f7..42b86cd55e0 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/StaticMembersCompletion.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/StaticMembersCompletion.kt @@ -26,6 +26,8 @@ import org.jetbrains.kotlin.idea.codeInsight.collectSyntheticStaticMembersAndCon import org.jetbrains.kotlin.idea.core.KotlinIndicesHelper import org.jetbrains.kotlin.idea.core.targetDescriptors import org.jetbrains.kotlin.idea.resolve.ResolutionFacade +import org.jetbrains.kotlin.idea.util.CallType +import org.jetbrains.kotlin.idea.util.substituteExtensionIfCallable import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.KtFile @@ -35,6 +37,7 @@ import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered +import org.jetbrains.kotlin.types.KotlinType import java.util.* class StaticMembersCompletion( @@ -117,6 +120,19 @@ class StaticMembersCompletion( } } + private fun processObjectMemberExtensions(indicesHelper: KotlinIndicesHelper, processor: (CallableDescriptor) -> Unit) { + val descriptorKindFilter = DescriptorKindFilter.CALLABLES exclude DescriptorKindExclude.NonExtensions + val nameFilter: (String) -> Boolean = { prefixMatcher.prefixMatches(it) } + + val filter = { _: KtNamedDeclaration, _: KtObjectDeclaration -> true } + + indicesHelper.processObjectMembers(descriptorKindFilter, nameFilter, filter) { + if (it !in alreadyAdded && it is CallableDescriptor) { + processor(it) + } + } + } + private fun KtObjectDeclaration.isTopLevelOrCompanion(): Boolean { if (isCompanion()) { val owner = parent.parent as? KtClass ?: return false @@ -134,6 +150,36 @@ class StaticMembersCompletion( .forEach { collector.addElement(it) } } + /** + * Collects extensions declared as members in objects into [collector], for example: + * + * ``` + * object Obj { + * fun String.foo() {} + * } + * ``` + * + * `foo` here is object member extension. + */ + fun completeObjectMemberExtensionsFromIndices( + indicesHelper: KotlinIndicesHelper, + receiverTypes: Collection, + callType: CallType<*>, + collector: LookupElementsCollector + ) { + val factory = decoratedLookupElementFactory(ItemPriority.STATIC_MEMBER) + processObjectMemberExtensions(indicesHelper) { objectMemberDescriptor -> + val substitutedExtensions = objectMemberDescriptor.substituteExtensionIfCallable(receiverTypes, callType) + + for (substituted in substitutedExtensions) { + val lookups = factory.createStandardLookupElementsForDescriptor(substituted, useReceiverTypes = true) + lookups.forEach { collector.addElement(it) } + } + + collector.flushToResultSet() + } + } + fun completeFromIndices(indicesHelper: KotlinIndicesHelper, collector: LookupElementsCollector) { val factory = decoratedLookupElementFactory(ItemPriority.STATIC_MEMBER) processMembersFromIndices(indicesHelper) { diff --git a/idea/idea-completion/testData/basic/common/extensionMethodInObject/CompanionObjectExplicitReceiver.kt b/idea/idea-completion/testData/basic/common/extensionMethodInObject/CompanionObjectExplicitReceiver.kt new file mode 100644 index 00000000000..110f3ce6154 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/extensionMethodInObject/CompanionObjectExplicitReceiver.kt @@ -0,0 +1,16 @@ +class T + +class A { + companion object { + fun T.fooExtension() {} + val T.fooProperty get() = 10 + } +} + +fun usage(t: T) { + t.foo +} + +// INVOCATION_COUNT: 2 +// EXIST: { lookupString: "fooExtension", itemText: "fooExtension" } +// EXIST: { lookupString: "fooProperty", itemText: "fooProperty" } \ No newline at end of file diff --git a/idea/idea-completion/testData/basic/common/extensionMethodInObject/CompanionObjectImplicitReceiver.kt b/idea/idea-completion/testData/basic/common/extensionMethodInObject/CompanionObjectImplicitReceiver.kt new file mode 100644 index 00000000000..b55c3e1af14 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/extensionMethodInObject/CompanionObjectImplicitReceiver.kt @@ -0,0 +1,16 @@ +class T + +class A { + companion object { + fun T.fooExtension() {} + val T.fooProperty get() = 10 + } +} + +fun T.usage() { + foo +} + +// INVOCATION_COUNT: 2 +// EXIST: { lookupString: "fooExtension", itemText: "fooExtension" } +// EXIST: { lookupString: "fooProperty", itemText: "fooProperty" } \ No newline at end of file diff --git a/idea/idea-completion/testData/basic/common/extensionMethodInObject/CorrectTypeExplicitReceiver.kt b/idea/idea-completion/testData/basic/common/extensionMethodInObject/CorrectTypeExplicitReceiver.kt new file mode 100644 index 00000000000..71e208bbd4a --- /dev/null +++ b/idea/idea-completion/testData/basic/common/extensionMethodInObject/CorrectTypeExplicitReceiver.kt @@ -0,0 +1,35 @@ +interface T +interface B: T +interface C: T + +object A { + fun Any.fooForAny() {} + + fun T.fooForT() {} + fun B.fooForB() {} + fun C.fooForC() {} + + fun TT.fooForAnyGeneric() {} + fun TT.fooForTGeneric() {} + fun TT.fooForBGeneric() {} + fun TT.fooForCGeneric() {} + + fun fooNoReceiver() {} +} + +fun usage(b: B) { + b.foo +} + +// INVOCATION_COUNT: 2 +// EXIST: { lookupString: "fooForAny", itemText: "fooForAny" } + +// EXIST: { lookupString: "fooForT", itemText: "fooForT" } +// EXIST: { lookupString: "fooForB", itemText: "fooForB" } + +// EXIST: { lookupString: "fooForTGeneric", itemText: "fooForTGeneric" } +// EXIST: { lookupString: "fooForBGeneric", itemText: "fooForBGeneric" } + +// ABSENT: fooForC +// ABSENT: fooForCGeneric +// ABSENT: fooNoReceiver \ No newline at end of file diff --git a/idea/idea-completion/testData/basic/common/extensionMethodInObject/CorrectTypeImplicitReceiver.kt b/idea/idea-completion/testData/basic/common/extensionMethodInObject/CorrectTypeImplicitReceiver.kt new file mode 100644 index 00000000000..0fd3a245c21 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/extensionMethodInObject/CorrectTypeImplicitReceiver.kt @@ -0,0 +1,36 @@ +interface T +interface B: T +interface C: T + +object A { + fun Any.fooForAny() {} + + fun T.fooForT() {} + fun B.fooForB() {} + fun C.fooForC() {} + + fun TT.fooForAnyGeneric() {} + fun TT.fooForTGeneric() {} + fun TT.fooForBGeneric() {} + fun TT.fooForCGeneric() {} + + fun fooNoReceiver() {} +} + +fun B.usage() { + foo +} + +// INVOCATION_COUNT: 2 +// EXIST: { lookupString: "fooForAny", itemText: "fooForAny" } + +// EXIST: { lookupString: "fooForT", itemText: "fooForT" } +// EXIST: { lookupString: "fooForB", itemText: "fooForB" } + +// EXIST: { lookupString: "fooForTGeneric", itemText: "fooForTGeneric" } +// EXIST: { lookupString: "fooForBGeneric", itemText: "fooForBGeneric" } + +// EXIST: fooNoReceiver + +// ABSENT: fooForC +// ABSENT: fooForCGeneric diff --git a/idea/idea-completion/testData/basic/common/extensionMethodInObject/MultipleImplicitReceivers.kt b/idea/idea-completion/testData/basic/common/extensionMethodInObject/MultipleImplicitReceivers.kt new file mode 100644 index 00000000000..449126e87ea --- /dev/null +++ b/idea/idea-completion/testData/basic/common/extensionMethodInObject/MultipleImplicitReceivers.kt @@ -0,0 +1,24 @@ +class T + +object O { + fun A.fooForA() {} + fun A.B.fooForB() {} + fun A.B.C.fooForC() {} + fun T.fooForT() {} +} + +class A { + inner class B { + fun T.usage() { + foo + } + + inner class C {} + } +} + +// INVOCATION_COUNT: 2 +// EXIST: { lookupString: "fooForA", itemText: "fooForA" } +// EXIST: { lookupString: "fooForB", itemText: "fooForB" } +// EXIST: { lookupString: "fooForT", itemText: "fooForT" } +// ABSENT: fooForC \ No newline at end of file diff --git a/idea/idea-completion/testData/basic/common/extensionMethodInObject/ObjectExplicitReceiver.kt b/idea/idea-completion/testData/basic/common/extensionMethodInObject/ObjectExplicitReceiver.kt new file mode 100644 index 00000000000..dfd7e69956d --- /dev/null +++ b/idea/idea-completion/testData/basic/common/extensionMethodInObject/ObjectExplicitReceiver.kt @@ -0,0 +1,14 @@ +class T + +object A { + fun T.fooExtension() {} + val T.fooProperty get() = 10 +} + +fun usage(t: T) { + t.foo +} + +// INVOCATION_COUNT: 2 +// EXIST: { lookupString: "fooExtension", itemText: "fooExtension" } +// EXIST: { lookupString: "fooProperty", itemText: "fooProperty" } \ No newline at end of file diff --git a/idea/idea-completion/testData/basic/common/extensionMethodInObject/ObjectImplicitReceiver.kt b/idea/idea-completion/testData/basic/common/extensionMethodInObject/ObjectImplicitReceiver.kt new file mode 100644 index 00000000000..924b98e4eef --- /dev/null +++ b/idea/idea-completion/testData/basic/common/extensionMethodInObject/ObjectImplicitReceiver.kt @@ -0,0 +1,14 @@ +class T + +object A { + fun T.fooExtension() {} + val T.fooProperty get() = 10 +} + +fun T.usage() { + foo +} + +// INVOCATION_COUNT: 2 +// EXIST: { lookupString: "fooExtension", itemText: "fooExtension" } +// EXIST: { lookupString: "fooProperty", itemText: "fooProperty" } \ No newline at end of file diff --git a/idea/idea-completion/testData/basic/common/extensionMethodInObject/OverridenExtensionsInObject.kt b/idea/idea-completion/testData/basic/common/extensionMethodInObject/OverridenExtensionsInObject.kt new file mode 100644 index 00000000000..030474f0218 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/extensionMethodInObject/OverridenExtensionsInObject.kt @@ -0,0 +1,19 @@ +class T + +interface Foo { + fun T.fooExtension() + val T.fooProperty: Int +} + +object A : Foo { + override fun T.fooExtension() {} + override val T.fooProperty get() = 10 +} + +fun T.usage() { + foo +} + +// INVOCATION_COUNT: 2 +// EXIST: { lookupString: "fooExtension", itemText: "fooExtension" } +// EXIST: { lookupString: "fooProperty", itemText: "fooProperty" } \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/CompanionObjectInSameFileExplicitReceiver.kt b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/CompanionObjectInSameFileExplicitReceiver.kt new file mode 100644 index 00000000000..e54a31c5b57 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/CompanionObjectInSameFileExplicitReceiver.kt @@ -0,0 +1,12 @@ +class T { + companion object { + fun T.foo() {} + } +} + +fun usage(t: T) { + t.f +} + +// INVOCATION_COUNT: 2 +// ELEMENT: foo \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/CompanionObjectInSameFileExplicitReceiver.kt.after b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/CompanionObjectInSameFileExplicitReceiver.kt.after new file mode 100644 index 00000000000..d87c8a10ef7 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/CompanionObjectInSameFileExplicitReceiver.kt.after @@ -0,0 +1,14 @@ +import T.Companion.foo + +class T { + companion object { + fun T.foo() {} + } +} + +fun usage(t: T) { + t.foo() +} + +// INVOCATION_COUNT: 2 +// ELEMENT: foo \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/CompanionObjectInSameFileImplicitReceiver.kt b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/CompanionObjectInSameFileImplicitReceiver.kt new file mode 100644 index 00000000000..ecbfb6441dc --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/CompanionObjectInSameFileImplicitReceiver.kt @@ -0,0 +1,12 @@ +class T { + companion object { + fun T.foo() {} + } +} + +fun T.usage() { + f +} + +// INVOCATION_COUNT: 2 +// ELEMENT: foo \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/CompanionObjectInSameFileImplicitReceiver.kt.after b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/CompanionObjectInSameFileImplicitReceiver.kt.after new file mode 100644 index 00000000000..f7fb703fcc0 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/CompanionObjectInSameFileImplicitReceiver.kt.after @@ -0,0 +1,14 @@ +import T.Companion.foo + +class T { + companion object { + fun T.foo() {} + } +} + +fun T.usage() { + foo() +} + +// INVOCATION_COUNT: 2 +// ELEMENT: foo \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedCompanionObjectInSameFileExplicitReceiver.kt b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedCompanionObjectInSameFileExplicitReceiver.kt new file mode 100644 index 00000000000..d8be5941fd8 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedCompanionObjectInSameFileExplicitReceiver.kt @@ -0,0 +1,16 @@ +class T + +class A { + class B { + companion object { + fun T.foo() {} + } + } +} + +fun usage(t: T) { + t.f +} + +// INVOCATION_COUNT: 2 +// ELEMENT: foo \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedCompanionObjectInSameFileExplicitReceiver.kt.after b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedCompanionObjectInSameFileExplicitReceiver.kt.after new file mode 100644 index 00000000000..1a470ad4d0f --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedCompanionObjectInSameFileExplicitReceiver.kt.after @@ -0,0 +1,18 @@ +import A.B.Companion.foo + +class T + +class A { + class B { + companion object { + fun T.foo() {} + } + } +} + +fun usage(t: T) { + t.foo() +} + +// INVOCATION_COUNT: 2 +// ELEMENT: foo \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedCompanionObjectInSameFileImplicitReceiver.kt b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedCompanionObjectInSameFileImplicitReceiver.kt new file mode 100644 index 00000000000..ef0b2943ef4 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedCompanionObjectInSameFileImplicitReceiver.kt @@ -0,0 +1,16 @@ +class T + +class A { + class B { + companion object { + fun T.foo() {} + } + } +} + +fun T.usage() { + f +} + +// INVOCATION_COUNT: 2 +// ELEMENT: foo \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedCompanionObjectInSameFileImplicitReceiver.kt.after b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedCompanionObjectInSameFileImplicitReceiver.kt.after new file mode 100644 index 00000000000..d214931bafb --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedCompanionObjectInSameFileImplicitReceiver.kt.after @@ -0,0 +1,18 @@ +import A.B.Companion.foo + +class T + +class A { + class B { + companion object { + fun T.foo() {} + } + } +} + +fun T.usage() { + foo() +} + +// INVOCATION_COUNT: 2 +// ELEMENT: foo \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedObjectInSameFileExplicitReceiver.kt b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedObjectInSameFileExplicitReceiver.kt new file mode 100644 index 00000000000..eb3d7d8322c --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedObjectInSameFileExplicitReceiver.kt @@ -0,0 +1,14 @@ +class T + +object TopLevel { + object Nested { + fun T.foo() {} + } +} + +fun usage(t: T) { + t.f +} + +// INVOCATION_COUNT: 2 +// ELEMENT: foo \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedObjectInSameFileExplicitReceiver.kt.after b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedObjectInSameFileExplicitReceiver.kt.after new file mode 100644 index 00000000000..4e6c0974cd8 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedObjectInSameFileExplicitReceiver.kt.after @@ -0,0 +1,16 @@ +import TopLevel.Nested.foo + +class T + +object TopLevel { + object Nested { + fun T.foo() {} + } +} + +fun usage(t: T) { + t.foo() +} + +// INVOCATION_COUNT: 2 +// ELEMENT: foo \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedObjectInSameFileImplicitReceiver.kt b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedObjectInSameFileImplicitReceiver.kt new file mode 100644 index 00000000000..40d8300858c --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedObjectInSameFileImplicitReceiver.kt @@ -0,0 +1,14 @@ +class T + +object TopLevel { + object Nested { + fun T.foo() {} + } +} + +fun T.usage() { + f +} + +// INVOCATION_COUNT: 2 +// ELEMENT: foo \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedObjectInSameFileImplicitReceiver.kt.after b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedObjectInSameFileImplicitReceiver.kt.after new file mode 100644 index 00000000000..14774614156 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedObjectInSameFileImplicitReceiver.kt.after @@ -0,0 +1,16 @@ +import TopLevel.Nested.foo + +class T + +object TopLevel { + object Nested { + fun T.foo() {} + } +} + +fun T.usage() { + foo() +} + +// INVOCATION_COUNT: 2 +// ELEMENT: foo \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/ObjectInSameFileExplicitReceiver.kt b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/ObjectInSameFileExplicitReceiver.kt new file mode 100644 index 00000000000..c390fea75fa --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/ObjectInSameFileExplicitReceiver.kt @@ -0,0 +1,12 @@ +class T + +object Extensions { + fun T.foo() {} +} + +fun usage(t: T) { + t.f +} + +// INVOCATION_COUNT: 2 +// ELEMENT: foo \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/ObjectInSameFileExplicitReceiver.kt.after b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/ObjectInSameFileExplicitReceiver.kt.after new file mode 100644 index 00000000000..4dba2fd9dad --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/ObjectInSameFileExplicitReceiver.kt.after @@ -0,0 +1,14 @@ +import Extensions.foo + +class T + +object Extensions { + fun T.foo() {} +} + +fun usage(t: T) { + t.foo() +} + +// INVOCATION_COUNT: 2 +// ELEMENT: foo \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/ObjectInSameFileImplicitReceiver.kt b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/ObjectInSameFileImplicitReceiver.kt new file mode 100644 index 00000000000..c4703379bea --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/ObjectInSameFileImplicitReceiver.kt @@ -0,0 +1,12 @@ +class T + +object Extensions { + fun T.foo() {} +} + +fun T.usage() { + f +} + +// INVOCATION_COUNT: 2 +// ELEMENT: foo \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/ObjectInSameFileImplicitReceiver.kt.after b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/ObjectInSameFileImplicitReceiver.kt.after new file mode 100644 index 00000000000..effc70b942b --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/extensionMethodInObject/ObjectInSameFileImplicitReceiver.kt.after @@ -0,0 +1,14 @@ +import Extensions.foo + +class T + +object Extensions { + fun T.foo() {} +} + +fun T.usage() { + foo() +} + +// INVOCATION_COUNT: 2 +// ELEMENT: foo \ No newline at end of file diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java index 10cf29f7f6c..6c1d0b0d17d 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java @@ -1229,6 +1229,59 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes } } + @TestMetadata("idea/idea-completion/testData/basic/common/extensionMethodInObject") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ExtensionMethodInObject extends AbstractJSBasicCompletionTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInExtensionMethodInObject() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/basic/common/extensionMethodInObject"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("CompanionObjectExplicitReceiver.kt") + public void testCompanionObjectExplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/basic/common/extensionMethodInObject/CompanionObjectExplicitReceiver.kt"); + } + + @TestMetadata("CompanionObjectImplicitReceiver.kt") + public void testCompanionObjectImplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/basic/common/extensionMethodInObject/CompanionObjectImplicitReceiver.kt"); + } + + @TestMetadata("CorrectTypeExplicitReceiver.kt") + public void testCorrectTypeExplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/basic/common/extensionMethodInObject/CorrectTypeExplicitReceiver.kt"); + } + + @TestMetadata("CorrectTypeImplicitReceiver.kt") + public void testCorrectTypeImplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/basic/common/extensionMethodInObject/CorrectTypeImplicitReceiver.kt"); + } + + @TestMetadata("MultipleImplicitReceivers.kt") + public void testMultipleImplicitReceivers() throws Exception { + runTest("idea/idea-completion/testData/basic/common/extensionMethodInObject/MultipleImplicitReceivers.kt"); + } + + @TestMetadata("ObjectExplicitReceiver.kt") + public void testObjectExplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/basic/common/extensionMethodInObject/ObjectExplicitReceiver.kt"); + } + + @TestMetadata("ObjectImplicitReceiver.kt") + public void testObjectImplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/basic/common/extensionMethodInObject/ObjectImplicitReceiver.kt"); + } + + @TestMetadata("OverridenExtensionsInObject.kt") + public void testOverridenExtensionsInObject() throws Exception { + runTest("idea/idea-completion/testData/basic/common/extensionMethodInObject/OverridenExtensionsInObject.kt"); + } + } + @TestMetadata("idea/idea-completion/testData/basic/common/extensions") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java index b36c860fe29..554b5fa7bc1 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java @@ -1229,6 +1229,59 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT } } + @TestMetadata("idea/idea-completion/testData/basic/common/extensionMethodInObject") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ExtensionMethodInObject extends AbstractJvmBasicCompletionTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInExtensionMethodInObject() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/basic/common/extensionMethodInObject"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("CompanionObjectExplicitReceiver.kt") + public void testCompanionObjectExplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/basic/common/extensionMethodInObject/CompanionObjectExplicitReceiver.kt"); + } + + @TestMetadata("CompanionObjectImplicitReceiver.kt") + public void testCompanionObjectImplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/basic/common/extensionMethodInObject/CompanionObjectImplicitReceiver.kt"); + } + + @TestMetadata("CorrectTypeExplicitReceiver.kt") + public void testCorrectTypeExplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/basic/common/extensionMethodInObject/CorrectTypeExplicitReceiver.kt"); + } + + @TestMetadata("CorrectTypeImplicitReceiver.kt") + public void testCorrectTypeImplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/basic/common/extensionMethodInObject/CorrectTypeImplicitReceiver.kt"); + } + + @TestMetadata("MultipleImplicitReceivers.kt") + public void testMultipleImplicitReceivers() throws Exception { + runTest("idea/idea-completion/testData/basic/common/extensionMethodInObject/MultipleImplicitReceivers.kt"); + } + + @TestMetadata("ObjectExplicitReceiver.kt") + public void testObjectExplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/basic/common/extensionMethodInObject/ObjectExplicitReceiver.kt"); + } + + @TestMetadata("ObjectImplicitReceiver.kt") + public void testObjectImplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/basic/common/extensionMethodInObject/ObjectImplicitReceiver.kt"); + } + + @TestMetadata("OverridenExtensionsInObject.kt") + public void testOverridenExtensionsInObject() throws Exception { + runTest("idea/idea-completion/testData/basic/common/extensionMethodInObject/OverridenExtensionsInObject.kt"); + } + } + @TestMetadata("idea/idea-completion/testData/basic/common/extensions") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTestGenerated.java index 129f6e42855..60c853d1d12 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTestGenerated.java @@ -343,6 +343,59 @@ public class BasicCompletionHandlerTestGenerated extends AbstractBasicCompletion } } + @TestMetadata("idea/idea-completion/testData/handlers/basic/extensionMethodInObject") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ExtensionMethodInObject extends AbstractBasicCompletionHandlerTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInExtensionMethodInObject() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/handlers/basic/extensionMethodInObject"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("CompanionObjectInSameFileExplicitReceiver.kt") + public void testCompanionObjectInSameFileExplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/handlers/basic/extensionMethodInObject/CompanionObjectInSameFileExplicitReceiver.kt"); + } + + @TestMetadata("CompanionObjectInSameFileImplicitReceiver.kt") + public void testCompanionObjectInSameFileImplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/handlers/basic/extensionMethodInObject/CompanionObjectInSameFileImplicitReceiver.kt"); + } + + @TestMetadata("NestedCompanionObjectInSameFileExplicitReceiver.kt") + public void testNestedCompanionObjectInSameFileExplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedCompanionObjectInSameFileExplicitReceiver.kt"); + } + + @TestMetadata("NestedCompanionObjectInSameFileImplicitReceiver.kt") + public void testNestedCompanionObjectInSameFileImplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedCompanionObjectInSameFileImplicitReceiver.kt"); + } + + @TestMetadata("NestedObjectInSameFileExplicitReceiver.kt") + public void testNestedObjectInSameFileExplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedObjectInSameFileExplicitReceiver.kt"); + } + + @TestMetadata("NestedObjectInSameFileImplicitReceiver.kt") + public void testNestedObjectInSameFileImplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedObjectInSameFileImplicitReceiver.kt"); + } + + @TestMetadata("ObjectInSameFileExplicitReceiver.kt") + public void testObjectInSameFileExplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/handlers/basic/extensionMethodInObject/ObjectInSameFileExplicitReceiver.kt"); + } + + @TestMetadata("ObjectInSameFileImplicitReceiver.kt") + public void testObjectInSameFileImplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/handlers/basic/extensionMethodInObject/ObjectInSameFileImplicitReceiver.kt"); + } + } + @TestMetadata("idea/idea-completion/testData/handlers/basic/highOrderFunctions") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/idea/performanceTests/org/jetbrains/kotlin/idea/perf/PerformanceBasicCompletionHandlerTestGenerated.java b/idea/performanceTests/org/jetbrains/kotlin/idea/perf/PerformanceBasicCompletionHandlerTestGenerated.java index 55ba5f22ec8..064cd260d6f 100644 --- a/idea/performanceTests/org/jetbrains/kotlin/idea/perf/PerformanceBasicCompletionHandlerTestGenerated.java +++ b/idea/performanceTests/org/jetbrains/kotlin/idea/perf/PerformanceBasicCompletionHandlerTestGenerated.java @@ -343,6 +343,59 @@ public class PerformanceBasicCompletionHandlerTestGenerated extends AbstractPerf } } + @TestMetadata("idea/idea-completion/testData/handlers/basic/extensionMethodInObject") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ExtensionMethodInObject extends AbstractPerformanceBasicCompletionHandlerTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doPerfTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInExtensionMethodInObject() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/handlers/basic/extensionMethodInObject"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("CompanionObjectInSameFileExplicitReceiver.kt") + public void testCompanionObjectInSameFileExplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/handlers/basic/extensionMethodInObject/CompanionObjectInSameFileExplicitReceiver.kt"); + } + + @TestMetadata("CompanionObjectInSameFileImplicitReceiver.kt") + public void testCompanionObjectInSameFileImplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/handlers/basic/extensionMethodInObject/CompanionObjectInSameFileImplicitReceiver.kt"); + } + + @TestMetadata("NestedCompanionObjectInSameFileExplicitReceiver.kt") + public void testNestedCompanionObjectInSameFileExplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedCompanionObjectInSameFileExplicitReceiver.kt"); + } + + @TestMetadata("NestedCompanionObjectInSameFileImplicitReceiver.kt") + public void testNestedCompanionObjectInSameFileImplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedCompanionObjectInSameFileImplicitReceiver.kt"); + } + + @TestMetadata("NestedObjectInSameFileExplicitReceiver.kt") + public void testNestedObjectInSameFileExplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedObjectInSameFileExplicitReceiver.kt"); + } + + @TestMetadata("NestedObjectInSameFileImplicitReceiver.kt") + public void testNestedObjectInSameFileImplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/handlers/basic/extensionMethodInObject/NestedObjectInSameFileImplicitReceiver.kt"); + } + + @TestMetadata("ObjectInSameFileExplicitReceiver.kt") + public void testObjectInSameFileExplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/handlers/basic/extensionMethodInObject/ObjectInSameFileExplicitReceiver.kt"); + } + + @TestMetadata("ObjectInSameFileImplicitReceiver.kt") + public void testObjectInSameFileImplicitReceiver() throws Exception { + runTest("idea/idea-completion/testData/handlers/basic/extensionMethodInObject/ObjectInSameFileImplicitReceiver.kt"); + } + } + @TestMetadata("idea/idea-completion/testData/handlers/basic/highOrderFunctions") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)