mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-03-10 08:31:29 +00:00
1/2 Preparation commit: move ide-common files which are required for scripting to separate directory
This commit is needed to preserve git history
This commit is contained in:
@@ -0,0 +1,494 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.codeInsight
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.FrontendInternals
|
||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.resolve.frontendService
|
||||
import org.jetbrains.kotlin.idea.util.*
|
||||
import org.jetbrains.kotlin.incremental.KotlinLookupLocation
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
||||
import org.jetbrains.kotlin.load.kotlin.toSourceElement
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager
|
||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||
import org.jetbrains.kotlin.resolve.scopes.*
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.collectAllFromMeAndParent
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.collectDescriptorsFiltered
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.memberScopeAsImportingScope
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
import org.jetbrains.kotlin.synthetic.JavaSyntheticScopes
|
||||
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
|
||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||
import java.util.*
|
||||
|
||||
@OptIn(FrontendInternals::class)
|
||||
class ReferenceVariantsHelper(
|
||||
private val bindingContext: BindingContext,
|
||||
private val resolutionFacade: ResolutionFacade,
|
||||
private val moduleDescriptor: ModuleDescriptor,
|
||||
private val visibilityFilter: (DeclarationDescriptor) -> Boolean,
|
||||
private val notProperties: Set<FqNameUnsafe> = setOf()
|
||||
) {
|
||||
fun getReferenceVariants(
|
||||
expression: KtSimpleNameExpression,
|
||||
kindFilter: DescriptorKindFilter,
|
||||
nameFilter: (Name) -> Boolean,
|
||||
filterOutJavaGettersAndSetters: Boolean = true,
|
||||
filterOutShadowed: Boolean = true,
|
||||
excludeNonInitializedVariable: Boolean = true,
|
||||
useReceiverType: KotlinType? = null
|
||||
): Collection<DeclarationDescriptor> = getReferenceVariants(
|
||||
expression, CallTypeAndReceiver.detect(expression),
|
||||
kindFilter, nameFilter, filterOutJavaGettersAndSetters, filterOutShadowed, excludeNonInitializedVariable, useReceiverType
|
||||
)
|
||||
|
||||
fun getReferenceVariants(
|
||||
contextElement: PsiElement,
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
kindFilter: DescriptorKindFilter,
|
||||
nameFilter: (Name) -> Boolean,
|
||||
filterOutJavaGettersAndSetters: Boolean = true,
|
||||
filterOutShadowed: Boolean = true,
|
||||
excludeNonInitializedVariable: Boolean = true,
|
||||
useReceiverType: KotlinType? = null
|
||||
): Collection<DeclarationDescriptor> {
|
||||
var variants: Collection<DeclarationDescriptor> =
|
||||
getReferenceVariantsNoVisibilityFilter(contextElement, kindFilter, nameFilter, callTypeAndReceiver, useReceiverType)
|
||||
.filter { !resolutionFacade.frontendService<DeprecationResolver>().isHiddenInResolution(it) && visibilityFilter(it) }
|
||||
|
||||
if (filterOutShadowed) {
|
||||
ShadowedDeclarationsFilter.create(bindingContext, resolutionFacade, contextElement, callTypeAndReceiver)?.let {
|
||||
variants = it.filter(variants)
|
||||
}
|
||||
}
|
||||
|
||||
if (filterOutJavaGettersAndSetters && kindFilter.kindMask.and(DescriptorKindFilter.FUNCTIONS_MASK) != 0) {
|
||||
variants = filterOutJavaGettersAndSetters(variants)
|
||||
}
|
||||
|
||||
if (excludeNonInitializedVariable && kindFilter.kindMask.and(DescriptorKindFilter.VARIABLES_MASK) != 0) {
|
||||
variants = excludeNonInitializedVariable(variants, contextElement)
|
||||
}
|
||||
|
||||
return variants
|
||||
}
|
||||
|
||||
fun <TDescriptor : DeclarationDescriptor> filterOutJavaGettersAndSetters(variants: Collection<TDescriptor>): Collection<TDescriptor> {
|
||||
val accessorMethodsToRemove = HashSet<FunctionDescriptor>()
|
||||
val filteredVariants = variants.filter { it !is SyntheticJavaPropertyDescriptor || !it.suppressedByNotPropertyList(notProperties) }
|
||||
|
||||
for (variant in filteredVariants) {
|
||||
if (variant is SyntheticJavaPropertyDescriptor) {
|
||||
accessorMethodsToRemove.add(variant.getMethod.original)
|
||||
|
||||
val setter = variant.setMethod
|
||||
if (setter != null && setter.returnType?.isUnit() == true) { // we do not filter out non-Unit setters
|
||||
accessorMethodsToRemove.add(setter.original)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return filteredVariants.filter { it !is FunctionDescriptor || it.original !in accessorMethodsToRemove }
|
||||
}
|
||||
|
||||
// filters out variable inside its initializer
|
||||
fun excludeNonInitializedVariable(
|
||||
variants: Collection<DeclarationDescriptor>,
|
||||
contextElement: PsiElement
|
||||
): Collection<DeclarationDescriptor> {
|
||||
for (element in contextElement.parentsWithSelf) {
|
||||
val parent = element.parent
|
||||
if (parent is KtVariableDeclaration && element == parent.initializer) {
|
||||
return variants.filter { it.findPsi() != parent }
|
||||
}
|
||||
if (element is KtDeclaration) break // we can use variable inside lambda or anonymous object located in its initializer
|
||||
}
|
||||
return variants
|
||||
}
|
||||
|
||||
private fun getReferenceVariantsNoVisibilityFilter(
|
||||
contextElement: PsiElement,
|
||||
kindFilter: DescriptorKindFilter,
|
||||
nameFilter: (Name) -> Boolean,
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
useReceiverType: KotlinType?
|
||||
): Collection<DeclarationDescriptor> {
|
||||
val callType = callTypeAndReceiver.callType
|
||||
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val kindFilter = kindFilter.intersect(callType.descriptorKindFilter)
|
||||
|
||||
val receiverExpression: KtExpression?
|
||||
when (callTypeAndReceiver) {
|
||||
is CallTypeAndReceiver.IMPORT_DIRECTIVE -> {
|
||||
return getVariantsForImportOrPackageDirective(callTypeAndReceiver.receiver, kindFilter, nameFilter)
|
||||
}
|
||||
|
||||
is CallTypeAndReceiver.PACKAGE_DIRECTIVE -> {
|
||||
return getVariantsForImportOrPackageDirective(callTypeAndReceiver.receiver, kindFilter, nameFilter)
|
||||
}
|
||||
|
||||
is CallTypeAndReceiver.TYPE -> {
|
||||
return getVariantsForUserType(callTypeAndReceiver.receiver, contextElement, kindFilter, nameFilter)
|
||||
}
|
||||
|
||||
is CallTypeAndReceiver.ANNOTATION -> {
|
||||
return getVariantsForUserType(callTypeAndReceiver.receiver, contextElement, kindFilter, nameFilter)
|
||||
}
|
||||
|
||||
is CallTypeAndReceiver.CALLABLE_REFERENCE -> {
|
||||
return getVariantsForCallableReference(callTypeAndReceiver, contextElement, useReceiverType, kindFilter, nameFilter)
|
||||
}
|
||||
|
||||
is CallTypeAndReceiver.DEFAULT -> receiverExpression = null
|
||||
is CallTypeAndReceiver.DOT -> receiverExpression = callTypeAndReceiver.receiver
|
||||
is CallTypeAndReceiver.SUPER_MEMBERS -> receiverExpression = callTypeAndReceiver.receiver
|
||||
is CallTypeAndReceiver.SAFE -> receiverExpression = callTypeAndReceiver.receiver
|
||||
is CallTypeAndReceiver.INFIX -> receiverExpression = callTypeAndReceiver.receiver
|
||||
is CallTypeAndReceiver.OPERATOR -> return emptyList()
|
||||
is CallTypeAndReceiver.UNKNOWN -> return emptyList()
|
||||
else -> throw RuntimeException() //TODO: see KT-9394
|
||||
}
|
||||
|
||||
val resolutionScope = contextElement.getResolutionScope(bindingContext, resolutionFacade)
|
||||
val dataFlowInfo = bindingContext.getDataFlowInfoBefore(contextElement)
|
||||
val containingDeclaration = resolutionScope.ownerDescriptor
|
||||
|
||||
val smartCastManager = resolutionFacade.frontendService<SmartCastManager>()
|
||||
val languageVersionSettings = resolutionFacade.frontendService<LanguageVersionSettings>()
|
||||
|
||||
val implicitReceiverTypes = resolutionScope.getImplicitReceiversWithInstance(
|
||||
languageVersionSettings.supportsFeature(LanguageFeature.DslMarkersSupport)
|
||||
).flatMap {
|
||||
smartCastManager.getSmartCastVariantsWithLessSpecificExcluded(
|
||||
it.value,
|
||||
bindingContext,
|
||||
containingDeclaration,
|
||||
dataFlowInfo,
|
||||
languageVersionSettings,
|
||||
resolutionFacade.frontendService<DataFlowValueFactory>()
|
||||
)
|
||||
}.toSet()
|
||||
|
||||
val descriptors = LinkedHashSet<DeclarationDescriptor>()
|
||||
|
||||
val filterWithoutExtensions = kindFilter exclude DescriptorKindExclude.Extensions
|
||||
if (receiverExpression != null) {
|
||||
val qualifier = bindingContext[BindingContext.QUALIFIER, receiverExpression]
|
||||
if (qualifier != null) {
|
||||
descriptors.addAll(qualifier.staticScope.collectStaticMembers(resolutionFacade, filterWithoutExtensions, nameFilter))
|
||||
}
|
||||
|
||||
val explicitReceiverTypes = if (useReceiverType != null) {
|
||||
listOf(useReceiverType)
|
||||
} else {
|
||||
callTypeAndReceiver.receiverTypes(
|
||||
bindingContext,
|
||||
contextElement,
|
||||
moduleDescriptor,
|
||||
resolutionFacade,
|
||||
stableSmartCastsOnly = false
|
||||
)!!
|
||||
}
|
||||
|
||||
descriptors.processAll(implicitReceiverTypes, explicitReceiverTypes, resolutionScope, callType, kindFilter, nameFilter)
|
||||
} else {
|
||||
assert(useReceiverType == null) { "'useReceiverType' parameter is not supported for implicit receiver" }
|
||||
|
||||
descriptors.processAll(implicitReceiverTypes, implicitReceiverTypes, resolutionScope, callType, kindFilter, nameFilter)
|
||||
|
||||
// add non-instance members
|
||||
descriptors.addAll(
|
||||
resolutionScope.collectDescriptorsFiltered(
|
||||
filterWithoutExtensions,
|
||||
nameFilter,
|
||||
changeNamesForAliased = true
|
||||
)
|
||||
)
|
||||
descriptors.addAll(resolutionScope.collectAllFromMeAndParent { scope ->
|
||||
scope.collectSyntheticStaticMembersAndConstructors(resolutionFacade, kindFilter, nameFilter)
|
||||
})
|
||||
}
|
||||
|
||||
if (callType == CallType.SUPER_MEMBERS) { // we need to unwrap fake overrides in case of "super." because ShadowedDeclarationsFilter does not work correctly
|
||||
return descriptors.flatMapTo(LinkedHashSet<DeclarationDescriptor>()) {
|
||||
if (it is CallableMemberDescriptor && it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE)
|
||||
it.overriddenDescriptors
|
||||
else
|
||||
listOf(it)
|
||||
}
|
||||
}
|
||||
|
||||
return descriptors
|
||||
}
|
||||
|
||||
private fun getVariantsForUserType(
|
||||
receiverExpression: KtExpression?,
|
||||
contextElement: PsiElement,
|
||||
kindFilter: DescriptorKindFilter,
|
||||
nameFilter: (Name) -> Boolean
|
||||
): Collection<DeclarationDescriptor> {
|
||||
if (receiverExpression != null) {
|
||||
val qualifier = bindingContext[BindingContext.QUALIFIER, receiverExpression] ?: return emptyList()
|
||||
return qualifier.staticScope.collectStaticMembers(resolutionFacade, kindFilter, nameFilter)
|
||||
} else {
|
||||
val scope = contextElement.getResolutionScope(bindingContext, resolutionFacade)
|
||||
return scope.collectDescriptorsFiltered(kindFilter, nameFilter, changeNamesForAliased = true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getVariantsForCallableReference(
|
||||
callTypeAndReceiver: CallTypeAndReceiver.CALLABLE_REFERENCE,
|
||||
contextElement: PsiElement,
|
||||
useReceiverType: KotlinType?,
|
||||
kindFilter: DescriptorKindFilter,
|
||||
nameFilter: (Name) -> Boolean
|
||||
): Collection<DeclarationDescriptor> {
|
||||
val descriptors = LinkedHashSet<DeclarationDescriptor>()
|
||||
|
||||
val resolutionScope = contextElement.getResolutionScope(bindingContext, resolutionFacade)
|
||||
|
||||
val receiver = callTypeAndReceiver.receiver
|
||||
if (receiver != null) {
|
||||
val isStatic = bindingContext[BindingContext.DOUBLE_COLON_LHS, receiver] is DoubleColonLHS.Type
|
||||
|
||||
val explicitReceiverTypes = if (useReceiverType != null) {
|
||||
listOf(useReceiverType)
|
||||
} else {
|
||||
callTypeAndReceiver.receiverTypes(
|
||||
bindingContext,
|
||||
contextElement,
|
||||
moduleDescriptor,
|
||||
resolutionFacade,
|
||||
stableSmartCastsOnly = false
|
||||
)!!
|
||||
}
|
||||
|
||||
val constructorFilter = { descriptor: ClassDescriptor -> if (isStatic) true else descriptor.isInner }
|
||||
descriptors.addNonExtensionMembers(explicitReceiverTypes, kindFilter, nameFilter, constructorFilter)
|
||||
|
||||
descriptors.addScopeAndSyntheticExtensions(
|
||||
resolutionScope,
|
||||
explicitReceiverTypes,
|
||||
CallType.CALLABLE_REFERENCE,
|
||||
kindFilter,
|
||||
nameFilter
|
||||
)
|
||||
|
||||
if (isStatic) {
|
||||
explicitReceiverTypes
|
||||
.mapNotNull { (it.constructor.declarationDescriptor as? ClassDescriptor)?.staticScope }
|
||||
.flatMapTo(descriptors) { it.collectStaticMembers(resolutionFacade, kindFilter, nameFilter) }
|
||||
}
|
||||
} else {
|
||||
// process non-instance members and class constructors
|
||||
descriptors.addNonExtensionCallablesAndConstructors(
|
||||
resolutionScope,
|
||||
kindFilter, nameFilter, constructorFilter = { !it.isInner },
|
||||
classesOnly = false
|
||||
)
|
||||
}
|
||||
return descriptors
|
||||
}
|
||||
|
||||
private fun getVariantsForImportOrPackageDirective(
|
||||
receiverExpression: KtExpression?,
|
||||
kindFilter: DescriptorKindFilter,
|
||||
nameFilter: (Name) -> Boolean
|
||||
): Collection<DeclarationDescriptor> {
|
||||
if (receiverExpression != null) {
|
||||
val qualifier = bindingContext[BindingContext.QUALIFIER, receiverExpression] ?: return emptyList()
|
||||
val staticDescriptors = qualifier.staticScope.collectStaticMembers(resolutionFacade, kindFilter, nameFilter)
|
||||
|
||||
val objectDescriptor =
|
||||
(qualifier as? ClassQualifier)?.descriptor?.takeIf { it.kind == ClassKind.OBJECT } ?: return staticDescriptors
|
||||
|
||||
return staticDescriptors + objectDescriptor.defaultType.memberScope.getDescriptorsFiltered(kindFilter, nameFilter)
|
||||
} else {
|
||||
val rootPackage = resolutionFacade.moduleDescriptor.getPackage(FqName.ROOT)
|
||||
return rootPackage.memberScope.getDescriptorsFiltered(kindFilter, nameFilter)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableSet<DeclarationDescriptor>.processAll(
|
||||
implicitReceiverTypes: Collection<KotlinType>,
|
||||
receiverTypes: Collection<KotlinType>,
|
||||
resolutionScope: LexicalScope,
|
||||
callType: CallType<*>,
|
||||
kindFilter: DescriptorKindFilter,
|
||||
nameFilter: (Name) -> Boolean
|
||||
) {
|
||||
addNonExtensionMembers(receiverTypes, kindFilter, nameFilter, constructorFilter = { it.isInner })
|
||||
addMemberExtensions(implicitReceiverTypes, receiverTypes, callType, kindFilter, nameFilter)
|
||||
addScopeAndSyntheticExtensions(resolutionScope, receiverTypes, callType, kindFilter, nameFilter)
|
||||
}
|
||||
|
||||
private fun MutableSet<DeclarationDescriptor>.addMemberExtensions(
|
||||
dispatchReceiverTypes: Collection<KotlinType>,
|
||||
extensionReceiverTypes: Collection<KotlinType>,
|
||||
callType: CallType<*>,
|
||||
kindFilter: DescriptorKindFilter,
|
||||
nameFilter: (Name) -> Boolean
|
||||
) {
|
||||
val memberFilter = kindFilter exclude DescriptorKindExclude.NonExtensions
|
||||
for (dispatchReceiverType in dispatchReceiverTypes) {
|
||||
for (member in dispatchReceiverType.memberScope.getDescriptorsFiltered(memberFilter, nameFilter)) {
|
||||
addAll((member as CallableDescriptor).substituteExtensionIfCallable(extensionReceiverTypes, callType))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableSet<DeclarationDescriptor>.addNonExtensionMembers(
|
||||
receiverTypes: Collection<KotlinType>,
|
||||
kindFilter: DescriptorKindFilter,
|
||||
nameFilter: (Name) -> Boolean,
|
||||
constructorFilter: (ClassDescriptor) -> Boolean
|
||||
) {
|
||||
for (receiverType in receiverTypes) {
|
||||
addNonExtensionCallablesAndConstructors(
|
||||
receiverType.memberScope.memberScopeAsImportingScope(),
|
||||
kindFilter, nameFilter, constructorFilter,
|
||||
false
|
||||
)
|
||||
receiverType.constructor.supertypes.forEach {
|
||||
addNonExtensionCallablesAndConstructors(
|
||||
it.memberScope.memberScopeAsImportingScope(),
|
||||
kindFilter, nameFilter, constructorFilter,
|
||||
true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableSet<DeclarationDescriptor>.addNonExtensionCallablesAndConstructors(
|
||||
scope: HierarchicalScope,
|
||||
kindFilter: DescriptorKindFilter,
|
||||
nameFilter: (Name) -> Boolean,
|
||||
constructorFilter: (ClassDescriptor) -> Boolean,
|
||||
classesOnly: Boolean
|
||||
) {
|
||||
var filterToUse =
|
||||
DescriptorKindFilter(kindFilter.kindMask and DescriptorKindFilter.CALLABLES.kindMask).exclude(DescriptorKindExclude.Extensions)
|
||||
|
||||
// should process classes if we need constructors
|
||||
if (filterToUse.acceptsKinds(DescriptorKindFilter.FUNCTIONS_MASK)) {
|
||||
filterToUse = filterToUse.withKinds(DescriptorKindFilter.NON_SINGLETON_CLASSIFIERS_MASK)
|
||||
}
|
||||
|
||||
for (descriptor in scope.collectDescriptorsFiltered(filterToUse, nameFilter, changeNamesForAliased = true)) {
|
||||
if (descriptor is ClassDescriptor) {
|
||||
if (descriptor.modality == Modality.ABSTRACT || descriptor.modality == Modality.SEALED) continue
|
||||
if (!constructorFilter(descriptor)) continue
|
||||
descriptor.constructors.filterTo(this) { kindFilter.accepts(it) }
|
||||
} else if (!classesOnly && kindFilter.accepts(descriptor)) {
|
||||
this.add(descriptor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableSet<DeclarationDescriptor>.addScopeAndSyntheticExtensions(
|
||||
scope: LexicalScope,
|
||||
receiverTypes: Collection<KotlinType>,
|
||||
callType: CallType<*>,
|
||||
kindFilter: DescriptorKindFilter,
|
||||
nameFilter: (Name) -> Boolean
|
||||
) {
|
||||
if (kindFilter.excludes.contains(DescriptorKindExclude.Extensions)) return
|
||||
if (receiverTypes.isEmpty()) return
|
||||
|
||||
fun process(extensionOrSyntheticMember: CallableDescriptor) {
|
||||
if (kindFilter.accepts(extensionOrSyntheticMember) && nameFilter(extensionOrSyntheticMember.name)) {
|
||||
if (extensionOrSyntheticMember.isExtension) {
|
||||
addAll(extensionOrSyntheticMember.substituteExtensionIfCallable(receiverTypes, callType))
|
||||
} else {
|
||||
add(extensionOrSyntheticMember)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (descriptor in scope.collectDescriptorsFiltered(
|
||||
kindFilter exclude DescriptorKindExclude.NonExtensions,
|
||||
nameFilter,
|
||||
changeNamesForAliased = true
|
||||
)) {
|
||||
// todo: sometimes resolution scope here is LazyJavaClassMemberScope. see ea.jetbrains.com/browser/ea_problems/72572
|
||||
process(descriptor as CallableDescriptor)
|
||||
}
|
||||
|
||||
val syntheticScopes = resolutionFacade.getFrontendService(SyntheticScopes::class.java).forceEnableSamAdapters()
|
||||
if (kindFilter.acceptsKinds(DescriptorKindFilter.VARIABLES_MASK)) {
|
||||
val lookupLocation = (scope.ownerDescriptor.toSourceElement.getPsi() as? KtElement)?.let { KotlinLookupLocation(it) }
|
||||
?: NoLookupLocation.FROM_IDE
|
||||
|
||||
for (extension in syntheticScopes.collectSyntheticExtensionProperties(receiverTypes, lookupLocation)) {
|
||||
process(extension)
|
||||
}
|
||||
}
|
||||
|
||||
if (kindFilter.acceptsKinds(DescriptorKindFilter.FUNCTIONS_MASK)) {
|
||||
for (syntheticMember in syntheticScopes.collectSyntheticMemberFunctions(receiverTypes)) {
|
||||
process(syntheticMember)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun MemberScope.collectStaticMembers(
|
||||
resolutionFacade: ResolutionFacade,
|
||||
kindFilter: DescriptorKindFilter,
|
||||
nameFilter: (Name) -> Boolean
|
||||
): Collection<DeclarationDescriptor> {
|
||||
return getDescriptorsFiltered(kindFilter, nameFilter) + collectSyntheticStaticMembersAndConstructors(
|
||||
resolutionFacade,
|
||||
kindFilter,
|
||||
nameFilter
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(FrontendInternals::class)
|
||||
fun ResolutionScope.collectSyntheticStaticMembersAndConstructors(
|
||||
resolutionFacade: ResolutionFacade,
|
||||
kindFilter: DescriptorKindFilter,
|
||||
nameFilter: (Name) -> Boolean
|
||||
): List<FunctionDescriptor> {
|
||||
val syntheticScopes = resolutionFacade.getFrontendService(SyntheticScopes::class.java)
|
||||
val functionDescriptors = getContributedDescriptors(DescriptorKindFilter.FUNCTIONS)
|
||||
val classifierDescriptors = getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS)
|
||||
return (syntheticScopes.forceEnableSamAdapters().collectSyntheticStaticFunctions(functionDescriptors) +
|
||||
syntheticScopes.collectSyntheticConstructors(classifierDescriptors))
|
||||
.filter { kindFilter.accepts(it) && nameFilter(it.name) }
|
||||
}
|
||||
|
||||
// New Inference disables scope with synthetic SAM-adapters because it uses conversions for resolution
|
||||
// However, sometimes we need to pretend that we have those synthetic members, for example:
|
||||
// - to show both option (with SAM-conversion signature, and without) in completion
|
||||
// - for various intentions and checks (see RedundantSamConstructorInspection, ConflictingExtensionPropertyIntention and other)
|
||||
// TODO(dsavvinov): review clients, rewrite them to not rely on synthetic adapetrs
|
||||
fun SyntheticScopes.forceEnableSamAdapters(): SyntheticScopes {
|
||||
return if (this !is JavaSyntheticScopes)
|
||||
this
|
||||
else
|
||||
object : SyntheticScopes {
|
||||
override val scopes: Collection<SyntheticScope> = this@forceEnableSamAdapters.scopesWithForceEnabledSamAdapters
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.resolve
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
import org.jetbrains.kotlin.analyzer.ResolverForProject
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.idea.FrontendInternals
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
|
||||
interface ResolutionFacade {
|
||||
val project: Project
|
||||
|
||||
fun analyze(element: KtElement, bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL): BindingContext
|
||||
fun analyze(elements: Collection<KtElement>, bodyResolveMode: BodyResolveMode): BindingContext
|
||||
|
||||
fun analyzeWithAllCompilerChecks(elements: Collection<KtElement>, callback: DiagnosticSink.DiagnosticsCallback? = null): AnalysisResult
|
||||
|
||||
fun resolveToDescriptor(declaration: KtDeclaration, bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL): DeclarationDescriptor
|
||||
|
||||
val moduleDescriptor: ModuleDescriptor
|
||||
|
||||
// get service for the module this resolution was created for
|
||||
@FrontendInternals
|
||||
fun <T : Any> getFrontendService(serviceClass: Class<T>): T
|
||||
|
||||
fun <T : Any> getIdeService(serviceClass: Class<T>): T
|
||||
|
||||
// get service for the module defined by PsiElement/ModuleDescriptor passed as parameter
|
||||
@FrontendInternals
|
||||
fun <T : Any> getFrontendService(element: PsiElement, serviceClass: Class<T>): T
|
||||
|
||||
@FrontendInternals
|
||||
fun <T : Any> tryGetFrontendService(element: PsiElement, serviceClass: Class<T>): T?
|
||||
|
||||
@FrontendInternals
|
||||
fun <T : Any> getFrontendService(moduleDescriptor: ModuleDescriptor, serviceClass: Class<T>): T
|
||||
|
||||
fun getResolverForProject(): ResolverForProject<out ModuleInfo>
|
||||
}
|
||||
|
||||
@FrontendInternals
|
||||
inline fun <reified T : Any> ResolutionFacade.frontendService(): T = this.getFrontendService(T::class.java)
|
||||
|
||||
inline fun <reified T : Any> ResolutionFacade.ideService(): T = this.getIdeService(T::class.java)
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.resolve
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.idea.FrontendInternals
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
|
||||
/**
|
||||
* Helper methods for commonly used frontend components.
|
||||
* Use them to avoid explicit opt-ins.
|
||||
* Before adding a new helper method please make sure component doesn't have fragile invariants that can be violated by external use.
|
||||
*/
|
||||
|
||||
@OptIn(FrontendInternals::class)
|
||||
fun ResolutionFacade.getLanguageVersionSettings(): LanguageVersionSettings =
|
||||
frontendService<LanguageVersionSettings>()
|
||||
|
||||
@OptIn(FrontendInternals::class)
|
||||
fun ResolutionFacade.getDataFlowValueFactory(): DataFlowValueFactory =
|
||||
frontendService<DataFlowValueFactory>()
|
||||
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.util
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.FrontendInternals
|
||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.resolve.frontendService
|
||||
import org.jetbrains.kotlin.idea.resolve.getDataFlowValueFactory
|
||||
import org.jetbrains.kotlin.idea.resolve.getLanguageVersionSettings
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isImportDirectiveExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isPackageDirectiveExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
|
||||
import org.jetbrains.kotlin.resolve.calls.DslMarkerUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.TypeAliasQualifier
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
|
||||
import org.jetbrains.kotlin.util.supertypesWithAny
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import java.util.*
|
||||
|
||||
sealed class CallType<TReceiver : KtElement?>(val descriptorKindFilter: DescriptorKindFilter) {
|
||||
object UNKNOWN : CallType<Nothing?>(DescriptorKindFilter.ALL)
|
||||
|
||||
object DEFAULT : CallType<Nothing?>(DescriptorKindFilter.ALL)
|
||||
|
||||
object DOT : CallType<KtExpression>(DescriptorKindFilter.ALL)
|
||||
|
||||
object SAFE : CallType<KtExpression>(DescriptorKindFilter.ALL)
|
||||
|
||||
object SUPER_MEMBERS : CallType<KtSuperExpression>(
|
||||
DescriptorKindFilter.CALLABLES exclude DescriptorKindExclude.Extensions exclude AbstractMembersExclude
|
||||
)
|
||||
|
||||
object INFIX : CallType<KtExpression>(DescriptorKindFilter.FUNCTIONS exclude NonInfixExclude)
|
||||
|
||||
object OPERATOR : CallType<KtExpression>(DescriptorKindFilter.FUNCTIONS exclude NonOperatorExclude)
|
||||
|
||||
object CALLABLE_REFERENCE : CallType<KtExpression?>(DescriptorKindFilter.CALLABLES exclude CallableReferenceExclude)
|
||||
|
||||
object IMPORT_DIRECTIVE : CallType<KtExpression?>(DescriptorKindFilter.ALL)
|
||||
|
||||
object PACKAGE_DIRECTIVE : CallType<KtExpression?>(DescriptorKindFilter.PACKAGES)
|
||||
|
||||
object TYPE : CallType<KtExpression?>(
|
||||
DescriptorKindFilter(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK)
|
||||
exclude DescriptorKindExclude.EnumEntry
|
||||
)
|
||||
|
||||
object DELEGATE : CallType<KtExpression?>(DescriptorKindFilter.FUNCTIONS exclude NonOperatorExclude)
|
||||
|
||||
object ANNOTATION : CallType<KtExpression?>(
|
||||
DescriptorKindFilter(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK)
|
||||
exclude NonAnnotationClassifierExclude
|
||||
)
|
||||
|
||||
private object NonInfixExclude : DescriptorKindExclude() {
|
||||
override fun excludes(descriptor: DeclarationDescriptor) =
|
||||
!(descriptor is SimpleFunctionDescriptor && descriptor.isInfix)
|
||||
|
||||
override val fullyExcludedDescriptorKinds: Int
|
||||
get() = 0
|
||||
}
|
||||
|
||||
private object NonOperatorExclude : DescriptorKindExclude() {
|
||||
override fun excludes(descriptor: DeclarationDescriptor) =
|
||||
!(descriptor is SimpleFunctionDescriptor && descriptor.isOperator)
|
||||
|
||||
override val fullyExcludedDescriptorKinds: Int
|
||||
get() = 0
|
||||
}
|
||||
|
||||
private object CallableReferenceExclude : DescriptorKindExclude() {
|
||||
override fun excludes(descriptor: DeclarationDescriptor) /* currently not supported for locals and synthetic */ =
|
||||
descriptor !is CallableMemberDescriptor || descriptor.kind == CallableMemberDescriptor.Kind.SYNTHESIZED
|
||||
|
||||
override val fullyExcludedDescriptorKinds: Int
|
||||
get() = 0
|
||||
}
|
||||
|
||||
private object NonAnnotationClassifierExclude : DescriptorKindExclude() {
|
||||
override fun excludes(descriptor: DeclarationDescriptor): Boolean {
|
||||
if (descriptor !is ClassifierDescriptor) return false
|
||||
return descriptor !is ClassDescriptor || descriptor.kind != ClassKind.ANNOTATION_CLASS
|
||||
}
|
||||
|
||||
override val fullyExcludedDescriptorKinds: Int get() = 0
|
||||
}
|
||||
|
||||
private object AbstractMembersExclude : DescriptorKindExclude() {
|
||||
override fun excludes(descriptor: DeclarationDescriptor) =
|
||||
descriptor is CallableMemberDescriptor && descriptor.modality == Modality.ABSTRACT
|
||||
|
||||
override val fullyExcludedDescriptorKinds: Int
|
||||
get() = 0
|
||||
}
|
||||
}
|
||||
|
||||
sealed class CallTypeAndReceiver<TReceiver : KtElement?, out TCallType : CallType<TReceiver>>(
|
||||
val callType: TCallType,
|
||||
val receiver: TReceiver
|
||||
) {
|
||||
object UNKNOWN : CallTypeAndReceiver<Nothing?, CallType.UNKNOWN>(CallType.UNKNOWN, null)
|
||||
object DEFAULT : CallTypeAndReceiver<Nothing?, CallType.DEFAULT>(CallType.DEFAULT, null)
|
||||
class DOT(receiver: KtExpression) : CallTypeAndReceiver<KtExpression, CallType.DOT>(CallType.DOT, receiver)
|
||||
class SAFE(receiver: KtExpression) : CallTypeAndReceiver<KtExpression, CallType.SAFE>(CallType.SAFE, receiver)
|
||||
class SUPER_MEMBERS(receiver: KtSuperExpression) : CallTypeAndReceiver<KtSuperExpression, CallType.SUPER_MEMBERS>(
|
||||
CallType.SUPER_MEMBERS, receiver
|
||||
)
|
||||
|
||||
class INFIX(receiver: KtExpression) : CallTypeAndReceiver<KtExpression, CallType.INFIX>(CallType.INFIX, receiver)
|
||||
class OPERATOR(receiver: KtExpression) : CallTypeAndReceiver<KtExpression, CallType.OPERATOR>(CallType.OPERATOR, receiver)
|
||||
class CALLABLE_REFERENCE(receiver: KtExpression?) : CallTypeAndReceiver<KtExpression?, CallType.CALLABLE_REFERENCE>(
|
||||
CallType.CALLABLE_REFERENCE, receiver
|
||||
)
|
||||
|
||||
class IMPORT_DIRECTIVE(receiver: KtExpression?) : CallTypeAndReceiver<KtExpression?, CallType.IMPORT_DIRECTIVE>(
|
||||
CallType.IMPORT_DIRECTIVE, receiver
|
||||
)
|
||||
|
||||
class PACKAGE_DIRECTIVE(receiver: KtExpression?) :
|
||||
CallTypeAndReceiver<KtExpression?, CallType.PACKAGE_DIRECTIVE>(CallType.PACKAGE_DIRECTIVE, receiver)
|
||||
|
||||
class TYPE(receiver: KtExpression?) : CallTypeAndReceiver<KtExpression?, CallType.TYPE>(CallType.TYPE, receiver)
|
||||
class DELEGATE(receiver: KtExpression?) : CallTypeAndReceiver<KtExpression?, CallType.DELEGATE>(CallType.DELEGATE, receiver)
|
||||
class ANNOTATION(receiver: KtExpression?) : CallTypeAndReceiver<KtExpression?, CallType.ANNOTATION>(CallType.ANNOTATION, receiver)
|
||||
|
||||
companion object {
|
||||
fun detect(expression: KtSimpleNameExpression): CallTypeAndReceiver<*, *> {
|
||||
val parent = expression.parent
|
||||
if (parent is KtCallableReferenceExpression && expression == parent.callableReference) {
|
||||
return CALLABLE_REFERENCE(parent.receiverExpression)
|
||||
}
|
||||
|
||||
val receiverExpression = expression.getReceiverExpression()
|
||||
|
||||
if (expression.isImportDirectiveExpression()) {
|
||||
return IMPORT_DIRECTIVE(receiverExpression)
|
||||
}
|
||||
|
||||
if (expression.isPackageDirectiveExpression()) {
|
||||
return PACKAGE_DIRECTIVE(receiverExpression)
|
||||
}
|
||||
|
||||
if (parent is KtUserType) {
|
||||
val constructorCallee = (parent.parent as? KtTypeReference)?.parent as? KtConstructorCalleeExpression
|
||||
if (constructorCallee != null && constructorCallee.parent is KtAnnotationEntry) {
|
||||
return ANNOTATION(receiverExpression)
|
||||
}
|
||||
|
||||
return TYPE(receiverExpression)
|
||||
}
|
||||
|
||||
when (expression) {
|
||||
is KtOperationReferenceExpression -> {
|
||||
if (receiverExpression == null) {
|
||||
return UNKNOWN // incomplete code
|
||||
}
|
||||
return when (parent) {
|
||||
is KtBinaryExpression -> {
|
||||
if (parent.operationToken == KtTokens.IDENTIFIER)
|
||||
INFIX(receiverExpression)
|
||||
else
|
||||
OPERATOR(receiverExpression)
|
||||
}
|
||||
|
||||
is KtUnaryExpression -> OPERATOR(receiverExpression)
|
||||
|
||||
else -> error("Unknown parent for JetOperationReferenceExpression: $parent with text '${parent.text}'")
|
||||
}
|
||||
}
|
||||
|
||||
is KtNameReferenceExpression -> {
|
||||
if (receiverExpression == null) {
|
||||
return DEFAULT
|
||||
}
|
||||
|
||||
if (receiverExpression is KtSuperExpression) {
|
||||
return SUPER_MEMBERS(receiverExpression)
|
||||
}
|
||||
|
||||
return when (parent) {
|
||||
is KtCallExpression -> {
|
||||
if ((parent.parent as KtQualifiedExpression).operationSign == KtTokens.SAFE_ACCESS)
|
||||
SAFE(receiverExpression)
|
||||
else
|
||||
DOT(receiverExpression)
|
||||
}
|
||||
|
||||
is KtQualifiedExpression -> {
|
||||
if (parent.operationSign == KtTokens.SAFE_ACCESS)
|
||||
SAFE(receiverExpression)
|
||||
else
|
||||
DOT(receiverExpression)
|
||||
}
|
||||
|
||||
else -> error("Unknown parent for JetNameReferenceExpression with receiver: $parent")
|
||||
}
|
||||
}
|
||||
|
||||
else -> return UNKNOWN
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class ReceiverType(
|
||||
val type: KotlinType,
|
||||
val receiverIndex: Int,
|
||||
val implicitValue: ReceiverValue? = null
|
||||
) {
|
||||
val implicit: Boolean get() = implicitValue != null
|
||||
|
||||
fun extractDslMarkers() =
|
||||
implicitValue?.let(DslMarkerUtils::extractDslMarkerFqNames)?.all()
|
||||
?: DslMarkerUtils.extractDslMarkerFqNames(type)
|
||||
}
|
||||
|
||||
fun CallTypeAndReceiver<*, *>.receiverTypes(
|
||||
bindingContext: BindingContext,
|
||||
contextElement: PsiElement,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
resolutionFacade: ResolutionFacade,
|
||||
stableSmartCastsOnly: Boolean
|
||||
): List<KotlinType>? {
|
||||
return receiverTypesWithIndex(bindingContext, contextElement, moduleDescriptor, resolutionFacade, stableSmartCastsOnly)?.map { it.type }
|
||||
}
|
||||
|
||||
fun CallTypeAndReceiver<*, *>.receiverTypesWithIndex(
|
||||
bindingContext: BindingContext,
|
||||
contextElement: PsiElement,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
resolutionFacade: ResolutionFacade,
|
||||
stableSmartCastsOnly: Boolean,
|
||||
withImplicitReceiversWhenExplicitPresent: Boolean = false
|
||||
): List<ReceiverType>? {
|
||||
val languageVersionSettings = resolutionFacade.getLanguageVersionSettings()
|
||||
|
||||
val receiverExpression: KtExpression?
|
||||
when (this) {
|
||||
is CallTypeAndReceiver.CALLABLE_REFERENCE -> {
|
||||
if (receiver != null) {
|
||||
return when (val lhs = bindingContext[BindingContext.DOUBLE_COLON_LHS, receiver] ?: return emptyList()) {
|
||||
is DoubleColonLHS.Type -> listOf(ReceiverType(lhs.type, 0))
|
||||
|
||||
is DoubleColonLHS.Expression -> {
|
||||
val receiverValue = ExpressionReceiver.create(receiver, lhs.type, bindingContext)
|
||||
receiverValueTypes(
|
||||
receiverValue, lhs.dataFlowInfo, bindingContext,
|
||||
moduleDescriptor, stableSmartCastsOnly,
|
||||
resolutionFacade
|
||||
).map { ReceiverType(it, 0) }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
is CallTypeAndReceiver.DEFAULT -> receiverExpression = null
|
||||
|
||||
is CallTypeAndReceiver.DOT -> receiverExpression = receiver
|
||||
is CallTypeAndReceiver.SAFE -> receiverExpression = receiver
|
||||
is CallTypeAndReceiver.INFIX -> receiverExpression = receiver
|
||||
is CallTypeAndReceiver.OPERATOR -> receiverExpression = receiver
|
||||
is CallTypeAndReceiver.DELEGATE -> receiverExpression = receiver
|
||||
|
||||
is CallTypeAndReceiver.SUPER_MEMBERS -> {
|
||||
val qualifier = receiver.superTypeQualifier
|
||||
return if (qualifier != null) {
|
||||
listOfNotNull(bindingContext.getType(receiver)).map { ReceiverType(it, 0) }
|
||||
} else {
|
||||
val resolutionScope = contextElement.getResolutionScope(bindingContext, resolutionFacade)
|
||||
val classDescriptor =
|
||||
resolutionScope.ownerDescriptor.parentsWithSelf.firstIsInstanceOrNull<ClassDescriptor>() ?: return emptyList()
|
||||
classDescriptor.typeConstructor.supertypesWithAny().map { ReceiverType(it, 0) }
|
||||
}
|
||||
}
|
||||
|
||||
is CallTypeAndReceiver.IMPORT_DIRECTIVE,
|
||||
is CallTypeAndReceiver.PACKAGE_DIRECTIVE,
|
||||
is CallTypeAndReceiver.TYPE,
|
||||
is CallTypeAndReceiver.ANNOTATION,
|
||||
is CallTypeAndReceiver.UNKNOWN ->
|
||||
return null
|
||||
}
|
||||
|
||||
val resolutionScope = contextElement.getResolutionScope(bindingContext, resolutionFacade)
|
||||
|
||||
val expressionReceiver = receiverExpression?.let {
|
||||
val receiverType =
|
||||
bindingContext.getType(receiverExpression) ?: (bindingContext.get(
|
||||
BindingContext.QUALIFIER,
|
||||
receiverExpression
|
||||
) as? ClassQualifier)?.descriptor?.classValueType ?: (bindingContext.get(
|
||||
BindingContext.QUALIFIER,
|
||||
receiverExpression
|
||||
) as? TypeAliasQualifier)?.classDescriptor?.classValueType ?: return emptyList()
|
||||
ExpressionReceiver.create(receiverExpression, receiverType, bindingContext)
|
||||
}
|
||||
|
||||
val implicitReceiverValues = resolutionScope.getImplicitReceiversWithInstance(
|
||||
excludeShadowedByDslMarkers = languageVersionSettings.supportsFeature(LanguageFeature.DslMarkersSupport)
|
||||
).map { it.value }
|
||||
|
||||
val dataFlowInfo = bindingContext.getDataFlowInfoBefore(contextElement)
|
||||
|
||||
val result = ArrayList<ReceiverType>()
|
||||
|
||||
var receiverIndex = 0
|
||||
|
||||
fun addReceiverType(receiverValue: ReceiverValue, implicit: Boolean) {
|
||||
val types = receiverValueTypes(
|
||||
receiverValue, dataFlowInfo, bindingContext, moduleDescriptor, stableSmartCastsOnly,
|
||||
resolutionFacade
|
||||
)
|
||||
|
||||
types.mapTo(result) { type -> ReceiverType(type, receiverIndex, receiverValue.takeIf { implicit }) }
|
||||
|
||||
receiverIndex++
|
||||
}
|
||||
if (withImplicitReceiversWhenExplicitPresent || expressionReceiver == null) {
|
||||
implicitReceiverValues.forEach { addReceiverType(it, true) }
|
||||
}
|
||||
if (expressionReceiver != null) {
|
||||
addReceiverType(expressionReceiver, false)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@OptIn(FrontendInternals::class)
|
||||
private fun receiverValueTypes(
|
||||
receiverValue: ReceiverValue,
|
||||
dataFlowInfo: DataFlowInfo,
|
||||
bindingContext: BindingContext,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
stableSmartCastsOnly: Boolean,
|
||||
resolutionFacade: ResolutionFacade
|
||||
): List<KotlinType> {
|
||||
val languageVersionSettings = resolutionFacade.getLanguageVersionSettings()
|
||||
val dataFlowValueFactory = resolutionFacade.getDataFlowValueFactory()
|
||||
val smartCastManager = resolutionFacade.frontendService<SmartCastManager>()
|
||||
val dataFlowValue = dataFlowValueFactory.createDataFlowValue(receiverValue, bindingContext, moduleDescriptor)
|
||||
return if (dataFlowValue.isStable || !stableSmartCastsOnly) { // we don't include smart cast receiver types for "unstable" receiver value to mark members grayed
|
||||
smartCastManager.getSmartCastVariantsWithLessSpecificExcluded(
|
||||
receiverValue,
|
||||
bindingContext,
|
||||
moduleDescriptor,
|
||||
dataFlowInfo,
|
||||
languageVersionSettings,
|
||||
dataFlowValueFactory
|
||||
)
|
||||
} else {
|
||||
listOf(receiverValue.type)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:JvmName("FuzzyTypeUtils")
|
||||
|
||||
package org.jetbrains.kotlin.idea.util
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.CallHandle
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.StrictEqualityTypeChecker
|
||||
import org.jetbrains.kotlin.types.typeUtil.*
|
||||
import java.util.*
|
||||
|
||||
fun CallableDescriptor.fuzzyReturnType() = returnType?.toFuzzyType(typeParameters)
|
||||
fun CallableDescriptor.fuzzyExtensionReceiverType() = extensionReceiverParameter?.type?.toFuzzyType(typeParameters)
|
||||
|
||||
fun FuzzyType.makeNotNullable() = type.makeNotNullable().toFuzzyType(freeParameters)
|
||||
fun FuzzyType.makeNullable() = type.makeNullable().toFuzzyType(freeParameters)
|
||||
fun FuzzyType.nullability() = type.nullability()
|
||||
|
||||
fun FuzzyType.isAlmostEverything(): Boolean {
|
||||
if (freeParameters.isEmpty()) return false
|
||||
val typeParameter = type.constructor.declarationDescriptor as? TypeParameterDescriptor ?: return false
|
||||
if (typeParameter !in freeParameters) return false
|
||||
return typeParameter.upperBounds.singleOrNull()?.isAnyOrNullableAny() ?: false
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces free parameters inside the type with corresponding type parameters of the class (when possible)
|
||||
*/
|
||||
fun FuzzyType.presentationType(): KotlinType {
|
||||
if (freeParameters.isEmpty()) return type
|
||||
|
||||
val map = HashMap<TypeConstructor, TypeProjection>()
|
||||
for ((argument, typeParameter) in type.arguments.zip(type.constructor.parameters)) {
|
||||
if (argument.projectionKind == Variance.INVARIANT) {
|
||||
val equalToFreeParameter = freeParameters.firstOrNull {
|
||||
StrictEqualityTypeChecker.strictEqualTypes(it.defaultType, argument.type.unwrap())
|
||||
} ?: continue
|
||||
|
||||
map[equalToFreeParameter.typeConstructor] = createProjection(typeParameter.defaultType, Variance.INVARIANT, null)
|
||||
}
|
||||
}
|
||||
val substitutor = TypeSubstitutor.create(map)
|
||||
return substitutor.substitute(type, Variance.INVARIANT)!!
|
||||
}
|
||||
|
||||
fun KotlinType.toFuzzyType(freeParameters: Collection<TypeParameterDescriptor>) = FuzzyType(this, freeParameters)
|
||||
|
||||
class FuzzyType(
|
||||
val type: KotlinType,
|
||||
freeParameters: Collection<TypeParameterDescriptor>
|
||||
) {
|
||||
val freeParameters: Set<TypeParameterDescriptor>
|
||||
|
||||
init {
|
||||
if (freeParameters.isNotEmpty()) {
|
||||
// we allow to pass type parameters from another function with the same original in freeParameters
|
||||
val usedTypeParameters = HashSet<TypeParameterDescriptor>().apply { addUsedTypeParameters(type) }
|
||||
if (usedTypeParameters.isNotEmpty()) {
|
||||
val originalFreeParameters = freeParameters.map { it.toOriginal() }.toSet()
|
||||
this.freeParameters = usedTypeParameters.filter { it.toOriginal() in originalFreeParameters }.toSet()
|
||||
} else {
|
||||
this.freeParameters = emptySet()
|
||||
}
|
||||
} else {
|
||||
this.freeParameters = emptySet()
|
||||
}
|
||||
}
|
||||
|
||||
// Diagnostic for EA-109046
|
||||
@Suppress("USELESS_ELVIS")
|
||||
private fun TypeParameterDescriptor.toOriginal(): TypeParameterDescriptor {
|
||||
val callableDescriptor = containingDeclaration as? CallableMemberDescriptor ?: return this
|
||||
val original = callableDescriptor.original ?: error("original = null for $callableDescriptor")
|
||||
val typeParameters = original.typeParameters ?: error("typeParameters = null for $original")
|
||||
return typeParameters[index]
|
||||
}
|
||||
|
||||
override fun equals(other: Any?) = other is FuzzyType && other.type == type && other.freeParameters == freeParameters
|
||||
|
||||
override fun hashCode() = type.hashCode()
|
||||
|
||||
private fun MutableSet<TypeParameterDescriptor>.addUsedTypeParameters(type: KotlinType) {
|
||||
val typeParameter = type.constructor.declarationDescriptor as? TypeParameterDescriptor
|
||||
if (typeParameter != null && add(typeParameter)) {
|
||||
typeParameter.upperBounds.forEach { addUsedTypeParameters(it) }
|
||||
}
|
||||
|
||||
for (argument in type.arguments) {
|
||||
if (!argument.isStarProjection) { // otherwise we can fall into infinite recursion
|
||||
addUsedTypeParameters(argument.type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun checkIsSubtypeOf(otherType: FuzzyType): TypeSubstitutor? = matchedSubstitutor(otherType, MatchKind.IS_SUBTYPE)
|
||||
|
||||
fun checkIsSuperTypeOf(otherType: FuzzyType): TypeSubstitutor? = matchedSubstitutor(otherType, MatchKind.IS_SUPERTYPE)
|
||||
|
||||
fun checkIsSubtypeOf(otherType: KotlinType): TypeSubstitutor? = checkIsSubtypeOf(otherType.toFuzzyType(emptyList()))
|
||||
|
||||
fun checkIsSuperTypeOf(otherType: KotlinType): TypeSubstitutor? = checkIsSuperTypeOf(otherType.toFuzzyType(emptyList()))
|
||||
|
||||
private enum class MatchKind {
|
||||
IS_SUBTYPE,
|
||||
IS_SUPERTYPE
|
||||
}
|
||||
|
||||
private fun matchedSubstitutor(otherType: FuzzyType, matchKind: MatchKind): TypeSubstitutor? {
|
||||
if (type.isError) return null
|
||||
if (otherType.type.isError) return null
|
||||
if (otherType.type.isUnit() && matchKind == MatchKind.IS_SUBTYPE) return TypeSubstitutor.EMPTY
|
||||
|
||||
fun KotlinType.checkInheritance(otherType: KotlinType): Boolean {
|
||||
return when (matchKind) {
|
||||
MatchKind.IS_SUBTYPE -> this.isSubtypeOf(otherType)
|
||||
MatchKind.IS_SUPERTYPE -> otherType.isSubtypeOf(this)
|
||||
}
|
||||
}
|
||||
|
||||
if (freeParameters.isEmpty() && otherType.freeParameters.isEmpty()) {
|
||||
return if (type.checkInheritance(otherType.type)) TypeSubstitutor.EMPTY else null
|
||||
}
|
||||
|
||||
val builder = ConstraintSystemBuilderImpl()
|
||||
val typeVariableSubstitutor = builder.registerTypeVariables(CallHandle.NONE, freeParameters + otherType.freeParameters)
|
||||
|
||||
val typeInSystem = typeVariableSubstitutor.substitute(type, Variance.INVARIANT)
|
||||
val otherTypeInSystem = typeVariableSubstitutor.substitute(otherType.type, Variance.INVARIANT)
|
||||
|
||||
when (matchKind) {
|
||||
MatchKind.IS_SUBTYPE ->
|
||||
builder.addSubtypeConstraint(typeInSystem, otherTypeInSystem, ConstraintPositionKind.RECEIVER_POSITION.position())
|
||||
MatchKind.IS_SUPERTYPE ->
|
||||
builder.addSubtypeConstraint(otherTypeInSystem, typeInSystem, ConstraintPositionKind.RECEIVER_POSITION.position())
|
||||
}
|
||||
|
||||
builder.fixVariables()
|
||||
|
||||
val constraintSystem = builder.build()
|
||||
|
||||
if (constraintSystem.status.hasContradiction()) return null
|
||||
|
||||
// currently ConstraintSystem return successful status in case there are problems with nullability
|
||||
// that's why we have to check subtyping manually
|
||||
val substitutor = constraintSystem.resultingSubstitutor
|
||||
val substitutedType = substitutor.substitute(type, Variance.INVARIANT) ?: return null
|
||||
if (substitutedType.isError) return TypeSubstitutor.EMPTY
|
||||
val otherSubstitutedType = substitutor.substitute(otherType.type, Variance.INVARIANT) ?: return null
|
||||
if (otherSubstitutedType.isError) return TypeSubstitutor.EMPTY
|
||||
if (!substitutedType.checkInheritance(otherSubstitutedType)) return null
|
||||
|
||||
val substitutorToKeepCapturedTypes = object : DelegatedTypeSubstitution(substitutor.substitution) {
|
||||
override fun approximateCapturedTypes() = false
|
||||
}.buildSubstitutor()
|
||||
|
||||
val substitutionMap: Map<TypeConstructor, TypeProjection> = constraintSystem.typeVariables
|
||||
.map { it.originalTypeParameter }
|
||||
.associateBy(
|
||||
keySelector = { it.typeConstructor },
|
||||
valueTransform = {
|
||||
val typeProjection = TypeProjectionImpl(Variance.INVARIANT, it.defaultType)
|
||||
val substitutedProjection = substitutorToKeepCapturedTypes.substitute(typeProjection)
|
||||
substitutedProjection?.takeUnless { ErrorUtils.containsUninferredParameter(it.type) } ?: typeProjection
|
||||
})
|
||||
return TypeConstructorSubstitution.createByConstructorsMap(substitutionMap, approximateCapturedTypes = true).buildSubstitutor()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun TypeSubstitution.hasConflictWith(other: TypeSubstitution, freeParameters: Collection<TypeParameterDescriptor>): Boolean {
|
||||
return freeParameters.any { parameter ->
|
||||
val type = parameter.defaultType
|
||||
val substituted1 = this[type] ?: return@any false
|
||||
val substituted2 = other[type] ?: return@any false
|
||||
!StrictEqualityTypeChecker.strictEqualTypes(
|
||||
substituted1.type.unwrap(),
|
||||
substituted2.type.unwrap()
|
||||
) || substituted1.projectionKind != substituted2.projectionKind
|
||||
}
|
||||
}
|
||||
|
||||
fun TypeSubstitutor.combineIfNoConflicts(other: TypeSubstitutor, freeParameters: Collection<TypeParameterDescriptor>): TypeSubstitutor? {
|
||||
if (this.substitution.hasConflictWith(other.substitution, freeParameters)) return null
|
||||
return TypeSubstitutor.createChainedSubstitutor(this.substitution, other.substitution)
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:JvmName("ImportsUtils")
|
||||
|
||||
package org.jetbrains.kotlin.idea.imports
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtImportDirective
|
||||
import org.jetbrains.kotlin.psi.KtReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
val DeclarationDescriptor.importableFqName: FqName?
|
||||
get() {
|
||||
if (!canBeReferencedViaImport()) return null
|
||||
return getImportableDescriptor().fqNameSafe
|
||||
}
|
||||
|
||||
fun DeclarationDescriptor.canBeReferencedViaImport(): Boolean {
|
||||
if (this is PackageViewDescriptor ||
|
||||
DescriptorUtils.isTopLevelDeclaration(this) ||
|
||||
this is CallableDescriptor && DescriptorUtils.isStaticDeclaration(this)
|
||||
) {
|
||||
return !name.isSpecial
|
||||
}
|
||||
|
||||
//Both TypeAliasDescriptor and ClassDescriptor
|
||||
val parentClassifier = containingDeclaration as? ClassifierDescriptorWithTypeParameters ?: return false
|
||||
if (!parentClassifier.canBeReferencedViaImport()) return false
|
||||
|
||||
return when (this) {
|
||||
is ConstructorDescriptor -> !parentClassifier.isInner // inner class constructors can't be referenced via import
|
||||
is ClassDescriptor, is TypeAliasDescriptor -> true
|
||||
else -> parentClassifier is ClassDescriptor && parentClassifier.kind == ClassKind.OBJECT
|
||||
}
|
||||
}
|
||||
|
||||
fun DeclarationDescriptor.canBeAddedToImport(): Boolean = this !is PackageViewDescriptor && canBeReferencedViaImport()
|
||||
|
||||
fun KotlinType.canBeReferencedViaImport(): Boolean {
|
||||
val descriptor = constructor.declarationDescriptor
|
||||
return descriptor != null && descriptor.canBeReferencedViaImport()
|
||||
}
|
||||
|
||||
// for cases when class qualifier refers companion object treats it like reference to class itself
|
||||
fun KtReferenceExpression.getImportableTargets(bindingContext: BindingContext): Collection<DeclarationDescriptor> {
|
||||
val targets = bindingContext[BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, this]?.let { listOf(it) }
|
||||
?: getReferenceTargets(bindingContext)
|
||||
return targets.map { it.getImportableDescriptor() }.toSet()
|
||||
}
|
||||
|
||||
fun KtImportDirective.canResolve(facade: ResolutionFacade): Boolean {
|
||||
return (importedReference?.getQualifiedElementSelector() as? KtSimpleNameExpression)?.let { nameExpression ->
|
||||
nameExpression.getImportableTargets(facade.analyze(nameExpression, BodyResolveMode.PARTIAL)).isNotEmpty()
|
||||
} ?: false
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.util
|
||||
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.overriddenTreeUniqueAsSequence
|
||||
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
|
||||
|
||||
fun FunctionDescriptor.shouldNotConvertToProperty(notProperties: Set<FqNameUnsafe>): Boolean {
|
||||
if (fqNameUnsafe in notProperties) return true
|
||||
return this.overriddenTreeUniqueAsSequence(false).any { fqNameUnsafe in notProperties }
|
||||
}
|
||||
|
||||
fun SyntheticJavaPropertyDescriptor.suppressedByNotPropertyList(set: Set<FqNameUnsafe>) =
|
||||
getMethod.shouldNotConvertToProperty(set) || setMethod?.shouldNotConvertToProperty(set) ?: false
|
||||
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.util
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.FrontendInternals
|
||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.resolve.frontendService
|
||||
import org.jetbrains.kotlin.idea.resolve.getDataFlowValueFactory
|
||||
import org.jetbrains.kotlin.idea.resolve.getLanguageVersionSettings
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
|
||||
import org.jetbrains.kotlin.resolve.calls.CallResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
|
||||
import org.jetbrains.kotlin.resolve.scopes.ExplicitImportsScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.addImportingScope
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.util.descriptorsEqualWithSubstitution
|
||||
import java.util.*
|
||||
|
||||
class ShadowedDeclarationsFilter(
|
||||
private val bindingContext: BindingContext,
|
||||
private val resolutionFacade: ResolutionFacade,
|
||||
private val context: PsiElement,
|
||||
private val explicitReceiverValue: ReceiverValue?
|
||||
) {
|
||||
companion object {
|
||||
fun create(
|
||||
bindingContext: BindingContext,
|
||||
resolutionFacade: ResolutionFacade,
|
||||
context: PsiElement,
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>
|
||||
): ShadowedDeclarationsFilter? {
|
||||
val receiverExpression = when (callTypeAndReceiver) {
|
||||
is CallTypeAndReceiver.DEFAULT -> null
|
||||
is CallTypeAndReceiver.DOT -> callTypeAndReceiver.receiver
|
||||
is CallTypeAndReceiver.SAFE -> callTypeAndReceiver.receiver
|
||||
is CallTypeAndReceiver.SUPER_MEMBERS -> callTypeAndReceiver.receiver
|
||||
is CallTypeAndReceiver.INFIX -> callTypeAndReceiver.receiver
|
||||
is CallTypeAndReceiver.TYPE, is CallTypeAndReceiver.ANNOTATION -> null // need filtering of classes with the same FQ-name
|
||||
else -> return null // TODO: support shadowed declarations filtering for callable references
|
||||
}
|
||||
|
||||
val explicitReceiverValue = receiverExpression?.let {
|
||||
val type = bindingContext.getType(it) ?: return null
|
||||
ExpressionReceiver.create(it, type, bindingContext)
|
||||
}
|
||||
return ShadowedDeclarationsFilter(bindingContext, resolutionFacade, context, explicitReceiverValue)
|
||||
}
|
||||
}
|
||||
|
||||
private val psiFactory = KtPsiFactory(resolutionFacade.project)
|
||||
private val dummyExpressionFactory = DummyExpressionFactory(psiFactory)
|
||||
|
||||
fun <TDescriptor : DeclarationDescriptor> filter(declarations: Collection<TDescriptor>): Collection<TDescriptor> =
|
||||
declarations.groupBy { signature(it) }.values.flatMap { group -> filterEqualSignatureGroup(group) }
|
||||
|
||||
fun <TDescriptor : DeclarationDescriptor> createNonImportedDeclarationsFilter(
|
||||
importedDeclarations: Collection<DeclarationDescriptor>
|
||||
): (Collection<TDescriptor>) -> Collection<TDescriptor> {
|
||||
val importedDeclarationsSet = importedDeclarations.toSet()
|
||||
val importedDeclarationsBySignature = importedDeclarationsSet.groupBy { signature(it) }
|
||||
|
||||
return filter@{ declarations ->
|
||||
// optimization
|
||||
if (declarations.size == 1 && importedDeclarationsBySignature[signature(declarations.single())] == null) return@filter declarations
|
||||
|
||||
val nonImportedDeclarations = declarations.filter { it !in importedDeclarationsSet }
|
||||
|
||||
val notShadowed = HashSet<DeclarationDescriptor>()
|
||||
// same signature non-imported declarations from different packages do not shadow each other
|
||||
for ((pair, group) in nonImportedDeclarations.groupBy { signature(it) to packageName(it) }) {
|
||||
val imported = importedDeclarationsBySignature[pair.first]
|
||||
val all = if (imported != null) group + imported else group
|
||||
notShadowed.addAll(filterEqualSignatureGroup(all, descriptorsToImport = group))
|
||||
}
|
||||
declarations.filter { it in notShadowed }
|
||||
}
|
||||
}
|
||||
|
||||
private fun signature(descriptor: DeclarationDescriptor): Any = when (descriptor) {
|
||||
is SimpleFunctionDescriptor -> FunctionSignature(descriptor)
|
||||
is VariableDescriptor -> descriptor.name
|
||||
is ClassDescriptor -> descriptor.importableFqName ?: descriptor
|
||||
else -> descriptor
|
||||
}
|
||||
|
||||
private fun packageName(descriptor: DeclarationDescriptor) = descriptor.importableFqName?.parent()
|
||||
|
||||
private fun <TDescriptor : DeclarationDescriptor> filterEqualSignatureGroup(
|
||||
descriptors: Collection<TDescriptor>,
|
||||
descriptorsToImport: Collection<TDescriptor> = emptyList()
|
||||
): Collection<TDescriptor> {
|
||||
if (descriptors.size == 1) return descriptors
|
||||
|
||||
val first = descriptors.firstOrNull {
|
||||
it is ClassDescriptor || it is ConstructorDescriptor || it is CallableDescriptor && !it.name.isSpecial
|
||||
} ?: return descriptors
|
||||
|
||||
if (first is ClassDescriptor) { // for classes with the same FQ-name we simply take the first one
|
||||
return listOf(first)
|
||||
}
|
||||
|
||||
val isFunction = first is FunctionDescriptor
|
||||
val name = when (first) {
|
||||
is ConstructorDescriptor -> first.constructedClass.name
|
||||
else -> first.name
|
||||
}
|
||||
val parameters = (first as CallableDescriptor).valueParameters
|
||||
|
||||
val dummyArgumentExpressions = dummyExpressionFactory.createDummyExpressions(parameters.size)
|
||||
|
||||
val bindingTrace = DelegatingBindingTrace(bindingContext, "Temporary trace for filtering shadowed declarations")
|
||||
for ((expression, parameter) in dummyArgumentExpressions.zip(parameters)) {
|
||||
bindingTrace.recordType(expression, parameter.varargElementType ?: parameter.type)
|
||||
bindingTrace.record(BindingContext.PROCESSED, expression, true)
|
||||
}
|
||||
|
||||
val firstVarargIndex = parameters.withIndex().firstOrNull { it.value.varargElementType != null }?.index
|
||||
val useNamedFromIndex =
|
||||
if (firstVarargIndex != null && firstVarargIndex != parameters.lastIndex) firstVarargIndex else parameters.size
|
||||
|
||||
class DummyArgument(val index: Int) : ValueArgument {
|
||||
private val expression = dummyArgumentExpressions[index]
|
||||
|
||||
private val argumentName: ValueArgumentName? = if (isNamed()) {
|
||||
object : ValueArgumentName {
|
||||
override val asName = parameters[index].name
|
||||
override val referenceExpression = null
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
override fun getArgumentExpression() = expression
|
||||
override fun isNamed() = index >= useNamedFromIndex
|
||||
override fun getArgumentName() = argumentName
|
||||
override fun asElement() = expression
|
||||
override fun getSpreadElement() = null
|
||||
override fun isExternal() = false
|
||||
}
|
||||
|
||||
val arguments = ArrayList<DummyArgument>()
|
||||
for (i in parameters.indices) {
|
||||
arguments.add(DummyArgument(i))
|
||||
}
|
||||
|
||||
val newCall = object : Call {
|
||||
//TODO: compiler crash (KT-8011)
|
||||
//val arguments = parameters.indices.map { DummyArgument(it) }
|
||||
val callee = psiFactory.createExpressionByPattern("$0", name, reformat = false)
|
||||
|
||||
override fun getCalleeExpression() = callee
|
||||
|
||||
override fun getValueArgumentList() = null
|
||||
|
||||
override fun getValueArguments() = arguments
|
||||
|
||||
override fun getFunctionLiteralArguments() = emptyList<LambdaArgument>()
|
||||
|
||||
override fun getTypeArguments() = emptyList<KtTypeProjection>()
|
||||
|
||||
override fun getTypeArgumentList() = null
|
||||
|
||||
override fun getDispatchReceiver() = null
|
||||
|
||||
override fun getCallOperationNode() = null
|
||||
|
||||
override fun getExplicitReceiver() = explicitReceiverValue
|
||||
|
||||
override fun getCallElement() = callee
|
||||
|
||||
override fun getCallType() = Call.CallType.DEFAULT
|
||||
}
|
||||
|
||||
var scope = context.getResolutionScope(bindingContext, resolutionFacade)
|
||||
|
||||
if (descriptorsToImport.isNotEmpty()) {
|
||||
scope = scope.addImportingScope(ExplicitImportsScope(descriptorsToImport))
|
||||
}
|
||||
|
||||
val dataFlowInfo = bindingContext.getDataFlowInfoBefore(context)
|
||||
val context = BasicCallResolutionContext.create(
|
||||
bindingTrace, scope, newCall, TypeUtils.NO_EXPECTED_TYPE, dataFlowInfo,
|
||||
ContextDependency.INDEPENDENT, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
|
||||
false, resolutionFacade.getLanguageVersionSettings(),
|
||||
resolutionFacade.getDataFlowValueFactory()
|
||||
)
|
||||
|
||||
@OptIn(FrontendInternals::class)
|
||||
val callResolver = resolutionFacade.frontendService<CallResolver>()
|
||||
val results = if (isFunction) callResolver.resolveFunctionCall(context) else callResolver.resolveSimpleProperty(context)
|
||||
val resultingDescriptors = results.resultingCalls.map { it.resultingDescriptor }
|
||||
val resultingOriginals = resultingDescriptors.mapTo(HashSet<DeclarationDescriptor>()) { it.original }
|
||||
val filtered = descriptors.filter { candidateDescriptor ->
|
||||
candidateDescriptor.original in resultingOriginals /* optimization */ && resultingDescriptors.any {
|
||||
descriptorsEqualWithSubstitution(
|
||||
it,
|
||||
candidateDescriptor
|
||||
)
|
||||
}
|
||||
}
|
||||
return if (filtered.isNotEmpty()) filtered else descriptors /* something went wrong, none of our declarations among resolve candidates, let's not filter anything */
|
||||
}
|
||||
|
||||
private class DummyExpressionFactory(val factory: KtPsiFactory) {
|
||||
private val expressions = ArrayList<KtExpression>()
|
||||
|
||||
fun createDummyExpressions(count: Int): List<KtExpression> {
|
||||
while (expressions.size < count) {
|
||||
expressions.add(factory.createExpression("dummy"))
|
||||
}
|
||||
return expressions.take(count)
|
||||
}
|
||||
}
|
||||
|
||||
private class FunctionSignature(val function: FunctionDescriptor) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other === this) return true
|
||||
if (other !is FunctionSignature) return false
|
||||
if (function.name != other.function.name) return false
|
||||
val parameters1 = function.valueParameters
|
||||
val parameters2 = other.function.valueParameters
|
||||
if (parameters1.size != parameters2.size) return false
|
||||
for (i in parameters1.indices) {
|
||||
val p1 = parameters1[i]
|
||||
val p2 = parameters2[i]
|
||||
if (p1.varargElementType != p2.varargElementType) return false // both should be vararg or or both not
|
||||
if (p1.type != p2.type) return false
|
||||
}
|
||||
|
||||
val typeParameters1 = function.typeParameters
|
||||
val typeParameters2 = other.function.typeParameters
|
||||
if (typeParameters1.size != typeParameters2.size) return false
|
||||
for (i in typeParameters1.indices) {
|
||||
val t1 = typeParameters1[i]
|
||||
val t2 = typeParameters2[i]
|
||||
if (t1.upperBounds != t2.upperBounds) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode() = function.name.hashCode() * 17 + function.valueParameters.size
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:JvmName("TypeUtils")
|
||||
|
||||
package org.jetbrains.kotlin.idea.util
|
||||
|
||||
import com.intellij.psi.*
|
||||
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType
|
||||
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMapper
|
||||
import org.jetbrains.kotlin.builtins.replaceReturnType
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.idea.FrontendInternals
|
||||
import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport
|
||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.load.java.components.TypeUsage
|
||||
import org.jetbrains.kotlin.load.java.lazy.JavaResolverComponents
|
||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
|
||||
import org.jetbrains.kotlin.load.java.lazy.TypeParameterResolver
|
||||
import org.jetbrains.kotlin.load.java.lazy.child
|
||||
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaTypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.load.java.lazy.types.JavaTypeAttributes
|
||||
import org.jetbrains.kotlin.load.java.lazy.types.JavaTypeResolver
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaTypeImpl
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaTypeParameterImpl
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.*
|
||||
import org.jetbrains.kotlin.utils.SmartSet
|
||||
|
||||
fun KotlinType.approximateFlexibleTypes(
|
||||
preferNotNull: Boolean = false,
|
||||
preferStarForRaw: Boolean = false
|
||||
): KotlinType {
|
||||
if (isDynamic()) return this
|
||||
return unwrapEnhancement().approximateNonDynamicFlexibleTypes(preferNotNull, preferStarForRaw)
|
||||
}
|
||||
|
||||
private fun KotlinType.approximateNonDynamicFlexibleTypes(
|
||||
preferNotNull: Boolean = false,
|
||||
preferStarForRaw: Boolean = false
|
||||
): SimpleType {
|
||||
if (this is ErrorType) return this
|
||||
|
||||
if (isFlexible()) {
|
||||
val flexible = asFlexibleType()
|
||||
val lowerClass = flexible.lowerBound.constructor.declarationDescriptor as? ClassDescriptor?
|
||||
val isCollection = lowerClass != null && JavaToKotlinClassMapper.isMutable(lowerClass)
|
||||
// (Mutable)Collection<T>! -> MutableCollection<T>?
|
||||
// Foo<(Mutable)Collection<T>!>! -> Foo<Collection<T>>?
|
||||
// Foo! -> Foo?
|
||||
// Foo<Bar!>! -> Foo<Bar>?
|
||||
var approximation =
|
||||
if (isCollection)
|
||||
flexible.lowerBound.makeNullableAsSpecified(!preferNotNull)
|
||||
else
|
||||
if (this is RawType && preferStarForRaw) flexible.upperBound.makeNullableAsSpecified(!preferNotNull)
|
||||
else
|
||||
if (preferNotNull) flexible.lowerBound else flexible.upperBound
|
||||
|
||||
approximation = approximation.approximateNonDynamicFlexibleTypes()
|
||||
|
||||
approximation = if (nullability() == TypeNullability.NOT_NULL) approximation.makeNullableAsSpecified(false) else approximation
|
||||
|
||||
if (approximation.isMarkedNullable && !flexible.lowerBound
|
||||
.isMarkedNullable && TypeUtils.isTypeParameter(approximation) && TypeUtils.hasNullableSuperType(approximation)
|
||||
) {
|
||||
approximation = approximation.makeNullableAsSpecified(false)
|
||||
}
|
||||
|
||||
return approximation
|
||||
}
|
||||
|
||||
(unwrap() as? AbbreviatedType)?.let {
|
||||
return AbbreviatedType(it.expandedType, it.abbreviation.approximateNonDynamicFlexibleTypes(preferNotNull))
|
||||
}
|
||||
return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(
|
||||
annotations,
|
||||
constructor,
|
||||
arguments.map { it.substitute { type -> type.approximateFlexibleTypes(preferNotNull = true) } },
|
||||
isMarkedNullable,
|
||||
ErrorUtils.createErrorScope("This type is not supposed to be used in member resolution", true)
|
||||
)
|
||||
}
|
||||
|
||||
fun KotlinType.isResolvableInScope(scope: LexicalScope?, checkTypeParameters: Boolean, allowIntersections: Boolean = false): Boolean {
|
||||
if (constructor is IntersectionTypeConstructor) {
|
||||
if (!allowIntersections) return false
|
||||
return constructor.supertypes.all { it.isResolvableInScope(scope, checkTypeParameters, allowIntersections) }
|
||||
}
|
||||
|
||||
if (canBeReferencedViaImport()) return true
|
||||
|
||||
val descriptor = constructor.declarationDescriptor
|
||||
if (descriptor == null || descriptor.name.isSpecial) return false
|
||||
if (!checkTypeParameters && descriptor is TypeParameterDescriptor) return true
|
||||
|
||||
return scope != null && scope.findClassifier(descriptor.name, NoLookupLocation.FROM_IDE) == descriptor
|
||||
}
|
||||
|
||||
fun KotlinType.approximateWithResolvableType(scope: LexicalScope?, checkTypeParameters: Boolean): KotlinType {
|
||||
if (isError || isResolvableInScope(scope, checkTypeParameters)) return this
|
||||
return supertypes().firstOrNull { it.isResolvableInScope(scope, checkTypeParameters) }
|
||||
?: builtIns.anyType
|
||||
}
|
||||
|
||||
fun KotlinType.anonymousObjectSuperTypeOrNull(): KotlinType? {
|
||||
val classDescriptor = constructor.declarationDescriptor
|
||||
if (classDescriptor != null && DescriptorUtils.isAnonymousObject(classDescriptor)) {
|
||||
return immediateSupertypes().firstOrNull() ?: classDescriptor.builtIns.anyType
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun KotlinType.getResolvableApproximations(
|
||||
scope: LexicalScope?,
|
||||
checkTypeParameters: Boolean,
|
||||
allowIntersections: Boolean = false
|
||||
): Sequence<KotlinType> {
|
||||
return (listOf(this) + TypeUtils.getAllSupertypes(this))
|
||||
.asSequence()
|
||||
.mapNotNull {
|
||||
it.asTypeProjection()
|
||||
.fixTypeProjection(scope, checkTypeParameters, allowIntersections, isOutVariance = true)
|
||||
?.type
|
||||
}
|
||||
}
|
||||
|
||||
private fun TypeProjection.fixTypeProjection(
|
||||
scope: LexicalScope?,
|
||||
checkTypeParameters: Boolean,
|
||||
allowIntersections: Boolean,
|
||||
isOutVariance: Boolean
|
||||
): TypeProjection? {
|
||||
if (!type.isResolvableInScope(scope, checkTypeParameters, allowIntersections)) return null
|
||||
if (type.arguments.isEmpty()) return this
|
||||
|
||||
val resolvableArgs = type.arguments.filterTo(SmartSet.create()) { typeProjection ->
|
||||
typeProjection.type.isResolvableInScope(scope, checkTypeParameters, allowIntersections)
|
||||
}
|
||||
|
||||
if (resolvableArgs.containsAll(type.arguments)) {
|
||||
fun fixArguments(type: KotlinType): KotlinType? = type.replace(
|
||||
(type.arguments zip type.constructor.parameters).map { (arg, param) ->
|
||||
if (arg.isStarProjection) arg
|
||||
else arg.fixTypeProjection(
|
||||
scope,
|
||||
checkTypeParameters,
|
||||
allowIntersections,
|
||||
isOutVariance = isOutVariance && param.variance == Variance.OUT_VARIANCE
|
||||
) ?: when {
|
||||
!isOutVariance -> return null
|
||||
param.variance == Variance.OUT_VARIANCE -> arg.type.approximateWithResolvableType(
|
||||
scope,
|
||||
checkTypeParameters
|
||||
).asTypeProjection()
|
||||
else -> type.replaceArgumentsWithStarProjections().arguments.first()
|
||||
}
|
||||
})
|
||||
|
||||
return if (type.isBuiltinFunctionalType) {
|
||||
val returnType = type.getReturnTypeFromFunctionType()
|
||||
type.replaceReturnType(fixArguments(returnType) ?: return null).asTypeProjection()
|
||||
} else fixArguments(type)?.asTypeProjection()
|
||||
}
|
||||
|
||||
if (!isOutVariance) return null
|
||||
|
||||
val newArguments = (type.arguments zip type.constructor.parameters).map { (arg, param) ->
|
||||
when {
|
||||
arg in resolvableArgs -> arg
|
||||
|
||||
arg.projectionKind == Variance.OUT_VARIANCE ||
|
||||
param.variance == Variance.OUT_VARIANCE -> TypeProjectionImpl(
|
||||
arg.projectionKind,
|
||||
arg.type.approximateWithResolvableType(scope, checkTypeParameters)
|
||||
)
|
||||
|
||||
else -> return if (isOutVariance) type.replaceArgumentsWithStarProjections().asTypeProjection() else null
|
||||
}
|
||||
}
|
||||
|
||||
return type.replace(newArguments).asTypeProjection()
|
||||
}
|
||||
|
||||
fun KotlinType.isAbstract(): Boolean {
|
||||
val modality = (constructor.declarationDescriptor as? ClassDescriptor)?.modality
|
||||
return modality == Modality.ABSTRACT || modality == Modality.SEALED
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: this is a very shaky implementation of [PsiType] to [KotlinType] conversion,
|
||||
* produced types are fakes and are usable only for code generation. Please be careful using this method.
|
||||
*/
|
||||
@OptIn(FrontendInternals::class)
|
||||
fun PsiType.resolveToKotlinType(resolutionFacade: ResolutionFacade): KotlinType {
|
||||
if (this == PsiType.NULL) {
|
||||
return resolutionFacade.moduleDescriptor.builtIns.nullableAnyType
|
||||
}
|
||||
|
||||
val typeParameters = collectTypeParameters()
|
||||
val components = resolutionFacade.getFrontendService(JavaResolverComponents::class.java)
|
||||
val rootContext = LazyJavaResolverContext(components, TypeParameterResolver.EMPTY) { null }
|
||||
val dummyPackageDescriptor = MutablePackageFragmentDescriptor(resolutionFacade.moduleDescriptor, FqName("dummy"))
|
||||
val dummyClassDescriptor = ClassDescriptorImpl(
|
||||
dummyPackageDescriptor,
|
||||
Name.identifier("Dummy"),
|
||||
Modality.FINAL,
|
||||
ClassKind.CLASS,
|
||||
emptyList(),
|
||||
SourceElement.NO_SOURCE,
|
||||
false,
|
||||
LockBasedStorageManager.NO_LOCKS
|
||||
)
|
||||
val typeParameterResolver = object : TypeParameterResolver {
|
||||
override fun resolveTypeParameter(javaTypeParameter: JavaTypeParameter): TypeParameterDescriptor? {
|
||||
val psiTypeParameter = (javaTypeParameter as JavaTypeParameterImpl).psi
|
||||
val index = typeParameters.indexOf(psiTypeParameter)
|
||||
if (index < 0) return null
|
||||
return LazyJavaTypeParameterDescriptor(rootContext.child(this), javaTypeParameter, index, dummyClassDescriptor)
|
||||
}
|
||||
}
|
||||
val typeResolver = JavaTypeResolver(rootContext, typeParameterResolver)
|
||||
val attributes = JavaTypeAttributes(TypeUsage.COMMON)
|
||||
return typeResolver.transformJavaType(JavaTypeImpl.create(this), attributes).approximateFlexibleTypes(preferNotNull = true)
|
||||
}
|
||||
|
||||
|
||||
private fun PsiType.collectTypeParameters(): List<PsiTypeParameter> {
|
||||
val results = ArrayList<PsiTypeParameter>()
|
||||
accept(
|
||||
object : PsiTypeVisitor<Unit>() {
|
||||
override fun visitArrayType(arrayType: PsiArrayType) {
|
||||
arrayType.componentType.accept(this)
|
||||
}
|
||||
|
||||
override fun visitClassType(classType: PsiClassType) {
|
||||
(classType.resolve() as? PsiTypeParameter)?.let { results += it }
|
||||
classType.parameters.forEach { it.accept(this) }
|
||||
}
|
||||
|
||||
override fun visitWildcardType(wildcardType: PsiWildcardType) {
|
||||
wildcardType.bound?.accept(this)
|
||||
}
|
||||
}
|
||||
)
|
||||
return results
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.util
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.types.FlexibleType
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
|
||||
|
||||
fun SmartCastManager.getSmartCastVariantsWithLessSpecificExcluded(
|
||||
receiverToCast: ReceiverValue,
|
||||
bindingContext: BindingContext,
|
||||
containingDeclarationOrModule: DeclarationDescriptor,
|
||||
dataFlowInfo: DataFlowInfo,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
dataFlowValueFactory: DataFlowValueFactory
|
||||
): List<KotlinType> {
|
||||
val variants = getSmartCastVariants(
|
||||
receiverToCast,
|
||||
bindingContext,
|
||||
containingDeclarationOrModule,
|
||||
dataFlowInfo,
|
||||
languageVersionSettings,
|
||||
dataFlowValueFactory
|
||||
)
|
||||
return variants.filter { type ->
|
||||
variants.all { another -> another === type || chooseMoreSpecific(type, another).let { it == null || it === type } }
|
||||
}
|
||||
}
|
||||
|
||||
private fun chooseMoreSpecific(type1: KotlinType, type2: KotlinType): KotlinType? {
|
||||
val type1IsSubtype = KotlinTypeChecker.DEFAULT.isSubtypeOf(type1, type2)
|
||||
val type2IsSubtype = KotlinTypeChecker.DEFAULT.isSubtypeOf(type2, type1)
|
||||
|
||||
when {
|
||||
type1IsSubtype && !type2IsSubtype -> return type1
|
||||
|
||||
type2IsSubtype && !type1IsSubtype -> return type2
|
||||
|
||||
!type1IsSubtype && !type2IsSubtype -> return null
|
||||
|
||||
else -> { // type1IsSubtype && type2IsSubtype
|
||||
val flexible1 = type1.unwrap() as? FlexibleType
|
||||
val flexible2 = type2.unwrap() as? FlexibleType
|
||||
return when {
|
||||
flexible1 != null && flexible2 == null -> type2
|
||||
flexible2 != null && flexible1 == null -> type1
|
||||
else -> null //TODO?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:JvmName("ExtensionUtils")
|
||||
|
||||
package org.jetbrains.kotlin.idea.util
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtPsiUtil
|
||||
import org.jetbrains.kotlin.psi.KtReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtThisExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.typeUtil.TypeNullability
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
import org.jetbrains.kotlin.types.typeUtil.nullability
|
||||
|
||||
fun <TCallable : CallableDescriptor> TCallable.substituteExtensionIfCallable(
|
||||
receiverTypes: Collection<KotlinType>,
|
||||
callType: CallType<*>
|
||||
): Collection<TCallable> {
|
||||
if (!callType.descriptorKindFilter.accepts(this)) return listOf()
|
||||
|
||||
var types = receiverTypes.asSequence()
|
||||
if (callType == CallType.SAFE) {
|
||||
types = types.map { it.makeNotNullable() }
|
||||
}
|
||||
|
||||
val extensionReceiverType = fuzzyExtensionReceiverType()!!
|
||||
val substitutors = types.mapNotNull {
|
||||
var substitutor = extensionReceiverType.checkIsSuperTypeOf(it)
|
||||
// check if we may fail due to receiver expression being nullable
|
||||
if (substitutor == null && it.nullability() == TypeNullability.NULLABLE && extensionReceiverType.nullability() == TypeNullability.NOT_NULL) {
|
||||
substitutor = extensionReceiverType.checkIsSuperTypeOf(it.makeNotNullable())
|
||||
}
|
||||
substitutor
|
||||
}
|
||||
return if (typeParameters.isEmpty()) { // optimization for non-generic callables
|
||||
if (substitutors.any()) listOf(this) else listOf()
|
||||
} else {
|
||||
substitutors
|
||||
.mapNotNull { @Suppress("UNCHECKED_CAST") (substitute(it) as TCallable?) }
|
||||
.toList()
|
||||
}
|
||||
}
|
||||
|
||||
fun ReceiverValue?.getThisReceiverOwner(bindingContext: BindingContext): DeclarationDescriptor? {
|
||||
return when (this) {
|
||||
is ExpressionReceiver -> {
|
||||
val thisRef = (KtPsiUtil.deparenthesize(this.expression) as? KtThisExpression)?.instanceReference ?: return null
|
||||
bindingContext[BindingContext.REFERENCE_TARGET, thisRef]
|
||||
}
|
||||
|
||||
is ImplicitReceiver -> this.declarationDescriptor
|
||||
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun ReceiverValue?.getReceiverTargetDescriptor(bindingContext: BindingContext): DeclarationDescriptor? = when (this) {
|
||||
is ExpressionReceiver -> when (val expression = KtPsiUtil.deparenthesize(this.expression)) {
|
||||
is KtThisExpression -> expression.instanceReference
|
||||
is KtReferenceExpression -> expression
|
||||
else -> null
|
||||
}?.let { referenceExpression ->
|
||||
bindingContext[BindingContext.REFERENCE_TARGET, referenceExpression]
|
||||
}
|
||||
|
||||
is ImplicitReceiver -> this.declarationDescriptor
|
||||
|
||||
else -> null
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.util
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtFunctionLiteral
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.renderer.render
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.DslMarkerUtils
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.getImplicitReceiversHierarchy
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||
import java.util.*
|
||||
import kotlin.collections.LinkedHashSet
|
||||
|
||||
fun LexicalScope.getImplicitReceiversWithInstance(excludeShadowedByDslMarkers: Boolean = false): Collection<ReceiverParameterDescriptor> =
|
||||
getImplicitReceiversWithInstanceToExpression(excludeShadowedByDslMarkers).keys
|
||||
|
||||
interface ReceiverExpressionFactory {
|
||||
val isImmediate: Boolean
|
||||
val expressionText: String
|
||||
fun createExpression(psiFactory: KtPsiFactory, shortThis: Boolean = true): KtExpression
|
||||
}
|
||||
|
||||
fun LexicalScope.getFactoryForImplicitReceiverWithSubtypeOf(receiverType: KotlinType): ReceiverExpressionFactory? =
|
||||
getImplicitReceiversWithInstanceToExpression().entries.firstOrNull { (receiverDescriptor, _) ->
|
||||
receiverDescriptor.type.isSubtypeOf(receiverType)
|
||||
}?.value
|
||||
|
||||
fun LexicalScope.getImplicitReceiversWithInstanceToExpression(
|
||||
excludeShadowedByDslMarkers: Boolean = false
|
||||
): Map<ReceiverParameterDescriptor, ReceiverExpressionFactory?> {
|
||||
val allReceivers = getImplicitReceiversHierarchy()
|
||||
// we use a set to workaround a bug with receiver for companion object present twice in the result of getImplicitReceiversHierarchy()
|
||||
val receivers = LinkedHashSet(
|
||||
if (excludeShadowedByDslMarkers) {
|
||||
allReceivers - allReceivers.shadowedByDslMarkers()
|
||||
} else {
|
||||
allReceivers
|
||||
}
|
||||
)
|
||||
|
||||
val outerDeclarationsWithInstance = LinkedHashSet<DeclarationDescriptor>()
|
||||
var current: DeclarationDescriptor? = ownerDescriptor
|
||||
while (current != null) {
|
||||
if (current is PropertyAccessorDescriptor) {
|
||||
current = current.correspondingProperty
|
||||
}
|
||||
outerDeclarationsWithInstance.add(current)
|
||||
|
||||
val classDescriptor = current as? ClassDescriptor
|
||||
if (classDescriptor != null && !classDescriptor.isInner && !DescriptorUtils.isLocal(classDescriptor)) break
|
||||
|
||||
current = current.containingDeclaration
|
||||
}
|
||||
|
||||
val result = LinkedHashMap<ReceiverParameterDescriptor, ReceiverExpressionFactory?>()
|
||||
for ((index, receiver) in receivers.withIndex()) {
|
||||
val owner = receiver.containingDeclaration
|
||||
if (owner is ScriptDescriptor) {
|
||||
result[receiver] = null
|
||||
outerDeclarationsWithInstance.addAll(owner.implicitReceivers)
|
||||
continue
|
||||
}
|
||||
val (expressionText, isImmediateThis) = if (owner in outerDeclarationsWithInstance) {
|
||||
val thisWithLabel = thisQualifierName(receiver)?.let { "this@${it.render()}" }
|
||||
if (index == 0)
|
||||
(thisWithLabel ?: "this") to true
|
||||
else
|
||||
thisWithLabel to false
|
||||
} else if (owner is ClassDescriptor && owner.kind.isSingleton) {
|
||||
IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(owner) to false
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
val factory = if (expressionText != null)
|
||||
object : ReceiverExpressionFactory {
|
||||
override val isImmediate = isImmediateThis
|
||||
override val expressionText: String get() = expressionText
|
||||
override fun createExpression(psiFactory: KtPsiFactory, shortThis: Boolean): KtExpression {
|
||||
return psiFactory.createExpression(if (shortThis && isImmediateThis) "this" else expressionText)
|
||||
}
|
||||
}
|
||||
else
|
||||
null
|
||||
result[receiver] = factory
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun thisQualifierName(receiver: ReceiverParameterDescriptor): Name? {
|
||||
val descriptor = receiver.containingDeclaration
|
||||
val name = descriptor.name
|
||||
if (!name.isSpecial) return name
|
||||
|
||||
val functionLiteral = DescriptorToSourceUtils.descriptorToDeclaration(descriptor) as? KtFunctionLiteral
|
||||
return functionLiteral?.findLabelAndCall()?.first
|
||||
}
|
||||
|
||||
private fun List<ReceiverParameterDescriptor>.shadowedByDslMarkers(): Set<ReceiverParameterDescriptor> {
|
||||
val typesByDslScopes = mutableMapOf<FqName, MutableList<ReceiverParameterDescriptor>>()
|
||||
|
||||
for (receiver in this) {
|
||||
val dslMarkers = DslMarkerUtils.extractDslMarkerFqNames(receiver.value).all()
|
||||
for (marker in dslMarkers) {
|
||||
typesByDslScopes.getOrPut(marker) { mutableListOf() } += receiver
|
||||
}
|
||||
}
|
||||
|
||||
// for each DSL marker, all receivers except the closest one are shadowed by it; that is why we drop it
|
||||
return typesByDslScopes.values.flatMapTo(mutableSetOf()) { it.drop(1) }
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:JvmName("ScopeUtils")
|
||||
|
||||
package org.jetbrains.kotlin.idea.util
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.idea.FrontendInternals
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.resolve.frontendService
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtClassBody
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.resolve.lazy.FileScopeProvider
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.collectFunctions
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.collectVariables
|
||||
|
||||
|
||||
fun LexicalScope.getAllAccessibleVariables(name: Name): Collection<VariableDescriptor> {
|
||||
return getVariablesFromImplicitReceivers(name) + collectVariables(name, NoLookupLocation.FROM_IDE)
|
||||
}
|
||||
|
||||
fun LexicalScope.getAllAccessibleFunctions(name: Name): Collection<FunctionDescriptor> {
|
||||
return getImplicitReceiversWithInstance().flatMap {
|
||||
it.type.memberScope.getContributedFunctions(name, NoLookupLocation.FROM_IDE)
|
||||
} + collectFunctions(name, NoLookupLocation.FROM_IDE)
|
||||
}
|
||||
|
||||
fun LexicalScope.getVariablesFromImplicitReceivers(name: Name): Collection<VariableDescriptor> =
|
||||
getImplicitReceiversWithInstance().flatMap {
|
||||
it.type.memberScope.getContributedVariables(name, NoLookupLocation.FROM_IDE)
|
||||
}
|
||||
|
||||
fun LexicalScope.getVariableFromImplicitReceivers(name: Name): VariableDescriptor? {
|
||||
getImplicitReceiversWithInstance().forEach {
|
||||
it.type.memberScope.getContributedVariables(name, NoLookupLocation.FROM_IDE).singleOrNull()?.let { return it }
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun PsiElement.getResolutionScope(bindingContext: BindingContext): LexicalScope? {
|
||||
for (parent in parentsWithSelf) {
|
||||
if (parent is KtElement) {
|
||||
val scope = bindingContext[BindingContext.LEXICAL_SCOPE, parent]
|
||||
if (scope != null) return scope
|
||||
}
|
||||
|
||||
if (parent is KtClassBody) {
|
||||
val classDescriptor = bindingContext[BindingContext.CLASS, parent.getParent()] as? ClassDescriptorWithResolutionScopes
|
||||
if (classDescriptor != null) {
|
||||
return classDescriptor.scopeForMemberDeclarationResolution
|
||||
}
|
||||
}
|
||||
if (parent is KtFile) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun PsiElement.getResolutionScope(
|
||||
bindingContext: BindingContext,
|
||||
resolutionFacade: ResolutionFacade/*TODO: get rid of this parameter*/
|
||||
): LexicalScope = getResolutionScope(bindingContext) ?: when (containingFile) {
|
||||
is KtFile -> resolutionFacade.getFileResolutionScope(containingFile as KtFile)
|
||||
else -> error("Not in KtFile")
|
||||
}
|
||||
|
||||
fun KtElement.getResolutionScope(): LexicalScope {
|
||||
val resolutionFacade = getResolutionFacade()
|
||||
val context = resolutionFacade.analyze(this, BodyResolveMode.FULL)
|
||||
return getResolutionScope(context, resolutionFacade)
|
||||
}
|
||||
|
||||
@OptIn(FrontendInternals::class)
|
||||
fun ResolutionFacade.getFileResolutionScope(file: KtFile): LexicalScope {
|
||||
return frontendService<FileScopeProvider>().getFileResolutionScope(file)
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.scopes
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.Printer
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
|
||||
class ExplicitImportsScope(private val descriptors: Collection<DeclarationDescriptor>) : BaseImportingScope(null) {
|
||||
override fun getContributedClassifier(name: Name, location: LookupLocation) =
|
||||
descriptors.filter { it.name == name }.firstIsInstanceOrNull<ClassifierDescriptor>()
|
||||
|
||||
override fun getContributedPackage(name: Name) = descriptors.filter { it.name == name }.firstIsInstanceOrNull<PackageViewDescriptor>()
|
||||
|
||||
override fun getContributedVariables(name: Name, location: LookupLocation) =
|
||||
descriptors.filter { it.name == name }.filterIsInstance<VariableDescriptor>()
|
||||
|
||||
override fun getContributedFunctions(name: Name, location: LookupLocation) =
|
||||
descriptors.filter { it.name == name }.filterIsInstance<FunctionDescriptor>()
|
||||
|
||||
override fun getContributedDescriptors(
|
||||
kindFilter: DescriptorKindFilter,
|
||||
nameFilter: (Name) -> Boolean,
|
||||
changeNamesForAliased: Boolean
|
||||
) = descriptors
|
||||
|
||||
override fun computeImportedNames() = descriptors.mapTo(hashSetOf()) { it.name }
|
||||
|
||||
override fun printStructure(p: Printer) {
|
||||
p.println(this::class.java.name)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.util
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.CONFLICT
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE
|
||||
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeConstructor
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeCheckerImpl
|
||||
import org.jetbrains.kotlin.types.typeUtil.equalTypesOrNulls
|
||||
|
||||
fun descriptorsEqualWithSubstitution(
|
||||
descriptor1: DeclarationDescriptor?,
|
||||
descriptor2: DeclarationDescriptor?,
|
||||
checkOriginals: Boolean = true
|
||||
): Boolean {
|
||||
if (descriptor1 == descriptor2) return true
|
||||
if (descriptor1 == null || descriptor2 == null) return false
|
||||
if (checkOriginals && descriptor1.original != descriptor2.original) return false
|
||||
if (descriptor1 !is CallableDescriptor) return true
|
||||
descriptor2 as CallableDescriptor
|
||||
|
||||
val typeChecker = KotlinTypeCheckerImpl.withAxioms(object : KotlinTypeChecker.TypeConstructorEquality {
|
||||
override fun equals(a: TypeConstructor, b: TypeConstructor): Boolean {
|
||||
val typeParam1 = a.declarationDescriptor as? TypeParameterDescriptor
|
||||
val typeParam2 = b.declarationDescriptor as? TypeParameterDescriptor
|
||||
if (typeParam1 != null
|
||||
&& typeParam2 != null
|
||||
&& typeParam1.containingDeclaration == descriptor1
|
||||
&& typeParam2.containingDeclaration == descriptor2
|
||||
) {
|
||||
return typeParam1.index == typeParam2.index
|
||||
}
|
||||
|
||||
return a == b
|
||||
}
|
||||
})
|
||||
|
||||
if (!typeChecker.equalTypesOrNulls(descriptor1.returnType, descriptor2.returnType)) return false
|
||||
|
||||
val parameters1 = descriptor1.valueParameters
|
||||
val parameters2 = descriptor2.valueParameters
|
||||
if (parameters1.size != parameters2.size) return false
|
||||
for ((param1, param2) in parameters1.zip(parameters2)) {
|
||||
if (!typeChecker.equalTypes(param1.type, param2.type)) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun ClassDescriptor.findCallableMemberBySignature(
|
||||
signature: CallableMemberDescriptor,
|
||||
allowOverridabilityConflicts: Boolean = false
|
||||
): CallableMemberDescriptor? {
|
||||
val descriptorKind = if (signature is FunctionDescriptor) DescriptorKindFilter.FUNCTIONS else DescriptorKindFilter.VARIABLES
|
||||
return defaultType.memberScope
|
||||
.getContributedDescriptors(descriptorKind)
|
||||
.filterIsInstance<CallableMemberDescriptor>()
|
||||
.firstOrNull {
|
||||
if (it.containingDeclaration != this) return@firstOrNull false
|
||||
val overridability = OverridingUtil.DEFAULT.isOverridableBy(it as CallableDescriptor, signature, null).result
|
||||
overridability == OVERRIDABLE || (allowOverridabilityConflicts && overridability == CONFLICT)
|
||||
}
|
||||
}
|
||||
|
||||
fun TypeConstructor.supertypesWithAny(): Collection<KotlinType> {
|
||||
val supertypes = supertypes
|
||||
val noSuperClass = supertypes.map { it.constructor.declarationDescriptor as? ClassDescriptor }.all {
|
||||
it == null || it.kind == ClassKind.INTERFACE
|
||||
}
|
||||
return if (noSuperClass) supertypes + builtIns.anyType else supertypes
|
||||
}
|
||||
|
||||
val ClassifierDescriptorWithTypeParameters.constructors: Collection<ConstructorDescriptor>
|
||||
get() = when (this) {
|
||||
is TypeAliasDescriptor -> this.constructors
|
||||
is ClassDescriptor -> this.constructors
|
||||
else -> emptyList()
|
||||
}
|
||||
|
||||
val ClassifierDescriptorWithTypeParameters.kind: ClassKind?
|
||||
get() = when (this) {
|
||||
is TypeAliasDescriptor -> classDescriptor?.kind
|
||||
is ClassDescriptor -> kind
|
||||
else -> null
|
||||
}
|
||||
|
||||
val DeclarationDescriptor.isJavaDescriptor
|
||||
get() = this is JavaClassDescriptor || this is JavaCallableMemberDescriptor
|
||||
Reference in New Issue
Block a user