Fix completing members for receivers shadowed by DslMarker

#KT-20396 Fixed
This commit is contained in:
Pavel V. Talanov
2018-08-07 21:48:26 +02:00
parent 0c1d25d5ac
commit b59f134f78
12 changed files with 115 additions and 54 deletions
@@ -17,6 +17,7 @@
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.resolve.ResolutionFacade
@@ -177,14 +178,18 @@ class ReferenceVariantsHelper(
val containingDeclaration = resolutionScope.ownerDescriptor
val smartCastManager = resolutionFacade.frontendService<SmartCastManager>()
val implicitReceiverTypes = resolutionScope.getImplicitReceiversWithInstance().flatMap {
val languageVersionSettings = resolutionFacade.frontendService<LanguageVersionSettings>()
val implicitReceiverTypes = resolutionScope.getImplicitReceiversWithInstance(
languageVersionSettings.supportsFeature(LanguageFeature.DslMarkersSupport)
).flatMap {
smartCastManager.getSmartCastVariantsWithLessSpecificExcluded(
it.value,
bindingContext,
containingDeclaration,
dataFlowInfo,
resolutionFacade.frontendService<LanguageVersionSettings>(),
resolutionFacade.frontendService<DataFlowValueFactory>()
it.value,
bindingContext,
containingDeclaration,
dataFlowInfo,
languageVersionSettings,
resolutionFacade.frontendService<DataFlowValueFactory>()
)
}.toSet()
@@ -17,12 +17,12 @@
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.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression
import org.jetbrains.kotlin.psi.psiUtil.isImportDirectiveExpression
@@ -306,7 +306,9 @@ fun CallTypeAndReceiver<*, *>.receiverTypesWithIndex(
ExpressionReceiver.create(receiverExpression, receiverType, bindingContext)
}
val implicitReceiverValues = resolutionScope.getImplicitReceiversWithInstance().map { it.value }
val implicitReceiverValues = resolutionScope.getImplicitReceiversWithInstance(
excludeShadowedByDslMarkers = languageVersionSettings.supportsFeature(LanguageFeature.DslMarkersSupport)
).map { it.value }
val dataFlowInfo = bindingContext.getDataFlowInfoBefore(contextElement)
@@ -357,20 +359,3 @@ private fun receiverValueTypes(
listOf(receiverValue.type)
}
}
fun Collection<ReceiverType>.shadowedByDslMarkers(): Set<ReceiverType> {
val typesByDslScopes = LinkedHashMap<FqName, MutableList<ReceiverType>>()
this
.mapNotNull { receiver ->
val dslMarkers = receiver.extractDslMarkers()
(receiver to dslMarkers).takeIf { dslMarkers.isNotEmpty() }
}
.forEach { (v, dslMarkers) -> dslMarkers.forEach { typesByDslScopes.getOrPut(it, { mutableListOf() }) += v } }
val shadowedDslReceivers = mutableSetOf<ReceiverType>()
typesByDslScopes.flatMapTo(shadowedDslReceivers) { (_, v) -> v.asSequence().drop(1).asIterable() }
return shadowedDslReceivers
}
@@ -17,6 +17,7 @@
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
@@ -24,14 +25,16 @@ 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(): Collection<ReceiverParameterDescriptor>
= getImplicitReceiversWithInstanceToExpression().keys
fun LexicalScope.getImplicitReceiversWithInstance(excludeShadowedByDslMarkers: Boolean = false): Collection<ReceiverParameterDescriptor> =
getImplicitReceiversWithInstanceToExpression(excludeShadowedByDslMarkers).keys
interface ReceiverExpressionFactory {
val isImmediate: Boolean
@@ -48,9 +51,18 @@ fun LexicalScope.getFactoryForImplicitReceiverWithSubtypeOf(receiverType: Kotlin
?.value
}
fun LexicalScope.getImplicitReceiversWithInstanceToExpression(): Map<ReceiverParameterDescriptor, ReceiverExpressionFactory?> {
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(getImplicitReceiversHierarchy())
val receivers = LinkedHashSet(
if (excludeShadowedByDslMarkers) {
allReceivers - allReceivers.shadowedByDslMarkers()
} else {
allReceivers
}
)
val outerDeclarationsWithInstance = LinkedHashSet<DeclarationDescriptor>()
var current: DeclarationDescriptor? = ownerDescriptor
@@ -109,3 +121,17 @@ private fun thisQualifierName(receiver: ReceiverParameterDescriptor): Name? {
val functionLiteral = DescriptorToSourceUtils.descriptorToDeclaration(descriptor) as? KtFunctionLiteral
return functionLiteral?.findLabelAndCall()?.first
}
private fun List<ReceiverParameterDescriptor>.shadowedByDslMarkers(): Set<ReceiverParameterDescriptor> {
val typesByDslScopes = LinkedHashMap<FqName, MutableList<ReceiverParameterDescriptor>>()
this.mapNotNull { receiver ->
val dslMarkers = DslMarkerUtils.extractDslMarkerFqNames(receiver.value).all()
(receiver to dslMarkers).takeIf { dslMarkers.isNotEmpty() }
}.forEach { (v, dslMarkers) -> dslMarkers.forEach { typesByDslScopes.getOrPut(it, { mutableListOf() }) += v } }
val shadowedDslReceivers = mutableSetOf<ReceiverParameterDescriptor>()
typesByDslScopes.flatMapTo(shadowedDslReceivers) { (_, v) -> v.asSequence().drop(1).asIterable() }
return shadowedDslReceivers
}