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 1b11cc58bd2..7e337211b49 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 @@ -72,10 +72,10 @@ import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull class BasicCompletionSession( - configuration: CompletionSessionConfiguration, - parameters: CompletionParameters, - toFromOriginalFileMapper: ToFromOriginalFileMapper, - resultSet: CompletionResultSet + configuration: CompletionSessionConfiguration, + parameters: CompletionParameters, + toFromOriginalFileMapper: ToFromOriginalFileMapper, + resultSet: CompletionResultSet ) : CompletionSession(configuration, parameters, toFromOriginalFileMapper, resultSet) { private interface CompletionKind { @@ -95,9 +95,9 @@ class BasicCompletionSession( private val smartCompletion = expression?.let { SmartCompletion( - it, resolutionFacade, bindingContext, moduleDescriptor, isVisibleFilter, indicesHelper(false), prefixMatcher, - GlobalSearchScope.EMPTY_SCOPE, toFromOriginalFileMapper, callTypeAndReceiver, - isJvmModule, forBasicCompletion = true + it, resolutionFacade, bindingContext, moduleDescriptor, isVisibleFilter, indicesHelper(false), prefixMatcher, + GlobalSearchScope.EMPTY_SCOPE, toFromOriginalFileMapper, callTypeAndReceiver, + isJvmModule, forBasicCompletion = true ) } @@ -106,7 +106,7 @@ class BasicCompletionSession( private fun detectCompletionKind(): CompletionKind { if (nameExpression == null) { - return when { + return when { (position.parent as? KtNamedDeclaration)?.nameIdentifier == position -> DECLARATION_NAME else -> KEYWORDS_ONLY @@ -127,11 +127,9 @@ class BasicCompletionSession( return ALL } - fun shouldDisableAutoPopup(): Boolean - = completionKind.shouldDisableAutoPopup() + fun shouldDisableAutoPopup(): Boolean = completionKind.shouldDisableAutoPopup() - override fun shouldCompleteTopLevelCallablesFromIndex() - = super.shouldCompleteTopLevelCallablesFromIndex() && prefix.isNotEmpty() + override fun shouldCompleteTopLevelCallablesFromIndex() = super.shouldCompleteTopLevelCallablesFromIndex() && prefix.isNotEmpty() override fun doComplete() { assert(parameters.completionType == CompletionType.BASIC) @@ -167,10 +165,13 @@ class BasicCompletionSession( var sorter = super.createSorter() if (smartCompletion != null) { - val smartCompletionInBasicWeigher = SmartCompletionInBasicWeigher(smartCompletion, callTypeAndReceiver, resolutionFacade, bindingContext) - sorter = sorter.weighBefore(KindWeigher.toString(), - smartCompletionInBasicWeigher, - CallableReferenceWeigher(callTypeAndReceiver.callType)) + val smartCompletionInBasicWeigher = + SmartCompletionInBasicWeigher(smartCompletion, callTypeAndReceiver, resolutionFacade, bindingContext) + sorter = sorter.weighBefore( + KindWeigher.toString(), + smartCompletionInBasicWeigher, + CallableReferenceWeigher(callTypeAndReceiver.callType) + ) } sorter = completionKind.addWeighers(sorter) @@ -214,7 +215,9 @@ class BasicCompletionSession( fun completeWithSmartCompletion(lookupElementFactory: LookupElementFactory) { if (smartCompletion != null) { - val (additionalItems, @Suppress("UNUSED_VARIABLE") inheritanceSearcher) = smartCompletion.additionalItems(lookupElementFactory) + val (additionalItems, @Suppress("UNUSED_VARIABLE") inheritanceSearcher) = smartCompletion.additionalItems( + lookupElementFactory + ) // all additional items should have SMART_COMPLETION_ITEM_PRIORITY_KEY to be recognized by SmartCompletionInBasicWeigher for (item in additionalItems) { @@ -239,8 +242,8 @@ class BasicCompletionSession( val contextVariableTypesForReferenceVariants = withCollectRequiredContextVariableTypes { lookupElementFactory -> when { prefix.isEmpty() - || callTypeAndReceiver.receiver != null - || CodeInsightSettings.getInstance().COMPLETION_CASE_SENSITIVE == CodeInsightSettings.NONE -> { + || callTypeAndReceiver.receiver != null + || CodeInsightSettings.getInstance().COMPLETION_CASE_SENSITIVE == CodeInsightSettings.NONE -> { addReferenceVariantElements(lookupElementFactory, descriptorKindFilter) } @@ -265,7 +268,7 @@ class BasicCompletionSession( if (callTypeAndReceiver.receiver == null && callTypeAndReceiver.callType.descriptorKindFilter.kindMask.and(DescriptorKindFilter.PACKAGES_MASK) != 0) { //TODO: move this code somewhere else? val packageNames = PackageIndexUtil.getSubPackageFqNames(FqName.ROOT, searchScope, project, prefixMatcher.asNameFilter()) - .toMutableSet() + .toMutableSet() if (TargetPlatformDetector.getPlatform(parameters.originalFile as KtFile) == JvmPlatform) { JavaPsiFacade.getInstance(project).findPackage("")?.getSubPackages(searchScope)?.forEach { psiPackage -> @@ -288,11 +291,12 @@ class BasicCompletionSession( withContextVariablesProvider(contextVariablesProvider) { lookupElementFactory -> if (receiverTypes != null) { ExtensionFunctionTypeValueCompletion(receiverTypes, callTypeAndReceiver.callType, lookupElementFactory) - .processVariables(contextVariablesProvider) - .forEach { - val lookupElements = it.factory.createStandardLookupElementsForDescriptor(it.invokeDescriptor, useReceiverTypes = true) - collector.addElements(lookupElements) - } + .processVariables(contextVariablesProvider) + .forEach { + val lookupElements = + it.factory.createStandardLookupElementsForDescriptor(it.invokeDescriptor, useReceiverTypes = true) + collector.addElements(lookupElements) + } } if (contextVariableTypesForSmartCompletion.any { contextVariablesProvider.functionTypeVariables(it).isNotEmpty() }) { @@ -306,11 +310,12 @@ class BasicCompletionSession( } val staticMembersCompletion = StaticMembersCompletion( - prefixMatcher, - resolutionFacade, - lookupElementFactory, - referenceVariantsCollector!!.allCollected.imported, - isJvmModule) + prefixMatcher, + resolutionFacade, + lookupElementFactory, + referenceVariantsCollector!!.allCollected.imported, + isJvmModule + ) if (callTypeAndReceiver is CallTypeAndReceiver.DEFAULT) { staticMembersCompletion.completeFromImports(file, collector) } @@ -324,7 +329,12 @@ class BasicCompletionSession( val variants = variantsAndFactory.first @Suppress("NAME_SHADOWING") val lookupElementFactory = variantsAndFactory.second collector.addDescriptorElements(variants.imported, lookupElementFactory, withReceiverCast = true) - collector.addDescriptorElements(variants.notImportedExtensions, lookupElementFactory, withReceiverCast = true, notImported = true) + collector.addDescriptorElements( + variants.notImportedExtensions, + lookupElementFactory, + withReceiverCast = true, + notImported = true + ) flushToResultSet() } } @@ -370,8 +380,7 @@ class BasicCompletionSession( prefixMatcher addClassesFromIndex(classKindFilter, includeTypeAliases, prefixMatcher) } - } - else if (callTypeAndReceiver is CallTypeAndReceiver.DOT) { + } else if (callTypeAndReceiver is CallTypeAndReceiver.DOT) { val qualifier = bindingContext[BindingContext.QUALIFIER, callTypeAndReceiver.receiver] if (qualifier != null) return val receiver = callTypeAndReceiver.receiver as? KtSimpleNameExpression ?: return @@ -388,98 +397,106 @@ class BasicCompletionSession( } } - AllClassesCompletion(parameters.withPosition(receiver, receiver.startOffset), helper, fullTextPrefixMatcher, resolutionFacade, - { true }, true, configuration.javaClassesNotToBeUsed + AllClassesCompletion( + parameters.withPosition(receiver, receiver.startOffset), helper, fullTextPrefixMatcher, resolutionFacade, + { true }, true, configuration.javaClassesNotToBeUsed ).collect({ descriptors += it }, { descriptors.addIfNotNull(it.resolveToDescriptor(resolutionFacade)) }) val foundDescriptors = mutableSetOf() descriptors.asSequence() - .filter { - it.kind == ClassKind.OBJECT || - it.kind == ClassKind.ENUM_CLASS || - it.kind == ClassKind.ENUM_ENTRY || - it.hasCompanionObject || - it is JavaClassDescriptor - } - .forEach { classifier -> - val scope = nameExpression?.getResolutionScope(bindingContext) ?: return + .filter { + it.kind == ClassKind.OBJECT || + it.kind == ClassKind.ENUM_CLASS || + it.kind == ClassKind.ENUM_ENTRY || + it.hasCompanionObject || + it is JavaClassDescriptor + } + .forEach { classifier -> + val scope = nameExpression?.getResolutionScope(bindingContext) ?: return - val desc = classifier.getImportableDescriptor() - val newScope = scope.addImportingScope(ExplicitImportsScope(listOf(desc))) + val desc = classifier.getImportableDescriptor() + val newScope = scope.addImportingScope(ExplicitImportsScope(listOf(desc))) - val newContext = (nameExpression.parent as KtExpression).analyzeInContext(newScope) + val newContext = (nameExpression.parent as KtExpression).analyzeInContext(newScope) - val rvHelper = ReferenceVariantsHelper(newContext, - resolutionFacade, - moduleDescriptor, - isVisibleFilter, - NotPropertiesService.getNotProperties(position)) - val rvCollector = ReferenceVariantsCollector(rvHelper, indicesHelper(true), prefixMatcher, - nameExpression, callTypeAndReceiver, resolutionFacade, newContext, - importableFqNameClassifier, configuration) + val rvHelper = ReferenceVariantsHelper( + newContext, + resolutionFacade, + moduleDescriptor, + isVisibleFilter, + NotPropertiesService.getNotProperties(position) + ) + val rvCollector = ReferenceVariantsCollector( + rvHelper, indicesHelper(true), prefixMatcher, + nameExpression, callTypeAndReceiver, resolutionFacade, newContext, + importableFqNameClassifier, configuration + ) - val receiverTypes = detectReceiverTypes(newContext, nameExpression, callTypeAndReceiver) + val receiverTypes = detectReceiverTypes(newContext, nameExpression, callTypeAndReceiver) - val factory = lookupElementFactory.copy(receiverTypes = receiverTypes, standardLookupElementsPostProcessor = { + val factory = lookupElementFactory.copy(receiverTypes = receiverTypes, standardLookupElementsPostProcessor = { lookupElement -> - val lookupDescriptor = (lookupElement.`object` as? DeclarationLookupObject) - ?.descriptor as? MemberDescriptor ?: return@copy lookupElement + val lookupDescriptor = (lookupElement.`object` as? DeclarationLookupObject) + ?.descriptor as? MemberDescriptor ?: return@copy lookupElement - if (!desc.isAncestorOf(lookupDescriptor, false)) return@copy lookupElement + if (!desc.isAncestorOf(lookupDescriptor, false)) return@copy lookupElement - if (lookupDescriptor is CallableMemberDescriptor && - lookupDescriptor.isExtension && - lookupDescriptor.extensionReceiverParameter?.importableFqName != desc.fqNameSafe) { - return@copy lookupElement - } - - val fqNameToImport = lookupDescriptor.containingDeclaration.importableFqName ?: return@copy lookupElement - - object : LookupElementDecorator(lookupElement) { - val name = fqNameToImport.shortName() - val packageName = fqNameToImport.parent() - - override fun handleInsert(context: InsertionContext) { - super.handleInsert(context) - context.commitDocument() - val file = context.file as? KtFile - if (file != null) { - val receiverInFile = file.findElementAt(receiver.startOffset)?.getParentOfType(false) ?: return - receiverInFile.mainReference.bindToFqName(fqNameToImport, FORCED_SHORTENING) - } - } - - override fun renderElement(presentation: LookupElementPresentation?) { - super.renderElement(presentation) - presentation?.appendTailText(" for $name in $packageName", true) - } - } - }) - - - rvCollector.collectReferenceVariants(descriptorKindFilter) { (imported, notImportedExtensions) -> - - val unique = imported.asSequence() - .filterNot { it.original in foundDescriptors } - .onEach { foundDescriptors += it.original } - - val uniqueNotImportedExtensions = notImportedExtensions.asSequence() - .filterNot { it.original in foundDescriptors } - .onEach { foundDescriptors += it.original } - - collector.addDescriptorElements( - unique.toList(), factory, - prohibitDuplicates = true - ) - collector.addDescriptorElements( - uniqueNotImportedExtensions.toList(), factory, - notImported = true, prohibitDuplicates = true - ) - - flushToResultSet() + if (lookupDescriptor is CallableMemberDescriptor && + lookupDescriptor.isExtension && + lookupDescriptor.extensionReceiverParameter?.importableFqName != desc.fqNameSafe + ) { + return@copy lookupElement } + + val fqNameToImport = lookupDescriptor.containingDeclaration.importableFqName ?: return@copy lookupElement + + object : LookupElementDecorator(lookupElement) { + val name = fqNameToImport.shortName() + val packageName = fqNameToImport.parent() + + override fun handleInsert(context: InsertionContext) { + super.handleInsert(context) + context.commitDocument() + val file = context.file as? KtFile + if (file != null) { + val receiverInFile = + file.findElementAt(receiver.startOffset)?.getParentOfType(false) + ?: return + receiverInFile.mainReference.bindToFqName(fqNameToImport, FORCED_SHORTENING) + } + } + + override fun renderElement(presentation: LookupElementPresentation?) { + super.renderElement(presentation) + presentation?.appendTailText(" for $name in $packageName", true) + } + } + }) + + + rvCollector.collectReferenceVariants(descriptorKindFilter) { (imported, notImportedExtensions) -> + + val unique = imported.asSequence() + .filterNot { it.original in foundDescriptors } + .onEach { foundDescriptors += it.original } + + val uniqueNotImportedExtensions = notImportedExtensions.asSequence() + .filterNot { it.original in foundDescriptors } + .onEach { foundDescriptors += it.original } + + collector.addDescriptorElements( + unique.toList(), factory, + prohibitDuplicates = true + ) + collector.addDescriptorElements( + uniqueNotImportedExtensions.toList(), factory, + notImported = true, prohibitDuplicates = true + ) + + flushToResultSet() } + } } } @@ -508,7 +525,12 @@ class BasicCompletionSession( val keywordsToSkip = HashSet() val keywordValueConsumer = object : KeywordValues.Consumer { - override fun consume(lookupString: String, expectedInfoMatcher: (ExpectedInfo) -> ExpectedInfoMatch, priority: SmartCompletionItemPriority, factory: () -> LookupElement) { + override fun consume( + lookupString: String, + expectedInfoMatcher: (ExpectedInfo) -> ExpectedInfoMatch, + priority: SmartCompletionItemPriority, + factory: () -> LookupElement + ) { keywordsToSkip.add(lookupString) val lookupElement = factory() val matched = expectedInfos.any { @@ -523,7 +545,14 @@ class BasicCompletionSession( collector.addElement(lookupElement) } } - KeywordValues.process(keywordValueConsumer, callTypeAndReceiver, bindingContext, resolutionFacade, moduleDescriptor, isJvmModule) + KeywordValues.process( + keywordValueConsumer, + callTypeAndReceiver, + bindingContext, + resolutionFacade, + moduleDescriptor, + isJvmModule + ) val keywordsPrefix = prefix.substringBefore('@') // if there is '@' in the prefix - use shorter prefix to not loose 'this' etc val isUseSiteAnnotationTarget = position.prevLeaf()?.node?.elementType == KtTokens.AT @@ -535,9 +564,14 @@ class BasicCompletionSession( // if "this" is parsed correctly in the current context - insert it and all this@xxx items "this" -> { if (expression != null) { - collector.addElements(thisExpressionItems(bindingContext, expression, prefix, resolutionFacade).map { it.createLookupElement() }) - } - else { + collector.addElements( + thisExpressionItems( + bindingContext, + expression, + prefix, + resolutionFacade + ).map { it.createLookupElement() }) + } else { // for completion in secondary constructor delegation call collector.addElement(lookupElement) } @@ -573,7 +607,14 @@ class BasicCompletionSession( if (!isUseSiteAnnotationTarget) { collector.addElement(createKeywordConstructLookupElement(project, keyword, "val v:Int get()=caret")) - collector.addElement(createKeywordConstructLookupElement(project, keyword, "val v:Int get(){caret}", trimSpacesAroundCaret = true)) + collector.addElement( + createKeywordConstructLookupElement( + project, + keyword, + "val v:Int get(){caret}", + trimSpacesAroundCaret = true + ) + ) } } @@ -582,7 +623,14 @@ class BasicCompletionSession( if (!isUseSiteAnnotationTarget) { collector.addElement(createKeywordConstructLookupElement(project, keyword, "var v:Int set(value)=caret")) - collector.addElement(createKeywordConstructLookupElement(project, keyword, "var v:Int set(value){caret}", trimSpacesAroundCaret = true)) + collector.addElement( + createKeywordConstructLookupElement( + project, + keyword, + "var v:Int set(value){caret}", + trimSpacesAroundCaret = true + ) + ) } } @@ -609,7 +657,8 @@ class BasicCompletionSession( if (nameExpression == null || nameExpression != expression) return false val func = position.getParentOfType(strict = false) ?: return false val funcNameIdentifier = func.nameIdentifier ?: return false - val identifierInNameExpression = nameExpression.nextLeaf { it is LeafPsiElement && it.elementType == KtTokens.IDENTIFIER } ?: return false + val identifierInNameExpression = + nameExpression.nextLeaf { it is LeafPsiElement && it.elementType == KtTokens.IDENTIFIER } ?: return false if (!func.hasModifier(KtTokens.OPERATOR_KEYWORD) || identifierInNameExpression != funcNameIdentifier) return false val originalFunc = toFromOriginalFileMapper.toOriginalFile(func) ?: return false return !originalFunc.isTopLevel || (originalFunc.isExtensionDeclaration()) @@ -692,7 +741,7 @@ class BasicCompletionSession( val classOrObject = position.parents.firstIsInstanceOrNull() ?: return val classDescriptor = resolutionFacade.resolveToDescriptor(classOrObject, BodyResolveMode.PARTIAL) as ClassDescriptor var superClasses = classDescriptor.defaultType.constructor.supertypesWithAny() - .mapNotNull { it.constructor.declarationDescriptor as? ClassDescriptor } + .mapNotNull { it.constructor.declarationDescriptor as? ClassDescriptor } if (callTypeAndReceiver.receiver != null) { val referenceVariantsSet = referenceVariantsCollector!!.collectReferenceVariants(descriptorKindFilter).imported.toSet() @@ -700,16 +749,15 @@ class BasicCompletionSession( } superClasses - .map { basicLookupElementFactory.createLookupElement(it, qualifyNestedClasses = true, includeClassTypeArguments = false) } - .forEach { collector.addElement(it) } + .map { basicLookupElementFactory.createLookupElement(it, qualifyNestedClasses = true, includeClassTypeArguments = false) } + .forEach { collector.addElement(it) } } } private fun completeDeclarationNameFromUnresolvedOrOverride(declaration: KtNamedDeclaration) { if (declaration is KtCallableDeclaration && declaration.hasModifier(KtTokens.OVERRIDE_KEYWORD)) { OverridesCompletion(collector, basicLookupElementFactory).complete(position, declaration) - } - else { + } else { val referenceScope = referenceScope(declaration) ?: return val originalScope = toFromOriginalFileMapper.toOriginalFile(referenceScope) ?: return val afterOffset = if (referenceScope is KtBlockExpression) parameters.offset else null @@ -727,8 +775,7 @@ class BasicCompletionSession( val classOrObject = parent.parent as KtClassOrObject if (classOrObject is KtObjectDeclaration && classOrObject.isCompanion()) { classOrObject.containingClassOrObject - } - else { + } else { classOrObject } } @@ -748,8 +795,9 @@ class BasicCompletionSession( val javaClassCollector = { javaClass: PsiClass -> collector.addElement(basicLookupElementFactory.createLookupElementForJavaClass(javaClass), notImported = true) } - AllClassesCompletion(parameters, indicesHelper(true), prefixMatcher, resolutionFacade, - kindFilter, includeTypeAliases, configuration.javaClassesNotToBeUsed + AllClassesCompletion( + parameters, indicesHelper(true), prefixMatcher, resolutionFacade, + kindFilter, includeTypeAliases, configuration.javaClassesNotToBeUsed ).collect(classifierDescriptorCollector, javaClassCollector) } @@ -793,10 +841,14 @@ class BasicCompletionSession( } } -private val USUALLY_START_UPPER_CASE = DescriptorKindFilter(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.FUNCTIONS_MASK, - listOf(NonSamConstructorFunctionExclude, DescriptorKindExclude.Extensions /* needed for faster getReferenceVariants */)) -private val USUALLY_START_LOWER_CASE = DescriptorKindFilter(DescriptorKindFilter.CALLABLES_MASK or DescriptorKindFilter.PACKAGES_MASK, - listOf(SamConstructorDescriptorKindExclude)) +private val USUALLY_START_UPPER_CASE = DescriptorKindFilter( + DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.FUNCTIONS_MASK, + listOf(NonSamConstructorFunctionExclude, DescriptorKindExclude.Extensions /* needed for faster getReferenceVariants */) +) +private val USUALLY_START_LOWER_CASE = DescriptorKindFilter( + DescriptorKindFilter.CALLABLES_MASK or DescriptorKindFilter.PACKAGES_MASK, + listOf(SamConstructorDescriptorKindExclude) +) private object NonSamConstructorFunctionExclude : DescriptorKindExclude() { override fun excludes(descriptor: DeclarationDescriptor) = descriptor is FunctionDescriptor && descriptor !is SamConstructorDescriptor