Fix completing members for receivers shadowed by DslMarker
#KT-20396 Fixed
This commit is contained in:
+12
-7
@@ -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
|
||||
+5
@@ -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 }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user