Moved classes to separate files
This commit is contained in:
+246
@@ -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<JetAnnotationEntry>()
|
||||||
|
if (annotationEntry != null) {
|
||||||
|
val valueArgList = position.getStrictParentOfType<JetValueArgumentList>()
|
||||||
|
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<JetTypeReference>()
|
||||||
|
if (typeReference != null) {
|
||||||
|
val firstPartReference = PsiTreeUtil.findChildOfType(typeReference, javaClass<JetSimpleNameExpression>())
|
||||||
|
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<JetParameter>()!!
|
||||||
|
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<String>("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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<JetAnnotationEntry>()
|
|
||||||
if (annotationEntry != null) {
|
|
||||||
val valueArgList = position.getStrictParentOfType<JetValueArgumentList>()
|
|
||||||
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<JetTypeReference>()
|
|
||||||
if (typeReference != null) {
|
|
||||||
val firstPartReference = PsiTreeUtil.findChildOfType(typeReference, javaClass<JetSimpleNameExpression>())
|
|
||||||
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<JetParameter>()!!
|
|
||||||
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<String>("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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+129
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user