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 new file mode 100644 index 00000000000..88f5b7cc049 --- /dev/null +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt @@ -0,0 +1,246 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.completion + +import com.intellij.codeInsight.completion.* +import com.intellij.patterns.PatternCondition +import com.intellij.patterns.StandardPatterns +import com.intellij.psi.util.PsiTreeUtil +import com.intellij.util.ProcessingContext +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.ClassifierDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType +import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType +import org.jetbrains.kotlin.psi.psiUtil.isAncestor +import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude +import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter + +class BasicCompletionSession(configuration: CompletionSessionConfiguration, + parameters: CompletionParameters, + resultSet: CompletionResultSet) +: CompletionSessionBase(configuration, parameters, resultSet) { + + private enum class CompletionKind( + val descriptorKindFilter: DescriptorKindFilter?, + val classKindFilter: ((ClassKind) -> Boolean)? + ) { + ALL( + descriptorKindFilter = DescriptorKindFilter(DescriptorKindFilter.ALL_KINDS_MASK), + classKindFilter = { it != ClassKind.ENUM_ENTRY } + ), + + TYPES( + descriptorKindFilter = DescriptorKindFilter(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK) exclude DescriptorKindExclude.EnumEntry, + classKindFilter = { it != ClassKind.ENUM_ENTRY } + ), + + ANNOTATION_TYPES( + descriptorKindFilter = ANNOTATION_TYPES_FILTER, + classKindFilter = { it == ClassKind.ANNOTATION_CLASS } + ), + + ANNOTATION_TYPES_OR_PARAMETER_NAME( + descriptorKindFilter = ANNOTATION_TYPES_FILTER, + classKindFilter = { it == ClassKind.ANNOTATION_CLASS } + ), + + KEYWORDS_ONLY(descriptorKindFilter = null, classKindFilter = null), + + NAMED_ARGUMENTS_ONLY(descriptorKindFilter = null, classKindFilter = null), + + PARAMETER_NAME(descriptorKindFilter = null, classKindFilter = null) + } + + private val completionKind = calcCompletionKind() + + override val descriptorKindFilter = completionKind.descriptorKindFilter + + private val parameterNameAndTypeCompletion = if (shouldCompleteParameterNameAndType()) + ParameterNameAndTypeCompletion(collector, lookupElementFactory, prefixMatcher, resolutionFacade) + else + null + + private fun calcCompletionKind(): CompletionKind { + if (NamedArgumentCompletion.isOnlyNamedArgumentExpected(position)) { + return CompletionKind.NAMED_ARGUMENTS_ONLY + } + + if (reference == null) { + val parameter = position.getParent() as? JetParameter + return if (parameter != null && position == parameter.getNameIdentifier()) + CompletionKind.PARAMETER_NAME + else + CompletionKind.KEYWORDS_ONLY + } + + val annotationEntry = position.getStrictParentOfType() + if (annotationEntry != null) { + val valueArgList = position.getStrictParentOfType() + if (valueArgList == null || !annotationEntry.isAncestor(valueArgList)) { + val parent = annotationEntry.getParent() + if (parent is JetDeclarationModifierList && parent.getParent() is JetParameter) { + return CompletionKind.ANNOTATION_TYPES_OR_PARAMETER_NAME + } + return CompletionKind.ANNOTATION_TYPES + } + } + + // Check that completion in the type annotation context and if there's a qualified + // expression we are at first of it + val typeReference = position.getStrictParentOfType() + if (typeReference != null) { + val firstPartReference = PsiTreeUtil.findChildOfType(typeReference, javaClass()) + if (firstPartReference == reference.expression) { + return CompletionKind.TYPES + } + } + + return CompletionKind.ALL + } + + private fun shouldCompleteParameterNameAndType(): Boolean { + when (completionKind) { + CompletionKind.PARAMETER_NAME, CompletionKind.ANNOTATION_TYPES_OR_PARAMETER_NAME -> { + val parameter = position.getNonStrictParentOfType()!! + val list = parameter.getParent() as? JetParameterList ?: return false + val owner = list.getParent() + return owner !is JetCatchClause && + owner !is JetPropertyAccessor && + !((owner as? JetPrimaryConstructor)?.getContainingClassOrObject()?.isAnnotation() ?: false) + } + + else -> return false + } + } + + public fun shouldDisableAutoPopup(): Boolean { + return when (completionKind) { + CompletionKind.PARAMETER_NAME, CompletionKind.ANNOTATION_TYPES_OR_PARAMETER_NAME -> !shouldCompleteParameterNameAndType() + else -> false + } + } + + override fun doComplete() { + assert(parameters.getCompletionType() == CompletionType.BASIC) + + // if we are typing parameter name, restart completion each time we type an upper case letter because new suggestions will appear (previous words can be used as user prefix) + if (parameterNameAndTypeCompletion != null) { + val prefixPattern = StandardPatterns.string().with(object : PatternCondition("Prefix ends with uppercase letter") { + override fun accepts(prefix: String, context: ProcessingContext?) = prefix.isNotEmpty() && prefix.last().isUpperCase() + }) + (CompletionService.getCompletionService().getCurrentCompletion() as CompletionProgressIndicator) + .addWatchedPrefix(parameters.getOffset(), prefixPattern) + } + + if (completionKind == CompletionKind.PARAMETER_NAME || completionKind == CompletionKind.ANNOTATION_TYPES_OR_PARAMETER_NAME) { + collector.suppressItemSelectionByCharsOnTyping = true + } + + if (completionKind != CompletionKind.NAMED_ARGUMENTS_ONLY) { + parameterNameAndTypeCompletion?.addFromParametersInFile(position, resolutionFacade, isVisibleFilter) + flushToResultSet() + + parameterNameAndTypeCompletion?.addFromImportedClasses(position, bindingContext, isVisibleFilter) + flushToResultSet() + + collector.addDescriptorElements(referenceVariants, suppressAutoInsertion = false) + + val keywordsPrefix = prefix.substringBefore('@') // if there is '@' in the prefix - use shorter prefix to not loose 'this' etc + KeywordCompletion.complete(expression ?: parameters.getPosition(), keywordsPrefix) { lookupElement -> + val keyword = lookupElement.getLookupString() + when (keyword) { + // 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).map { it.factory() }) + } + else { + // for completion in secondary constructor delegation call + collector.addElement(lookupElement) + } + } + + // if "return" is parsed correctly in the current context - insert it and all return@xxx items + "return" -> { + if (expression != null) { + collector.addElements(returnExpressionItems(bindingContext, expression)) + } + } + + "break", "continue" -> { + if (expression != null) { + collector.addElements(breakOrContinueExpressionItems(expression, keyword)) + } + } + + else -> collector.addElement(lookupElement) + } + } + + if (completionKind != CompletionKind.KEYWORDS_ONLY) { + flushToResultSet() + + if (!configuration.completeNonImportedDeclarations && isNoQualifierContext()) { + collector.advertiseSecondCompletion() + } + + addNonImported(completionKind) + + if (position.getContainingFile() is JetCodeFragment) { + flushToResultSet() + collector.addDescriptorElements(getRuntimeReceiverTypeReferenceVariants(), suppressAutoInsertion = false, withReceiverCast = true) + } + } + } + + NamedArgumentCompletion.complete(position, collector, bindingContext) + } + + private fun addNonImported(completionKind: CompletionKind) { + if (completionKind == CompletionKind.ALL) { + collector.addDescriptorElements(getTopLevelExtensions(), suppressAutoInsertion = true) + } + + flushToResultSet() + + if (shouldRunTopLevelCompletion()) { + completionKind.classKindFilter?.let { addAllClasses(it) } + + if (completionKind == CompletionKind.ALL) { + collector.addDescriptorElements(getTopLevelCallables(), suppressAutoInsertion = true) + } + } + + parameterNameAndTypeCompletion?.addFromAllClasses(parameters, indicesHelper) + } + + private companion object { + object NonAnnotationClassifierExclude : DescriptorKindExclude { + override fun matches(descriptor: DeclarationDescriptor): Boolean { + return if (descriptor is ClassDescriptor) + descriptor.getKind() != ClassKind.ANNOTATION_CLASS + else + descriptor !is ClassifierDescriptor + } + } + + val ANNOTATION_TYPES_FILTER = DescriptorKindFilter(DescriptorKindFilter.NON_SINGLETON_CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK) exclude NonAnnotationClassifierExclude + } +} \ No newline at end of file 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 ada259d8320..c9e90fc7177 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 @@ -270,311 +270,3 @@ abstract class CompletionSessionBase(protected val configuration: CompletionSess ) } } - -class BasicCompletionSession(configuration: CompletionSessionConfiguration, - parameters: CompletionParameters, - resultSet: CompletionResultSet) -: CompletionSessionBase(configuration, parameters, resultSet) { - - private enum class CompletionKind( - val descriptorKindFilter: DescriptorKindFilter?, - val classKindFilter: ((ClassKind) -> Boolean)? - ) { - ALL( - descriptorKindFilter = DescriptorKindFilter(DescriptorKindFilter.ALL_KINDS_MASK), - classKindFilter = { it != ClassKind.ENUM_ENTRY } - ), - - TYPES( - descriptorKindFilter = DescriptorKindFilter(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK) exclude DescriptorKindExclude.EnumEntry, - classKindFilter = { it != ClassKind.ENUM_ENTRY } - ), - - ANNOTATION_TYPES( - descriptorKindFilter = ANNOTATION_TYPES_FILTER, - classKindFilter = { it == ClassKind.ANNOTATION_CLASS } - ), - - ANNOTATION_TYPES_OR_PARAMETER_NAME( - descriptorKindFilter = ANNOTATION_TYPES_FILTER, - classKindFilter = { it == ClassKind.ANNOTATION_CLASS } - ), - - KEYWORDS_ONLY(descriptorKindFilter = null, classKindFilter = null), - - NAMED_ARGUMENTS_ONLY(descriptorKindFilter = null, classKindFilter = null), - - PARAMETER_NAME(descriptorKindFilter = null, classKindFilter = null) - } - - private val completionKind = calcCompletionKind() - - override val descriptorKindFilter = completionKind.descriptorKindFilter - - private val parameterNameAndTypeCompletion = if (shouldCompleteParameterNameAndType()) - ParameterNameAndTypeCompletion(collector, lookupElementFactory, prefixMatcher, resolutionFacade) - else - null - - private fun calcCompletionKind(): CompletionKind { - if (NamedArgumentCompletion.isOnlyNamedArgumentExpected(position)) { - return CompletionKind.NAMED_ARGUMENTS_ONLY - } - - if (reference == null) { - val parameter = position.getParent() as? JetParameter - return if (parameter != null && position == parameter.getNameIdentifier()) - CompletionKind.PARAMETER_NAME - else - CompletionKind.KEYWORDS_ONLY - } - - val annotationEntry = position.getStrictParentOfType() - if (annotationEntry != null) { - val valueArgList = position.getStrictParentOfType() - if (valueArgList == null || !annotationEntry.isAncestor(valueArgList)) { - val parent = annotationEntry.getParent() - if (parent is JetDeclarationModifierList && parent.getParent() is JetParameter) { - return CompletionKind.ANNOTATION_TYPES_OR_PARAMETER_NAME - } - return CompletionKind.ANNOTATION_TYPES - } - } - - // Check that completion in the type annotation context and if there's a qualified - // expression we are at first of it - val typeReference = position.getStrictParentOfType() - if (typeReference != null) { - val firstPartReference = PsiTreeUtil.findChildOfType(typeReference, javaClass()) - if (firstPartReference == reference.expression) { - return CompletionKind.TYPES - } - } - - return CompletionKind.ALL - } - - private fun shouldCompleteParameterNameAndType(): Boolean { - when (completionKind) { - CompletionKind.PARAMETER_NAME, CompletionKind.ANNOTATION_TYPES_OR_PARAMETER_NAME -> { - val parameter = position.getNonStrictParentOfType()!! - val list = parameter.getParent() as? JetParameterList ?: return false - val owner = list.getParent() - return owner !is JetCatchClause && - owner !is JetPropertyAccessor && - !((owner as? JetPrimaryConstructor)?.getContainingClassOrObject()?.isAnnotation() ?: false) - } - - else -> return false - } - } - - public fun shouldDisableAutoPopup(): Boolean { - return when (completionKind) { - CompletionKind.PARAMETER_NAME, CompletionKind.ANNOTATION_TYPES_OR_PARAMETER_NAME -> !shouldCompleteParameterNameAndType() - else -> false - } - } - - override fun doComplete() { - assert(parameters.getCompletionType() == CompletionType.BASIC) - - // if we are typing parameter name, restart completion each time we type an upper case letter because new suggestions will appear (previous words can be used as user prefix) - if (parameterNameAndTypeCompletion != null) { - val prefixPattern = StandardPatterns.string().with(object : PatternCondition("Prefix ends with uppercase letter") { - override fun accepts(prefix: String, context: ProcessingContext?) = prefix.isNotEmpty() && prefix.last().isUpperCase() - }) - (CompletionService.getCompletionService().getCurrentCompletion() as CompletionProgressIndicator) - .addWatchedPrefix(parameters.getOffset(), prefixPattern) - } - - if (completionKind == CompletionKind.PARAMETER_NAME || completionKind == CompletionKind.ANNOTATION_TYPES_OR_PARAMETER_NAME) { - collector.suppressItemSelectionByCharsOnTyping = true - } - - if (completionKind != CompletionKind.NAMED_ARGUMENTS_ONLY) { - parameterNameAndTypeCompletion?.addFromParametersInFile(position, resolutionFacade, isVisibleFilter) - flushToResultSet() - - parameterNameAndTypeCompletion?.addFromImportedClasses(position, bindingContext, isVisibleFilter) - flushToResultSet() - - collector.addDescriptorElements(referenceVariants, suppressAutoInsertion = false) - - val keywordsPrefix = prefix.substringBefore('@') // if there is '@' in the prefix - use shorter prefix to not loose 'this' etc - KeywordCompletion.complete(expression ?: parameters.getPosition(), keywordsPrefix) { lookupElement -> - val keyword = lookupElement.getLookupString() - when (keyword) { - // 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).map { it.factory() }) - } - else { - // for completion in secondary constructor delegation call - collector.addElement(lookupElement) - } - } - - // if "return" is parsed correctly in the current context - insert it and all return@xxx items - "return" -> { - if (expression != null) { - collector.addElements(returnExpressionItems(bindingContext, expression)) - } - } - - "break", "continue" -> { - if (expression != null) { - collector.addElements(breakOrContinueExpressionItems(expression, keyword)) - } - } - - else -> collector.addElement(lookupElement) - } - } - - if (completionKind != CompletionKind.KEYWORDS_ONLY) { - flushToResultSet() - - if (!configuration.completeNonImportedDeclarations && isNoQualifierContext()) { - collector.advertiseSecondCompletion() - } - - addNonImported(completionKind) - - if (position.getContainingFile() is JetCodeFragment) { - flushToResultSet() - collector.addDescriptorElements(getRuntimeReceiverTypeReferenceVariants(), suppressAutoInsertion = false, withReceiverCast = true) - } - } - } - - NamedArgumentCompletion.complete(position, collector, bindingContext) - } - - private fun addNonImported(completionKind: CompletionKind) { - if (completionKind == CompletionKind.ALL) { - collector.addDescriptorElements(getTopLevelExtensions(), suppressAutoInsertion = true) - } - - flushToResultSet() - - if (shouldRunTopLevelCompletion()) { - completionKind.classKindFilter?.let { addAllClasses(it) } - - if (completionKind == CompletionKind.ALL) { - collector.addDescriptorElements(getTopLevelCallables(), suppressAutoInsertion = true) - } - } - - parameterNameAndTypeCompletion?.addFromAllClasses(parameters, indicesHelper) - } - - private companion object { - object NonAnnotationClassifierExclude : DescriptorKindExclude { - override fun matches(descriptor: DeclarationDescriptor): Boolean { - return if (descriptor is ClassDescriptor) - descriptor.getKind() != ClassKind.ANNOTATION_CLASS - else - descriptor !is ClassifierDescriptor - } - } - - val ANNOTATION_TYPES_FILTER = DescriptorKindFilter(DescriptorKindFilter.NON_SINGLETON_CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK) exclude NonAnnotationClassifierExclude - } -} - -class SmartCompletionSession(configuration: CompletionSessionConfiguration, parameters: CompletionParameters, resultSet: CompletionResultSet) -: CompletionSessionBase(configuration, parameters, resultSet) { - - // we do not include SAM-constructors because they are handled separately and adding them requires iterating of java classes - override val descriptorKindFilter = DescriptorKindFilter.VALUES exclude SamConstructorDescriptorKindExclude - - override fun doComplete() { - if (NamedArgumentCompletion.isOnlyNamedArgumentExpected(position)) { - NamedArgumentCompletion.complete(position, collector, bindingContext) - return - } - - if (expression != null) { - val mapper = ToFromOriginalFileMapper(parameters.getOriginalFile() as JetFile, position.getContainingFile() as JetFile, parameters.getOffset()) - - addFunctionLiteralArgumentCompletions() - - val completion = SmartCompletion(expression, resolutionFacade, moduleDescriptor, - bindingContext, isVisibleFilter, inDescriptor, prefixMatcher, originalSearchScope, - mapper, lookupElementFactory) - val result = completion.execute() - if (result != null) { - collector.addElements(result.additionalItems) - - if (reference != null) { - val filter = result.declarationFilter - if (filter != null) { - referenceVariants.forEach { collector.addElements(filter(it)) } - flushToResultSet() - - processNonImported { collector.addElements(filter(it)) } - flushToResultSet() - - if (position.getContainingFile() is JetCodeFragment) { - getRuntimeReceiverTypeReferenceVariants().forEach { - collector.addElements(filter(it).map { it.withReceiverCast() }) - } - flushToResultSet() - } - } - - // it makes no sense to search inheritors if there is no reference because it means that we have prefix like "this@" - result.inheritanceSearcher?.search({ prefixMatcher.prefixMatches(it) }) { - collector.addElement(it) - flushToResultSet() - } - } - } - } - } - - // special completion for outside parenthesis lambda argument - private fun addFunctionLiteralArgumentCompletions() { - if (reference != null) { - val receiverData = ReferenceVariantsHelper.getExplicitReceiverData(reference.expression) - if (receiverData != null && receiverData.second == CallType.INFIX) { - val call = receiverData.first.getCall(bindingContext) - if (call != null && call.getFunctionLiteralArguments().isEmpty()) { - val dummyArgument = object : FunctionLiteralArgument { - override fun getFunctionLiteral() = throw UnsupportedOperationException() - override fun getArgumentExpression() = throw UnsupportedOperationException() - override fun getArgumentName(): ValueArgumentName? = null - override fun isNamed() = false - override fun asElement() = throw UnsupportedOperationException() - override fun getSpreadElement(): LeafPsiElement? = null - override fun isExternal() = false - } - val dummyArguments = call.getValueArguments() + listOf(dummyArgument) - val dummyCall = object : DelegatingCall(call) { - override fun getValueArguments() = dummyArguments - override fun getFunctionLiteralArguments() = listOf(dummyArgument) - override fun getValueArgumentList() = throw UnsupportedOperationException() - } - - val expectedInfos = ExpectedInfos(bindingContext, resolutionFacade, moduleDescriptor, true) - .calculateForArgument(dummyCall, dummyArgument) - if (expectedInfos != null) { - collector.addElements(LambdaItems.collect(expectedInfos)) - } - } - } - } - } - - private fun processNonImported(processor: (DeclarationDescriptor) -> Unit) { - getTopLevelExtensions().forEach(processor) - - flushToResultSet() - - if (shouldRunTopLevelCompletion()) { - getTopLevelCallables().forEach(processor) - } - } -} diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/SmartCompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/SmartCompletionSession.kt new file mode 100644 index 00000000000..f9512d19e1c --- /dev/null +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/SmartCompletionSession.kt @@ -0,0 +1,129 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.completion + +import com.intellij.codeInsight.completion.CompletionParameters +import com.intellij.codeInsight.completion.CompletionResultSet +import com.intellij.psi.impl.source.tree.LeafPsiElement +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.idea.codeInsight.ReferenceVariantsHelper +import org.jetbrains.kotlin.idea.completion.smart.LambdaItems +import org.jetbrains.kotlin.idea.completion.smart.SmartCompletion +import org.jetbrains.kotlin.idea.util.CallType +import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptorKindExclude +import org.jetbrains.kotlin.psi.FunctionLiteralArgument +import org.jetbrains.kotlin.psi.JetCodeFragment +import org.jetbrains.kotlin.psi.JetFile +import org.jetbrains.kotlin.psi.ValueArgumentName +import org.jetbrains.kotlin.resolve.calls.callUtil.getCall +import org.jetbrains.kotlin.resolve.calls.util.DelegatingCall +import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter + +class SmartCompletionSession(configuration: CompletionSessionConfiguration, parameters: CompletionParameters, resultSet: CompletionResultSet) +: CompletionSessionBase(configuration, parameters, resultSet) { + + // we do not include SAM-constructors because they are handled separately and adding them requires iterating of java classes + override val descriptorKindFilter = DescriptorKindFilter.VALUES exclude SamConstructorDescriptorKindExclude + + override fun doComplete() { + if (NamedArgumentCompletion.isOnlyNamedArgumentExpected(position)) { + NamedArgumentCompletion.complete(position, collector, bindingContext) + return + } + + if (expression != null) { + val mapper = ToFromOriginalFileMapper(parameters.getOriginalFile() as JetFile, position.getContainingFile() as JetFile, parameters.getOffset()) + + addFunctionLiteralArgumentCompletions() + + val completion = SmartCompletion(expression, resolutionFacade, moduleDescriptor, + bindingContext, isVisibleFilter, inDescriptor, prefixMatcher, originalSearchScope, + mapper, lookupElementFactory) + val result = completion.execute() + if (result != null) { + collector.addElements(result.additionalItems) + + if (reference != null) { + val filter = result.declarationFilter + if (filter != null) { + referenceVariants.forEach { collector.addElements(filter(it)) } + flushToResultSet() + + processNonImported { collector.addElements(filter(it)) } + flushToResultSet() + + if (position.getContainingFile() is JetCodeFragment) { + getRuntimeReceiverTypeReferenceVariants().forEach { + collector.addElements(filter(it).map { it.withReceiverCast() }) + } + flushToResultSet() + } + } + + // it makes no sense to search inheritors if there is no reference because it means that we have prefix like "this@" + result.inheritanceSearcher?.search({ prefixMatcher.prefixMatches(it) }) { + collector.addElement(it) + flushToResultSet() + } + } + } + } + } + + // special completion for outside parenthesis lambda argument + private fun addFunctionLiteralArgumentCompletions() { + if (reference != null) { + val receiverData = ReferenceVariantsHelper.getExplicitReceiverData(reference.expression) + if (receiverData != null && receiverData.second == CallType.INFIX) { + val call = receiverData.first.getCall(bindingContext) + if (call != null && call.getFunctionLiteralArguments().isEmpty()) { + val dummyArgument = object : FunctionLiteralArgument { + override fun getFunctionLiteral() = throw UnsupportedOperationException() + override fun getArgumentExpression() = throw UnsupportedOperationException() + override fun getArgumentName(): ValueArgumentName? = null + override fun isNamed() = false + override fun asElement() = throw UnsupportedOperationException() + override fun getSpreadElement(): LeafPsiElement? = null + override fun isExternal() = false + } + val dummyArguments = call.getValueArguments() + listOf(dummyArgument) + val dummyCall = object : DelegatingCall(call) { + override fun getValueArguments() = dummyArguments + override fun getFunctionLiteralArguments() = listOf(dummyArgument) + override fun getValueArgumentList() = throw UnsupportedOperationException() + } + + val expectedInfos = ExpectedInfos(bindingContext, resolutionFacade, moduleDescriptor, true) + .calculateForArgument(dummyCall, dummyArgument) + if (expectedInfos != null) { + collector.addElements(LambdaItems.collect(expectedInfos)) + } + } + } + } + } + + private fun processNonImported(processor: (DeclarationDescriptor) -> Unit) { + getTopLevelExtensions().forEach(processor) + + flushToResultSet() + + if (shouldRunTopLevelCompletion()) { + getTopLevelCallables().forEach(processor) + } + } +} \ No newline at end of file