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
}
@@ -406,18 +406,15 @@ abstract class CompletionSession(
nameExpression: KtSimpleNameExpression,
callTypeAndReceiver: CallTypeAndReceiver<*, *>): Collection<ReceiverType>? {
var receiverTypes = callTypeAndReceiver.receiverTypesWithIndex(
bindingContext, nameExpression, moduleDescriptor, resolutionFacade,
stableSmartCastsOnly = true, /* we don't include smart cast receiver types for "unstable" receiver value to mark members grayed */
withImplicitReceiversWhenExplicitPresent = true)
bindingContext, nameExpression, moduleDescriptor, resolutionFacade,
stableSmartCastsOnly = true, /* we don't include smart cast receiver types for "unstable" receiver value to mark members grayed */
withImplicitReceiversWhenExplicitPresent = true
)
if (callTypeAndReceiver is CallTypeAndReceiver.SAFE || isDebuggerContext) {
receiverTypes = receiverTypes?.map { ReceiverType(it.type.makeNotNullable(), it.receiverIndex) }
}
if (receiverTypes != null && nameExpression.languageVersionSettings.supportsFeature(LanguageFeature.DslMarkersSupport)) {
receiverTypes -= receiverTypes.shadowedByDslMarkers()
}
return receiverTypes
}
}
@@ -43,5 +43,5 @@ fun test() {
}
}
// EXIST: {"lookupString":"two", "attributes":""}
// EXIST: {"lookupString":"one", "attributes":["grayed"]}
// EXIST: two
// ABSENT: one
@@ -37,5 +37,5 @@ fun test() {
}
}
// EXIST: {"lookupString":"container", "attributes":["grayed"]}
// EXIST: {"lookupString":"child", "attributes":["grayed"]}
// ABSENT: container
// ABSENT: lookupString
@@ -42,7 +42,9 @@ class DslOtherChild {
@SimpleOtherDsl @SimpleDsl
class DslAnotherChild {
fun foo () {
}
}
fun dsl(body: DslRoot.() -> Unit) {
@@ -66,6 +68,7 @@ fun test() {
}
}
// EXIST: {lookupString:"otherThing", attributes:["grayed"]}
// EXIST: {lookupString:"child", attributes:["grayed"]}
// EXIST: {lookupString:"otherChild", attributes:["grayed"]}
// EXIST: foo
// ABSENT: otherThing
// ABSENT: child
// ABSENT: otherChild
@@ -34,5 +34,5 @@ fun test() {
}
}
// EXIST: {"lookupString":"child", "attributes":["bold"]}
// EXIST: {"lookupString":"container", "attributes":["grayed"]}
// EXIST: child
// ABSENT: container
@@ -0,0 +1,6 @@
package bar
import baz.*
fun B.booExtension() {}
fun A.booExtensionToA() {}
@@ -0,0 +1,35 @@
// RUNTIME
package baz
@DslMarker
annotation class Marker
@Marker
class A {
val booFromA = ""
fun booFromA2() {}
fun section(block: B.() -> Unit) {}
}
@Marker
class B {
fun booFromB() {}
}
fun x() {
A().apply {
section {
boo<caret>
}
}
}
fun booUnrelated() {
}
// ORDER: booFromB, booUnrelated, booleanArrayOf, booExtension
@@ -204,6 +204,11 @@ public class BasicCompletionWeigherTestGenerated extends AbstractBasicCompletion
runTest("idea/idea-completion/testData/weighers/basic/SuperMembers.kt");
}
@TestMetadata("UnavailableDslReceiver.kt")
public void testUnavailableDslReceiver() throws Exception {
runTest("idea/idea-completion/testData/weighers/basic/UnavailableDslReceiver.kt");
}
@TestMetadata("idea/idea-completion/testData/weighers/basic/expectedInfo")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -303,15 +303,14 @@ internal class ImportFix(expression: KtSimpleNameExpression) : OrdinaryImportFix
indicesHelper.getKotlinEnumsByName(name).filterTo(result, filterByCallType)
val resolutionFacade = element.getResolutionFacade()
var actualReceiverTypes = callTypeAndReceiver
.receiverTypesWithIndex(bindingContext, element,
resolutionFacade.moduleDescriptor, resolutionFacade,
stableSmartCastsOnly = false,
withImplicitReceiversWhenExplicitPresent = true).orEmpty()
val actualReceiverTypes = callTypeAndReceiver
.receiverTypesWithIndex(
bindingContext, element,
resolutionFacade.moduleDescriptor, resolutionFacade,
stableSmartCastsOnly = false,
withImplicitReceiversWhenExplicitPresent = true
).orEmpty()
if (element.languageVersionSettings.supportsFeature(LanguageFeature.DslMarkersSupport)) {
actualReceiverTypes -= actualReceiverTypes.shadowedByDslMarkers()
}
val explicitReceiverTypes = actualReceiverTypes.filterNot { it.implicit }