From 3cda866af0eb390c51a6fa198753737155ca64df Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Thu, 5 Nov 2015 23:02:28 +0300 Subject: [PATCH] Static members completion works in smart completion + fixed incorrect finding of java method descriptor that caused duplicated items --- .../caches/resolve/JavaResolveExtension.kt | 11 ++++ .../idea/completion/BasicCompletionSession.kt | 6 +- .../idea/completion/CompletionSession.kt | 2 +- .../idea/completion/LookupElementFactory.kt | 24 ++++++-- .../completion/StaticMembersCompletion.kt | 60 ++++++++++++------- .../idea/completion/smart/SmartCompletion.kt | 10 ++-- .../smart/SmartCompletionSession.kt | 19 ++++++ .../handlers/smart/JavaStaticMethod2.kt | 9 +++ .../handlers/smart/JavaStaticMethod2.kt.after | 9 +++ .../StaticMembers1/Declarations1.kt | 9 +++ .../StaticMembers1/Declarations2.kt | 7 +++ .../StaticMembers1/JavaClass1.java | 15 +++++ .../StaticMembers1/JavaClass2.java | 11 ++++ .../StaticMembers1/StaticMembers1.kt | 24 ++++++++ .../StaticMembers2/Declarations1.kt | 9 +++ .../StaticMembers2/Declarations2.kt | 7 +++ .../StaticMembers2/JavaClass1.java | 15 +++++ .../StaticMembers2/JavaClass2.java | 11 ++++ .../StaticMembers2/StaticMembers2.kt | 24 ++++++++ ...MultiFileSmartCompletionTestGenerated.java | 12 ++++ .../SmartCompletionHandlerTestGenerated.java | 6 ++ .../BasicCompletionWeigherTestGenerated.java | 12 ++-- .../kotlin/idea/core/KotlinIndicesHelper.kt | 2 +- 23 files changed, 272 insertions(+), 42 deletions(-) create mode 100644 idea/idea-completion/testData/handlers/smart/JavaStaticMethod2.kt create mode 100644 idea/idea-completion/testData/handlers/smart/JavaStaticMethod2.kt.after create mode 100644 idea/idea-completion/testData/smartMultiFile/StaticMembers1/Declarations1.kt create mode 100644 idea/idea-completion/testData/smartMultiFile/StaticMembers1/Declarations2.kt create mode 100644 idea/idea-completion/testData/smartMultiFile/StaticMembers1/JavaClass1.java create mode 100644 idea/idea-completion/testData/smartMultiFile/StaticMembers1/JavaClass2.java create mode 100644 idea/idea-completion/testData/smartMultiFile/StaticMembers1/StaticMembers1.kt create mode 100644 idea/idea-completion/testData/smartMultiFile/StaticMembers2/Declarations1.kt create mode 100644 idea/idea-completion/testData/smartMultiFile/StaticMembers2/Declarations2.kt create mode 100644 idea/idea-completion/testData/smartMultiFile/StaticMembers2/JavaClass1.java create mode 100644 idea/idea-completion/testData/smartMultiFile/StaticMembers2/JavaClass2.java create mode 100644 idea/idea-completion/testData/smartMultiFile/StaticMembers2/StaticMembers2.kt diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/JavaResolveExtension.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/JavaResolveExtension.kt index 1ec4fe8c227..053a9467182 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/JavaResolveExtension.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/JavaResolveExtension.kt @@ -20,6 +20,7 @@ package org.jetbrains.kotlin.idea.caches.resolve import com.intellij.psi.* import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.util.ProjectRootsUtil import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.load.java.sources.JavaSourceElement @@ -47,6 +48,16 @@ fun PsiMethod.getJavaMethodDescriptor(): FunctionDescriptor? { } } +fun PsiMethod.getJavaMethodDescriptor(resolutionFacade: ResolutionFacade): FunctionDescriptor? { + val method = originalElement as? PsiMethod ?: return null + if (method.containingClass == null || !Name.isValidIdentifier(method.name)) return null + val resolver = resolutionFacade.getFrontendService(method, JavaDescriptorResolver::class.java) + return when { + method.isConstructor -> resolver.resolveConstructor(JavaConstructorImpl(method)) + else -> resolver.resolveMethod(JavaMethodImpl(method)) + } +} + fun PsiClass.getJavaClassDescriptor(): ClassDescriptor? { val psiClass = originalElement as? PsiClass ?: return null return psiClass.getJavaDescriptorResolver()?.resolveClass(JavaClassImpl(psiClass)) 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 63394864c71..234c5205f46 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 @@ -215,9 +215,9 @@ class BasicCompletionSession( } val staticMembersCompletion = StaticMembersCompletion( - collector, prefixMatcher, resolutionFacade, lookupElementFactory, referenceVariants!!.imported, isJvmModule) + prefixMatcher, resolutionFacade, lookupElementFactory, referenceVariants!!.imported, isJvmModule) if (callTypeAndReceiver is CallTypeAndReceiver.DEFAULT) { - staticMembersCompletion.completeFromImports(position.containingFile as KtFile) + staticMembersCompletion.completeFromImports(file, collector) } completeNonImported(lookupElementFactory) @@ -235,7 +235,7 @@ class BasicCompletionSession( } if (configuration.completeStaticMembers && callTypeAndReceiver is CallTypeAndReceiver.DEFAULT && prefix.isNotEmpty()) { - staticMembersCompletion.completeFromIndices(indicesHelper(false)) + staticMembersCompletion.completeFromIndices(indicesHelper(false), collector) } } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt index d3407a6bd46..66fbb919009 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt @@ -75,7 +75,7 @@ abstract class CompletionSession( resultSet: CompletionResultSet ) { protected val position = parameters.getPosition() - private val file = position.getContainingFile() as KtFile + protected val file = position.getContainingFile() as KtFile protected val resolutionFacade = file.getResolutionFacade() protected val moduleDescriptor = resolutionFacade.moduleDescriptor protected val project = position.getProject() diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt index 900294ba9e8..ee2ae1d66a1 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt @@ -42,6 +42,18 @@ import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf import org.jetbrains.kotlin.utils.addIfNotNull +interface AbstractLookupElementFactory { + fun createStandardLookupElementsForDescriptor(descriptor: DeclarationDescriptor, useReceiverTypes: Boolean): Collection + + fun createLookupElement( + descriptor: DeclarationDescriptor, + useReceiverTypes: Boolean, + qualifyNestedClasses: Boolean = false, + includeClassTypeArguments: Boolean = true, + parametersAndTypeGrayed: Boolean = false + ): LookupElement? +} + data /* we need copy() */ class LookupElementFactory( val basicFactory: BasicLookupElementFactory, @@ -50,7 +62,7 @@ class LookupElementFactory( private val inDescriptor: DeclarationDescriptor, private val contextVariablesProvider: ContextVariablesProvider, private val standardLookupElementsPostProcessor: (LookupElement) -> LookupElement = { it } -) { +) : AbstractLookupElementFactory { companion object { fun hasSingleFunctionTypeParameter(descriptor: FunctionDescriptor): Boolean { val parameter = descriptor.original.valueParameters.singleOrNull() ?: return false @@ -69,7 +81,7 @@ class LookupElementFactory( .toSet() } - public fun createStandardLookupElementsForDescriptor(descriptor: DeclarationDescriptor, useReceiverTypes: Boolean): Collection { + override fun createStandardLookupElementsForDescriptor(descriptor: DeclarationDescriptor, useReceiverTypes: Boolean): Collection { val result = SmartList() val isNormalCall = callType == CallType.DEFAULT || callType == CallType.DOT || callType == CallType.SAFE || callType == CallType.SUPER_MEMBERS @@ -197,12 +209,12 @@ class LookupElementFactory( } } - public fun createLookupElement( + override fun createLookupElement( descriptor: DeclarationDescriptor, useReceiverTypes: Boolean, - qualifyNestedClasses: Boolean = false, - includeClassTypeArguments: Boolean = true, - parametersAndTypeGrayed: Boolean = false + qualifyNestedClasses: Boolean, + includeClassTypeArguments: Boolean, + parametersAndTypeGrayed: Boolean ): LookupElement { var element = basicFactory.createLookupElement(descriptor, qualifyNestedClasses, includeClassTypeArguments, parametersAndTypeGrayed) 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 8758cb8db8b..81b779316ab 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 @@ -30,10 +30,10 @@ 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.utils.addToStdlib.singletonOrEmptyList import java.util.* class StaticMembersCompletion( - private val collector: LookupElementsCollector, private val prefixMatcher: PrefixMatcher, private val resolutionFacade: ResolutionFacade, private val lookupElementFactory: LookupElementFactory, @@ -44,8 +44,24 @@ class StaticMembersCompletion( if (it is ImportedFromObjectCallableDescriptor<*>) it.callableFromObject else it } - //TODO: include it in smart completion? - fun completeFromImports(file: KtFile) { + fun decoratedLookupElementFactory(itemPriority: ItemPriority): AbstractLookupElementFactory { + return object : AbstractLookupElementFactory { + override fun createStandardLookupElementsForDescriptor(descriptor: DeclarationDescriptor, useReceiverTypes: Boolean): Collection { + if (!useReceiverTypes) return emptyList() + return lookupElementFactory.createLookupElement(descriptor, useReceiverTypes = false) + .decorateAsStaticMember(descriptor, classNameAsLookupString = false) + ?.assignPriority(itemPriority) + ?.suppressAutoInsertion() + .singletonOrEmptyList() + } + + override fun createLookupElement(descriptor: DeclarationDescriptor, useReceiverTypes: Boolean, + qualifyNestedClasses: Boolean, includeClassTypeArguments: Boolean, + parametersAndTypeGrayed: Boolean) = null + } + } + + fun membersFromImports(file: KtFile): Collection { val containers = file.importDirectives .filter { !it.isAllUnder } .map { @@ -54,42 +70,46 @@ class StaticMembersCompletion( .filterNotNull() .toSet() + val result = ArrayList() for (container in containers) { val memberScope = if (container.kind == ClassKind.OBJECT) container.unsubstitutedMemberScope else container.staticScope val members = memberScope.getDescriptorsFiltered(DescriptorKindFilter.CALLABLES exclude DescriptorKindExclude.Extensions, prefixMatcher.asNameFilter()) - for (member in members) { - if (member is CallableDescriptor) { - addFromDescriptor(member, ItemPriority.STATIC_MEMBER_FROM_IMPORTS) - } - } + members.filterTo(result) { it is CallableDescriptor && it !in alreadyAdded } //TODO: substitution } + return result } //TODO: filter out those that are accessible from SmartCompletion.additionalItems //TODO: what about enum members? //TODO: better presentation for lookup elements from imports too //TODO: from the same file - fun completeFromIndices(indicesHelper: KotlinIndicesHelper) { + + fun membersFromIndices(indicesHelper: KotlinIndicesHelper): Collection { val descriptorKindFilter = DescriptorKindFilter.CALLABLES exclude DescriptorKindExclude.Extensions val nameFilter: (String) -> Boolean = { prefixMatcher.prefixMatches(it) } + val result = ArrayList() + if (isJvmModule) { - indicesHelper.getJavaStaticMembers(descriptorKindFilter, nameFilter).forEach { addFromDescriptor(it, ItemPriority.STATIC_MEMBER) } + indicesHelper.getJavaStaticMembers(descriptorKindFilter, nameFilter).filterTo(result) { it !in alreadyAdded } //TODO: substitution } - indicesHelper.getObjectMembers(descriptorKindFilter, nameFilter).forEach { addFromDescriptor(it, ItemPriority.STATIC_MEMBER) } + indicesHelper.getObjectMembers(descriptorKindFilter, nameFilter).filterTo(result) { it !in alreadyAdded } //TODO: substitution + + return result } - private fun addFromDescriptor(member: CallableDescriptor, itemPriority: ItemPriority) { - if (member !in alreadyAdded) { //TODO: substitution - collector.addElement(createLookupElement(member, itemPriority) ?: return) - } + fun completeFromImports(file: KtFile, collector: LookupElementsCollector) { + val factory = decoratedLookupElementFactory(ItemPriority.STATIC_MEMBER_FROM_IMPORTS) + membersFromImports(file) + .flatMap { factory.createStandardLookupElementsForDescriptor(it, useReceiverTypes = true) } + .forEach { collector.addElement(it) } } - private fun createLookupElement(descriptor: CallableDescriptor, itemPriority: ItemPriority): LookupElement? { - return lookupElementFactory.createLookupElement(descriptor, useReceiverTypes = false) - .decorateAsStaticMember(descriptor, classNameAsLookupString = false) - ?.assignPriority(itemPriority) - ?.suppressAutoInsertion() + fun completeFromIndices(indicesHelper: KotlinIndicesHelper, collector: LookupElementsCollector) { + val factory = decoratedLookupElementFactory(ItemPriority.STATIC_MEMBER) + membersFromIndices(indicesHelper) + .flatMap { factory.createStandardLookupElementsForDescriptor(it, useReceiverTypes = true) } + .forEach { collector.addElement(it) } } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletion.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletion.kt index ee115dcf3b3..a5a154f1dc3 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletion.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletion.kt @@ -83,9 +83,9 @@ class SmartCompletion( SmartCastCalculator(bindingContext, resolutionFacade.moduleDescriptor, expression, resolutionFacade) } - public val descriptorFilter: ((DeclarationDescriptor, LookupElementFactory) -> Collection)? = - { descriptor: DeclarationDescriptor, lookupElementFactory: LookupElementFactory -> - filterDescriptor(descriptor, lookupElementFactory).map { postProcess(it) } + public val descriptorFilter: ((DeclarationDescriptor, AbstractLookupElementFactory) -> Collection)? = + { descriptor: DeclarationDescriptor, factory: AbstractLookupElementFactory -> + filterDescriptor(descriptor, factory).map { postProcess(it) } }.check { expectedInfos.isNotEmpty() } public fun additionalItems(lookupElementFactory: LookupElementFactory): Pair, InheritanceItemsSearcher?> { @@ -154,7 +154,7 @@ class SmartCompletion( return@lazy emptySet() } - private fun filterDescriptor(descriptor: DeclarationDescriptor, lookupElementFactory: LookupElementFactory): Collection { + private fun filterDescriptor(descriptor: DeclarationDescriptor, lookupElementFactory: AbstractLookupElementFactory): Collection { val callType = callTypeAndReceiver.callType if (descriptor in descriptorsToSkip) return emptyList() @@ -322,7 +322,7 @@ class SmartCompletion( return null } - private fun MutableCollection.addCallableReferenceLookupElements(descriptor: DeclarationDescriptor, lookupElementFactory: LookupElementFactory) { + private fun MutableCollection.addCallableReferenceLookupElements(descriptor: DeclarationDescriptor, lookupElementFactory: AbstractLookupElementFactory) { if (callableTypeExpectedInfo.isEmpty()) return fun toLookupElement(descriptor: CallableDescriptor): LookupElement? { diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletionSession.kt index 12fdb24b330..c467a2d9807 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletionSession.kt @@ -107,6 +107,18 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para flushToResultSet() if (filter != null) { + val staticMembersCompletion: StaticMembersCompletion? + if (callTypeAndReceiver is CallTypeAndReceiver.DEFAULT) { + staticMembersCompletion = StaticMembersCompletion(prefixMatcher, resolutionFacade, lookupElementFactory, referenceVariants!!.imported, isJvmModule) + val decoratedFactory = staticMembersCompletion.decoratedLookupElementFactory(ItemPriority.STATIC_MEMBER_FROM_IMPORTS) + staticMembersCompletion.membersFromImports(file) + .flatMap { filter(it, decoratedFactory) } + .forEach { collector.addElement(it) } + } + else { + staticMembersCompletion = null + } + if (shouldCompleteTopLevelCallablesFromIndex()) { getTopLevelCallables().forEach { collector.addElements(filter(it, lookupElementFactory), notImported = true) } flushToResultSet() @@ -122,6 +134,13 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para flushToResultSet() } } + + if (staticMembersCompletion != null && configuration.completeStaticMembers) { + val decoratedFactory = staticMembersCompletion.decoratedLookupElementFactory(ItemPriority.STATIC_MEMBER) + staticMembersCompletion.membersFromIndices(indicesHelper(false)) + .flatMap { filter(it, decoratedFactory) } + .forEach { collector.addElement(it) } + } } } diff --git a/idea/idea-completion/testData/handlers/smart/JavaStaticMethod2.kt b/idea/idea-completion/testData/handlers/smart/JavaStaticMethod2.kt new file mode 100644 index 00000000000..1fcb0168a2b --- /dev/null +++ b/idea/idea-completion/testData/handlers/smart/JavaStaticMethod2.kt @@ -0,0 +1,9 @@ +fun foo(r: Runnable){} + +fun bar(){ + foo() +} + + +// INVOCATION_COUNT: 2 +// ELEMENT_TEXT: Thread.currentThread diff --git a/idea/idea-completion/testData/handlers/smart/JavaStaticMethod2.kt.after b/idea/idea-completion/testData/handlers/smart/JavaStaticMethod2.kt.after new file mode 100644 index 00000000000..54f7601ef5f --- /dev/null +++ b/idea/idea-completion/testData/handlers/smart/JavaStaticMethod2.kt.after @@ -0,0 +1,9 @@ +fun foo(r: Runnable){} + +fun bar(){ + foo(Thread.currentThread()) +} + + +// INVOCATION_COUNT: 2 +// ELEMENT_TEXT: Thread.currentThread diff --git a/idea/idea-completion/testData/smartMultiFile/StaticMembers1/Declarations1.kt b/idea/idea-completion/testData/smartMultiFile/StaticMembers1/Declarations1.kt new file mode 100644 index 00000000000..198c50d7fd3 --- /dev/null +++ b/idea/idea-completion/testData/smartMultiFile/StaticMembers1/Declarations1.kt @@ -0,0 +1,9 @@ +package dependency1 + +import test.C + +object O1 { + fun foo(): C = C() + fun bar(): C = C() + fun x(): String = "" +} \ No newline at end of file diff --git a/idea/idea-completion/testData/smartMultiFile/StaticMembers1/Declarations2.kt b/idea/idea-completion/testData/smartMultiFile/StaticMembers1/Declarations2.kt new file mode 100644 index 00000000000..bb60317d940 --- /dev/null +++ b/idea/idea-completion/testData/smartMultiFile/StaticMembers1/Declarations2.kt @@ -0,0 +1,7 @@ +package dependency2 + +import test.C + +object O2 { + fun foo(): C = C() +} \ No newline at end of file diff --git a/idea/idea-completion/testData/smartMultiFile/StaticMembers1/JavaClass1.java b/idea/idea-completion/testData/smartMultiFile/StaticMembers1/JavaClass1.java new file mode 100644 index 00000000000..df8733bd414 --- /dev/null +++ b/idea/idea-completion/testData/smartMultiFile/StaticMembers1/JavaClass1.java @@ -0,0 +1,15 @@ +import test.C + +public class JavaClass1 { + public static C f() { + return new C(); + } + + public static C g() { + return new C(); + } + + public static int h() { + return 0; + } +} \ No newline at end of file diff --git a/idea/idea-completion/testData/smartMultiFile/StaticMembers1/JavaClass2.java b/idea/idea-completion/testData/smartMultiFile/StaticMembers1/JavaClass2.java new file mode 100644 index 00000000000..72512e4388e --- /dev/null +++ b/idea/idea-completion/testData/smartMultiFile/StaticMembers1/JavaClass2.java @@ -0,0 +1,11 @@ +import test.C + +public class JavaClass2 { + public static C f() { + return new C(); + } + + public static C g() { + return new C(); + } +} \ No newline at end of file diff --git a/idea/idea-completion/testData/smartMultiFile/StaticMembers1/StaticMembers1.kt b/idea/idea-completion/testData/smartMultiFile/StaticMembers1/StaticMembers1.kt new file mode 100644 index 00000000000..75f6d8777d0 --- /dev/null +++ b/idea/idea-completion/testData/smartMultiFile/StaticMembers1/StaticMembers1.kt @@ -0,0 +1,24 @@ +package test + +import dependency1.O1.foo +import JavaClass1.f + +class C + +fun foo(): C { + return +} + +// INVOCATION_COUNT: 1 + +// EXIST: { allLookupStrings: "bar", itemText: "O1.bar", tailText: "() (dependency1)", attributes: "" } +// EXIST: { itemText: "foo", tailText: "()", attributes: "" } +// ABSENT: { itemText: "O1.foo" } +// ABSENT: { itemText: "O2.foo" } + +// EXIST: { allLookupStrings: "g", itemText: "JavaClass1.g", tailText: "() ()", attributes: "" } +// EXIST: { itemText: "f", tailText: "()", attributes: "" } +// ABSENT: { itemText: "JavaClass1.f" } +// ABSENT: { itemText: "JavaClass1.h" } +// ABSENT: { itemText: "JavaClass2.f" } +// ABSENT: { itemText: "JavaClass2.g" } diff --git a/idea/idea-completion/testData/smartMultiFile/StaticMembers2/Declarations1.kt b/idea/idea-completion/testData/smartMultiFile/StaticMembers2/Declarations1.kt new file mode 100644 index 00000000000..198c50d7fd3 --- /dev/null +++ b/idea/idea-completion/testData/smartMultiFile/StaticMembers2/Declarations1.kt @@ -0,0 +1,9 @@ +package dependency1 + +import test.C + +object O1 { + fun foo(): C = C() + fun bar(): C = C() + fun x(): String = "" +} \ No newline at end of file diff --git a/idea/idea-completion/testData/smartMultiFile/StaticMembers2/Declarations2.kt b/idea/idea-completion/testData/smartMultiFile/StaticMembers2/Declarations2.kt new file mode 100644 index 00000000000..bb60317d940 --- /dev/null +++ b/idea/idea-completion/testData/smartMultiFile/StaticMembers2/Declarations2.kt @@ -0,0 +1,7 @@ +package dependency2 + +import test.C + +object O2 { + fun foo(): C = C() +} \ No newline at end of file diff --git a/idea/idea-completion/testData/smartMultiFile/StaticMembers2/JavaClass1.java b/idea/idea-completion/testData/smartMultiFile/StaticMembers2/JavaClass1.java new file mode 100644 index 00000000000..df8733bd414 --- /dev/null +++ b/idea/idea-completion/testData/smartMultiFile/StaticMembers2/JavaClass1.java @@ -0,0 +1,15 @@ +import test.C + +public class JavaClass1 { + public static C f() { + return new C(); + } + + public static C g() { + return new C(); + } + + public static int h() { + return 0; + } +} \ No newline at end of file diff --git a/idea/idea-completion/testData/smartMultiFile/StaticMembers2/JavaClass2.java b/idea/idea-completion/testData/smartMultiFile/StaticMembers2/JavaClass2.java new file mode 100644 index 00000000000..626f4789854 --- /dev/null +++ b/idea/idea-completion/testData/smartMultiFile/StaticMembers2/JavaClass2.java @@ -0,0 +1,11 @@ +import test.C + +public class JavaClass2 { + public static C f() { + return new C(); + } + + public static int g() { + return 0; + } +} \ No newline at end of file diff --git a/idea/idea-completion/testData/smartMultiFile/StaticMembers2/StaticMembers2.kt b/idea/idea-completion/testData/smartMultiFile/StaticMembers2/StaticMembers2.kt new file mode 100644 index 00000000000..f423dfd47f4 --- /dev/null +++ b/idea/idea-completion/testData/smartMultiFile/StaticMembers2/StaticMembers2.kt @@ -0,0 +1,24 @@ +package test + +import dependency1.O1.foo +import JavaClass1.f + +class C + +fun foo(): C { + return +} + +// INVOCATION_COUNT: 2 + +// EXIST: { allLookupStrings: "bar", itemText: "O1.bar", tailText: "() (dependency1)", attributes: "" } +// EXIST: { itemText: "foo", tailText: "()", attributes: "" } +// ABSENT: { itemText: "O1.foo" } +// EXIST: { allLookupStrings: "foo", itemText: "O2.foo", tailText: "() (dependency2)", attributes: "" } + +// EXIST: { allLookupStrings: "g", itemText: "JavaClass1.g", tailText: "() ()", attributes: "" } +// EXIST: { itemText: "f", tailText: "()", attributes: "" } +// ABSENT: { itemText: "JavaClass1.f" } +// ABSENT: { itemText: "JavaClass1.h" } +// EXIST: { itemText: "JavaClass2.f" } +// ABSENT: { itemText: "JavaClass2.g" } diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/MultiFileSmartCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/MultiFileSmartCompletionTestGenerated.java index 6b3b440230c..f874fdc6144 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/MultiFileSmartCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/MultiFileSmartCompletionTestGenerated.java @@ -136,4 +136,16 @@ public class MultiFileSmartCompletionTestGenerated extends AbstractMultiFileSmar String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smartMultiFile/NoObjectDuplication/"); doTest(fileName); } + + @TestMetadata("StaticMembers1") + public void testStaticMembers1() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smartMultiFile/StaticMembers1/"); + doTest(fileName); + } + + @TestMetadata("StaticMembers2") + public void testStaticMembers2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smartMultiFile/StaticMembers2/"); + doTest(fileName); + } } diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/SmartCompletionHandlerTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/SmartCompletionHandlerTestGenerated.java index f4d248ab1f3..f3a53ffe555 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/SmartCompletionHandlerTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/SmartCompletionHandlerTestGenerated.java @@ -491,6 +491,12 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion doTest(fileName); } + @TestMetadata("JavaStaticMethod2.kt") + public void testJavaStaticMethod2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/JavaStaticMethod2.kt"); + doTest(fileName); + } + @TestMetadata("JavaStaticMethodInsertsImport.kt") public void testJavaStaticMethodInsertsImport() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/JavaStaticMethodInsertsImport.kt"); diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/weighers/BasicCompletionWeigherTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/weighers/BasicCompletionWeigherTestGenerated.java index 154cd2226b4..53469bf0cc4 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/weighers/BasicCompletionWeigherTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/weighers/BasicCompletionWeigherTestGenerated.java @@ -149,18 +149,18 @@ public class BasicCompletionWeigherTestGenerated extends AbstractBasicCompletion doTest(fileName); } - @TestMetadata("SuperMembers.kt") - public void testSuperMembers() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/weighers/basic/SuperMembers.kt"); - doTest(fileName); - } - @TestMetadata("StaticMembers.kt") public void testStaticMembers() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/weighers/basic/StaticMembers.kt"); doTest(fileName); } + @TestMetadata("SuperMembers.kt") + public void testSuperMembers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/weighers/basic/SuperMembers.kt"); + doTest(fileName); + } + @TestMetadata("idea/idea-completion/testData/weighers/basic/expectedInfo") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt index 8cd47498ffd..3f7da2d49ea 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt @@ -230,7 +230,7 @@ public class KotlinIndicesHelper( for (method in shortNamesCache.getMethodsByName(name, scope)) { if (!method.hasModifierProperty(PsiModifier.STATIC)) continue if (!visibilityFilterMayIncludeAccessible && method.hasModifierProperty(PsiModifier.PRIVATE)) continue - val descriptor = method.getJavaMethodDescriptor() ?: continue + val descriptor = method.getJavaMethodDescriptor(resolutionFacade) ?: continue val container = descriptor.containingDeclaration as? ClassDescriptor ?: continue if (descriptorKindFilter.accepts(descriptor) && descriptorFilter(descriptor)) { result.add(descriptor)