Refactoring: step 1
This commit is contained in:
+12
-111
@@ -37,19 +37,15 @@ import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||
import org.jetbrains.kotlin.idea.project.ProjectStructureUtil
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.idea.util.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.resolve.DataClassDescriptorResolver
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.decapitalizeSmart
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||
import java.util.*
|
||||
|
||||
@@ -154,20 +150,6 @@ abstract class CompletionSession(
|
||||
declarationTranslator = { toFromOriginalFileMapper.toSyntheticFile(it) })
|
||||
}
|
||||
|
||||
protected object TopLevelExtensionsExclude : DescriptorKindExclude() {
|
||||
override fun excludes(descriptor: DeclarationDescriptor): Boolean {
|
||||
if (descriptor !is CallableMemberDescriptor) return false
|
||||
if (descriptor.extensionReceiverParameter == null) return false
|
||||
if (descriptor.kind != CallableMemberDescriptor.Kind.DECLARATION) return false /* do not filter out synthetic extensions */
|
||||
val containingPackage = descriptor.containingDeclaration as? PackageFragmentDescriptor ?: return false
|
||||
if (containingPackage.fqName.asString().startsWith("kotlinx.android.synthetic.")) return false // TODO: temporary solution for Android synthetic extensions
|
||||
return true
|
||||
}
|
||||
|
||||
override val fullyExcludedDescriptorKinds: Int
|
||||
get() = 0
|
||||
}
|
||||
|
||||
private fun isVisibleDescriptor(descriptor: DeclarationDescriptor, completeNonAccessible: Boolean): Boolean {
|
||||
if (!configuration.javaClassesNotToBeUsed && descriptor is ClassDescriptor) {
|
||||
if (descriptor.importableFqName?.let { isJavaClassNotToBeUsedInKotlin(it) } == true) return false
|
||||
@@ -287,99 +269,20 @@ abstract class CompletionSession(
|
||||
return context
|
||||
}
|
||||
|
||||
protected data class ReferenceVariants(val imported: Collection<DeclarationDescriptor>, val notImportedExtensions: Collection<CallableDescriptor>)
|
||||
|
||||
protected val referenceVariants: ReferenceVariants? by lazy {
|
||||
if (nameExpression != null && descriptorKindFilter != null) collectReferenceVariants(descriptorKindFilter!!, nameExpression) else null
|
||||
if (nameExpression != null && descriptorKindFilter != null)
|
||||
ReferenceVariantsCollector(referenceVariantsHelper, indicesHelper(true), prefixMatcher,
|
||||
nameExpression, callTypeAndReceiver, resolutionFacade, bindingContext,
|
||||
importableFqNameClassifier, configuration
|
||||
).collectReferenceVariants(descriptorKindFilter!!)
|
||||
else
|
||||
null
|
||||
}
|
||||
|
||||
protected val referenceVariantsWithNonInitializedVarExcluded: ReferenceVariants? by lazy {
|
||||
referenceVariants?.let { ReferenceVariants(referenceVariantsHelper.excludeNonInitializedVariable(it.imported, position), it.notImportedExtensions) }
|
||||
}
|
||||
|
||||
private fun collectReferenceVariants(
|
||||
descriptorKindFilter: DescriptorKindFilter,
|
||||
nameExpression: KtSimpleNameExpression,
|
||||
runtimeReceiver: ExpressionReceiver? = null
|
||||
): ReferenceVariants {
|
||||
val completeExtensionsFromIndices = descriptorKindFilter.kindMask.and(DescriptorKindFilter.CALLABLES_MASK) != 0
|
||||
&& callTypeAndReceiver !is CallTypeAndReceiver.IMPORT_DIRECTIVE
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val descriptorKindFilter = if (completeExtensionsFromIndices)
|
||||
descriptorKindFilter exclude TopLevelExtensionsExclude // handled via indices
|
||||
else
|
||||
descriptorKindFilter
|
||||
|
||||
fun getReferenceVariants(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> {
|
||||
return referenceVariantsHelper.getReferenceVariants(
|
||||
nameExpression,
|
||||
kindFilter,
|
||||
nameFilter,
|
||||
filterOutJavaGettersAndSetters = false,
|
||||
filterOutShadowed = false,
|
||||
excludeNonInitializedVariable = false,
|
||||
useReceiverType = runtimeReceiver?.type)
|
||||
}
|
||||
|
||||
var variants = getReferenceVariants(descriptorKindFilter, descriptorNameFilter.toNameFilter())
|
||||
|
||||
val getOrSetPrefix = listOf("get", "set", "ge", "se", "g", "s").firstOrNull { prefix.startsWith(it) }
|
||||
val additionalPropertyNameFilter: ((String) -> Boolean)? = run {
|
||||
getOrSetPrefix?.let { prefixMatcher.cloneWithPrefix(prefix.removePrefix(getOrSetPrefix).decapitalizeSmart()).asStringNameFilter() }
|
||||
}
|
||||
if (additionalPropertyNameFilter != null) {
|
||||
variants += getReferenceVariants(descriptorKindFilter.intersect(DescriptorKindFilter.VARIABLES),
|
||||
additionalPropertyNameFilter.toNameFilter())
|
||||
variants = variants.distinct()
|
||||
}
|
||||
|
||||
var notImportedExtensions: Collection<CallableDescriptor> = emptyList()
|
||||
if (completeExtensionsFromIndices) {
|
||||
val indicesHelper = indicesHelper(true)
|
||||
val nameFilter = if (additionalPropertyNameFilter != null)
|
||||
descriptorNameFilter or additionalPropertyNameFilter
|
||||
else
|
||||
descriptorNameFilter
|
||||
val extensions = if (runtimeReceiver != null)
|
||||
indicesHelper.getCallableTopLevelExtensions(callTypeAndReceiver, listOf(runtimeReceiver.type), nameFilter)
|
||||
else
|
||||
indicesHelper.getCallableTopLevelExtensions(callTypeAndReceiver, expression!!, bindingContext, nameFilter)
|
||||
|
||||
val pair = extensions.partition { isImportableDescriptorImported(it) }
|
||||
variants += pair.first
|
||||
notImportedExtensions = pair.second
|
||||
}
|
||||
|
||||
val shadowedDeclarationsFilter = if (runtimeReceiver != null)
|
||||
ShadowedDeclarationsFilter(bindingContext, resolutionFacade, position, runtimeReceiver)
|
||||
else
|
||||
ShadowedDeclarationsFilter.create(bindingContext, resolutionFacade, position, callTypeAndReceiver)
|
||||
|
||||
if (shadowedDeclarationsFilter != null) {
|
||||
variants = shadowedDeclarationsFilter.filter(variants)
|
||||
notImportedExtensions = shadowedDeclarationsFilter
|
||||
.createNonImportedDeclarationsFilter<CallableDescriptor>(importedDeclarations = variants)
|
||||
.invoke(notImportedExtensions)
|
||||
}
|
||||
|
||||
if (!configuration.javaGettersAndSetters) {
|
||||
variants = referenceVariantsHelper.filterOutJavaGettersAndSetters(variants)
|
||||
}
|
||||
|
||||
if (!configuration.dataClassComponentFunctions) {
|
||||
variants = variants.filter { !isDataClassComponentFunction(it) }
|
||||
}
|
||||
|
||||
return ReferenceVariants(variants, notImportedExtensions)
|
||||
}
|
||||
|
||||
private fun isDataClassComponentFunction(descriptor: DeclarationDescriptor): Boolean {
|
||||
return descriptor is FunctionDescriptor &&
|
||||
descriptor.isOperator &&
|
||||
DataClassDescriptorResolver.isComponentLike(descriptor.name) &&
|
||||
descriptor.kind == CallableMemberDescriptor.Kind.SYNTHESIZED
|
||||
}
|
||||
|
||||
protected fun referenceVariantsWithSingleFunctionTypeParameter(): ReferenceVariants? {
|
||||
val variants = referenceVariants ?: return null
|
||||
val filter: (DeclarationDescriptor) -> Boolean = { it is FunctionDescriptor && LookupElementFactory.hasSingleFunctionTypeParameter(it) }
|
||||
@@ -398,7 +301,11 @@ abstract class CompletionSession(
|
||||
if (runtimeType == null || runtimeType == type) return null
|
||||
|
||||
val expressionReceiver = ExpressionReceiver.create(explicitReceiver, runtimeType, bindingContext)
|
||||
val (variants, notImportedExtensions) = collectReferenceVariants(descriptorKindFilter!!, nameExpression!!, expressionReceiver)
|
||||
val (variants, notImportedExtensions) = ReferenceVariantsCollector(
|
||||
referenceVariantsHelper, indicesHelper(true), prefixMatcher,
|
||||
nameExpression!!, callTypeAndReceiver, resolutionFacade, bindingContext,
|
||||
importableFqNameClassifier, configuration, runtimeReceiver = expressionReceiver
|
||||
).collectReferenceVariants(descriptorKindFilter!!)
|
||||
val filteredVariants = filterVariantsForRuntimeReceiverType(variants, referenceVariants.imported)
|
||||
val filteredNotImportedExtensions = filterVariantsForRuntimeReceiverType(notImportedExtensions, referenceVariants.notImportedExtensions)
|
||||
|
||||
@@ -475,10 +382,4 @@ abstract class CompletionSession(
|
||||
|
||||
return callTypeAndReceiver to receiverTypes
|
||||
}
|
||||
|
||||
protected fun isImportableDescriptorImported(descriptor: DeclarationDescriptor): Boolean {
|
||||
val classification = importableFqNameClassifier.classify(descriptor.importableFqName!!, false)
|
||||
return classification != ImportableFqNameClassifier.Classification.notImported
|
||||
&& classification != ImportableFqNameClassifier.Classification.siblingImported
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.KotlinIcons
|
||||
import org.jetbrains.kotlin.idea.completion.handlers.CastReceiverInsertHandler
|
||||
import org.jetbrains.kotlin.idea.completion.handlers.WithTailInsertHandler
|
||||
import org.jetbrains.kotlin.idea.core.ImportableFqNameClassifier
|
||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||
@@ -401,3 +402,10 @@ fun LookupElement.decorateAsStaticMember(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun ImportableFqNameClassifier.isImportableDescriptorImported(descriptor: DeclarationDescriptor): Boolean {
|
||||
val classification = classify(descriptor.importableFqName!!, false)
|
||||
return classification != ImportableFqNameClassifier.Classification.notImported
|
||||
&& classification != ImportableFqNameClassifier.Classification.siblingImported
|
||||
}
|
||||
|
||||
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.PrefixMatcher
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.codeInsight.ReferenceVariantsHelper
|
||||
import org.jetbrains.kotlin.idea.core.ImportableFqNameClassifier
|
||||
import org.jetbrains.kotlin.idea.core.KotlinIndicesHelper
|
||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
|
||||
import org.jetbrains.kotlin.idea.util.ShadowedDeclarationsFilter
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DataClassDescriptorResolver
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.decapitalizeSmart
|
||||
|
||||
data class ReferenceVariants(val imported: Collection<DeclarationDescriptor>, val notImportedExtensions: Collection<CallableDescriptor>)
|
||||
|
||||
internal class ReferenceVariantsCollector(
|
||||
private val referenceVariantsHelper: ReferenceVariantsHelper,
|
||||
private val indicesHelper: KotlinIndicesHelper,
|
||||
private val prefixMatcher: PrefixMatcher,
|
||||
private val nameExpression: KtSimpleNameExpression,
|
||||
private val callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
private val resolutionFacade: ResolutionFacade,
|
||||
private val bindingContext: BindingContext,
|
||||
private val importableFqNameClassifier: ImportableFqNameClassifier,
|
||||
private val configuration: CompletionSessionConfiguration,
|
||||
private val runtimeReceiver: ExpressionReceiver? = null
|
||||
) {
|
||||
private val prefix = prefixMatcher.prefix
|
||||
private val descriptorNameFilter = prefixMatcher.asStringNameFilter()
|
||||
|
||||
fun collectReferenceVariants(descriptorKindFilter: DescriptorKindFilter): ReferenceVariants {
|
||||
val completeExtensionsFromIndices = descriptorKindFilter.kindMask.and(DescriptorKindFilter.CALLABLES_MASK) != 0
|
||||
&& callTypeAndReceiver !is CallTypeAndReceiver.IMPORT_DIRECTIVE
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val descriptorKindFilter = if (completeExtensionsFromIndices)
|
||||
descriptorKindFilter exclude TopLevelExtensionsExclude // handled via indices
|
||||
else
|
||||
descriptorKindFilter
|
||||
|
||||
fun getReferenceVariants(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> {
|
||||
return referenceVariantsHelper.getReferenceVariants(
|
||||
nameExpression,
|
||||
kindFilter,
|
||||
nameFilter,
|
||||
filterOutJavaGettersAndSetters = false,
|
||||
filterOutShadowed = false,
|
||||
excludeNonInitializedVariable = false,
|
||||
useReceiverType = runtimeReceiver?.type)
|
||||
}
|
||||
|
||||
var variants = getReferenceVariants(descriptorKindFilter, descriptorNameFilter.toNameFilter())
|
||||
|
||||
val getOrSetPrefix = listOf("get", "set", "ge", "se", "g", "s").firstOrNull { prefix.startsWith(it) }
|
||||
val additionalPropertyNameFilter: ((String) -> Boolean)? = run {
|
||||
getOrSetPrefix?.let { prefixMatcher.cloneWithPrefix(prefix.removePrefix(getOrSetPrefix).decapitalizeSmart()).asStringNameFilter() }
|
||||
}
|
||||
if (additionalPropertyNameFilter != null) {
|
||||
variants += getReferenceVariants(descriptorKindFilter.intersect(DescriptorKindFilter.VARIABLES),
|
||||
additionalPropertyNameFilter.toNameFilter())
|
||||
variants = variants.distinct()
|
||||
}
|
||||
|
||||
var notImportedExtensions: Collection<CallableDescriptor> = emptyList()
|
||||
if (completeExtensionsFromIndices) {
|
||||
val nameFilter = if (additionalPropertyNameFilter != null)
|
||||
descriptorNameFilter or additionalPropertyNameFilter
|
||||
else
|
||||
descriptorNameFilter
|
||||
val extensions = if (runtimeReceiver != null)
|
||||
indicesHelper.getCallableTopLevelExtensions(callTypeAndReceiver, listOf(runtimeReceiver.type), nameFilter)
|
||||
else
|
||||
indicesHelper.getCallableTopLevelExtensions(callTypeAndReceiver, nameExpression, bindingContext, nameFilter)
|
||||
|
||||
val pair = extensions.partition { importableFqNameClassifier.isImportableDescriptorImported(it) }
|
||||
variants += pair.first
|
||||
notImportedExtensions = pair.second
|
||||
}
|
||||
|
||||
val shadowedDeclarationsFilter = if (runtimeReceiver != null)
|
||||
ShadowedDeclarationsFilter(bindingContext, resolutionFacade, nameExpression, runtimeReceiver)
|
||||
else
|
||||
ShadowedDeclarationsFilter.create(bindingContext, resolutionFacade, nameExpression, callTypeAndReceiver)
|
||||
|
||||
if (shadowedDeclarationsFilter != null) {
|
||||
variants = shadowedDeclarationsFilter.filter(variants)
|
||||
notImportedExtensions = shadowedDeclarationsFilter
|
||||
.createNonImportedDeclarationsFilter<CallableDescriptor>(importedDeclarations = variants)
|
||||
.invoke(notImportedExtensions)
|
||||
}
|
||||
|
||||
if (!configuration.javaGettersAndSetters) {
|
||||
variants = referenceVariantsHelper.filterOutJavaGettersAndSetters(variants)
|
||||
}
|
||||
|
||||
if (!configuration.dataClassComponentFunctions) {
|
||||
variants = variants.filter { !isDataClassComponentFunction(it) }
|
||||
}
|
||||
|
||||
return ReferenceVariants(variants, notImportedExtensions)
|
||||
}
|
||||
|
||||
private object TopLevelExtensionsExclude : DescriptorKindExclude() {
|
||||
override fun excludes(descriptor: DeclarationDescriptor): Boolean {
|
||||
if (descriptor !is CallableMemberDescriptor) return false
|
||||
if (descriptor.extensionReceiverParameter == null) return false
|
||||
if (descriptor.kind != CallableMemberDescriptor.Kind.DECLARATION) return false /* do not filter out synthetic extensions */
|
||||
val containingPackage = descriptor.containingDeclaration as? PackageFragmentDescriptor ?: return false
|
||||
if (containingPackage.fqName.asString().startsWith("kotlinx.android.synthetic.")) return false // TODO: temporary solution for Android synthetic extensions
|
||||
return true
|
||||
}
|
||||
|
||||
override val fullyExcludedDescriptorKinds: Int
|
||||
get() = 0
|
||||
}
|
||||
|
||||
private fun isDataClassComponentFunction(descriptor: DeclarationDescriptor): Boolean {
|
||||
return descriptor is FunctionDescriptor &&
|
||||
descriptor.isOperator &&
|
||||
DataClassDescriptorResolver.isComponentLike(descriptor.name) &&
|
||||
descriptor.kind == CallableMemberDescriptor.Kind.SYNTHESIZED
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user