[PSI, FE, PSI2IR] Use labels for referencing specific receiver
This commit is contained in:
committed by
TeamCityServer
parent
aaabf5e1ca
commit
1bcaeabd84
+1
-1
@@ -167,7 +167,7 @@ class SyntheticClassOrObjectDescriptor(
|
||||
override fun getPrimaryConstructorModifierList(): KtModifierList? = null
|
||||
override fun getPrimaryConstructorParameters(): List<KtParameter> = emptyList()
|
||||
override fun getSecondaryConstructors(): List<KtSecondaryConstructor> = emptyList()
|
||||
override fun getContextReceiverTypeReferences(): List<KtTypeReference> = emptyList()
|
||||
override fun getContextReceivers(): List<KtContextReceiver> = emptyList()
|
||||
|
||||
override fun getPsiOrParent() = _parent.psiOrParent
|
||||
override fun getParent() = _parent.psiOrParent
|
||||
|
||||
@@ -48,6 +48,8 @@ import org.jetbrains.kotlin.util.slicedMap.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.jetbrains.kotlin.util.slicedMap.RewritePolicy.DO_NOTHING;
|
||||
import static org.jetbrains.kotlin.util.slicedMap.Slices.COMPILE_TIME_VALUE_REWRITE_POLICY;
|
||||
@@ -262,6 +264,7 @@ public interface BindingContext {
|
||||
.setFurtherLookupSlices(DECLARATIONS_TO_DESCRIPTORS)
|
||||
.build();
|
||||
|
||||
WritableSlice<DeclarationDescriptor, LinkedHashMap<ReceiverParameterDescriptor, String>> DESCRIPTOR_TO_NAMED_RECEIVERS = Slices.createSimpleSlice();
|
||||
WritableSlice<KtReferenceExpression, PsiElement> LABEL_TARGET = Slices.createSimpleSlice();
|
||||
WritableSlice<KtReferenceExpression, Collection<? extends PsiElement>> AMBIGUOUS_LABEL_TARGET = Slices.createSimpleSlice();
|
||||
WritableSlice<ValueParameterDescriptor, PropertyDescriptor> VALUE_PARAMETER_AS_PROPERTY = Slices.createSimpleSlice();
|
||||
|
||||
@@ -1023,7 +1023,8 @@ public class BodyResolver {
|
||||
);
|
||||
|
||||
// Synthetic "field" creation
|
||||
if (functionDescriptor instanceof PropertyAccessorDescriptor && functionDescriptor.getExtensionReceiverParameter() == null) {
|
||||
if (functionDescriptor instanceof PropertyAccessorDescriptor && functionDescriptor.getExtensionReceiverParameter() == null
|
||||
&& functionDescriptor.getContextReceiverParameters().isEmpty()) {
|
||||
PropertyAccessorDescriptor accessorDescriptor = (PropertyAccessorDescriptor) functionDescriptor;
|
||||
KtProperty property = (KtProperty) function.getParent();
|
||||
SourceElement propertySourceElement = KotlinSourceElementKt.toSourceElement(property);
|
||||
|
||||
@@ -64,13 +64,11 @@ import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.*;
|
||||
import static org.jetbrains.kotlin.diagnostics.Errors.*;
|
||||
import static org.jetbrains.kotlin.lexer.KtTokens.*;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContext.CONSTRUCTOR;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContext.TYPE_ALIAS;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContext.*;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
|
||||
import static org.jetbrains.kotlin.resolve.ModifiersChecker.resolveMemberModalityFromModifiers;
|
||||
import static org.jetbrains.kotlin.resolve.ModifiersChecker.resolveVisibilityFromModifiers;
|
||||
@@ -929,7 +927,6 @@ public class DescriptorResolver {
|
||||
LexicalScope scopeForDeclarationResolutionWithTypeParameters;
|
||||
LexicalScope scopeForInitializerResolutionWithTypeParameters;
|
||||
KotlinType receiverType = null;
|
||||
Stream<KotlinType> contextReceiverTypes;
|
||||
|
||||
{
|
||||
List<KtTypeParameter> typeParameters = variableDeclaration.getTypeParameters();
|
||||
@@ -958,37 +955,25 @@ public class DescriptorResolver {
|
||||
scopeForDeclarationResolutionWithTypeParameters = writableScopeForDeclarationResolution;
|
||||
scopeForInitializerResolutionWithTypeParameters = writableScopeForInitializerResolution;
|
||||
}
|
||||
|
||||
KtTypeReference receiverTypeRef = variableDeclaration.getReceiverTypeReference();
|
||||
if (receiverTypeRef != null) {
|
||||
receiverType = typeResolver.resolveType(scopeForDeclarationResolutionWithTypeParameters, receiverTypeRef, trace, true);
|
||||
}
|
||||
|
||||
List<KtTypeReference> contextReceiverTypeRefs = variableDeclaration.getContextReceiverTypeReferences();
|
||||
for (KtTypeReference contextReceiverTypeRef: contextReceiverTypeRefs) {
|
||||
typeResolver.resolveType(scopeForDeclarationResolutionWithTypeParameters, contextReceiverTypeRef, trace, true);
|
||||
}
|
||||
contextReceiverTypes = contextReceiverTypeRefs.stream()
|
||||
.map((typeRef) -> typeResolver.resolveType(scopeForDeclarationResolutionWithTypeParameters, typeRef, trace, true));
|
||||
}
|
||||
|
||||
ReceiverParameterDescriptor receiverDescriptor;
|
||||
if (receiverType != null) {
|
||||
LinkedHashMap<ReceiverParameterDescriptor, String> receiverToLabelMap = new LinkedHashMap<>();
|
||||
|
||||
KtTypeReference receiverTypeRef = variableDeclaration.getReceiverTypeReference();
|
||||
ReceiverParameterDescriptor receiverDescriptor = null;
|
||||
if (receiverTypeRef != null) {
|
||||
receiverType = typeResolver.resolveType(scopeForDeclarationResolutionWithTypeParameters, receiverTypeRef, trace, true);
|
||||
AnnotationSplitter splitter = new AnnotationSplitter(storageManager, receiverType.getAnnotations(), EnumSet.of(RECEIVER));
|
||||
receiverDescriptor = DescriptorFactory.createExtensionReceiverParameterForCallable(
|
||||
propertyDescriptor, receiverType, splitter.getAnnotationsForTarget(RECEIVER)
|
||||
);
|
||||
}
|
||||
else {
|
||||
receiverDescriptor = null;
|
||||
propertyDescriptor, receiverType, splitter.getAnnotationsForTarget(RECEIVER),
|
||||
false);
|
||||
receiverToLabelMap.put(receiverDescriptor, receiverTypeRef.nameForReceiverLabel());
|
||||
}
|
||||
|
||||
List<ReceiverParameterDescriptor> contextReceiverDescriptors = contextReceiverTypes.map((type) -> {
|
||||
AnnotationSplitter splitter = new AnnotationSplitter(storageManager, type.getAnnotations(), EnumSet.of(RECEIVER));
|
||||
return DescriptorFactory.createExtensionReceiverParameterForCallable(
|
||||
propertyDescriptor, type, splitter.getAnnotationsForTarget(RECEIVER)
|
||||
);
|
||||
}).collect(Collectors.toList());
|
||||
List<KtContextReceiver> contextReceivers = variableDeclaration.getContextReceivers();
|
||||
List<ReceiverParameterDescriptor> contextReceiverDescriptors =
|
||||
createReceiverDescriptorsForProperty(propertyDescriptor, scopeForDeclarationResolutionWithTypeParameters, trace,
|
||||
contextReceivers, receiverToLabelMap);
|
||||
|
||||
LexicalScope scopeForInitializer = ScopeUtils.makeScopeForPropertyInitializer(scopeForInitializerResolutionWithTypeParameters, propertyDescriptor);
|
||||
KotlinType propertyType = propertyInfo.getVariableType();
|
||||
@@ -1037,11 +1022,41 @@ public class DescriptorResolver {
|
||||
new FieldDescriptorImpl(annotationSplitter.getAnnotationsForTarget(FIELD), propertyDescriptor),
|
||||
new FieldDescriptorImpl(annotationSplitter.getAnnotationsForTarget(PROPERTY_DELEGATE_FIELD), propertyDescriptor)
|
||||
);
|
||||
|
||||
trace.record(DESCRIPTOR_TO_NAMED_RECEIVERS, propertyDescriptor, receiverToLabelMap);
|
||||
trace.record(BindingContext.VARIABLE, variableDeclaration, propertyDescriptor);
|
||||
return propertyDescriptor;
|
||||
}
|
||||
|
||||
private List<ReceiverParameterDescriptor> createReceiverDescriptorsForProperty(
|
||||
@NotNull PropertyDescriptor propertyDescriptor,
|
||||
@NotNull LexicalScope scopeForResolution,
|
||||
@NotNull BindingTrace trace,
|
||||
@NotNull List<KtContextReceiver> contextReceivers,
|
||||
@NotNull Map<ReceiverParameterDescriptor, String> receiverToLabelMap
|
||||
) {
|
||||
Map<KtContextReceiver, KotlinType> contextReceiversToTypes = new LinkedHashMap<>();
|
||||
for (KtContextReceiver contextReceiver: contextReceivers) {
|
||||
KtTypeReference typeReference = contextReceiver.typeReference();
|
||||
if (typeReference == null) {
|
||||
continue;
|
||||
}
|
||||
KotlinType kotlinType = typeResolver.resolveType(scopeForResolution, typeReference, trace, true);
|
||||
contextReceiversToTypes.put(contextReceiver, kotlinType);
|
||||
}
|
||||
return Lists.reverse(contextReceivers).stream().map(contextReceiver -> {
|
||||
KotlinType receiverType = contextReceiversToTypes.get(contextReceiver);
|
||||
AnnotationSplitter splitter = new AnnotationSplitter(storageManager, receiverType.getAnnotations(), EnumSet.of(RECEIVER));
|
||||
ReceiverParameterDescriptor receiverDescriptor = DescriptorFactory.createExtensionReceiverParameterForCallable(
|
||||
propertyDescriptor, receiverType, splitter.getAnnotationsForTarget(RECEIVER),
|
||||
true);
|
||||
String contextReceiverName = contextReceiver.name();
|
||||
if (contextReceiverName != null) {
|
||||
receiverToLabelMap.put(receiverDescriptor, contextReceiverName);
|
||||
}
|
||||
return receiverDescriptor;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
/*package*/ static KotlinType transformAnonymousTypeIfNeeded(
|
||||
@NotNull DeclarationDescriptorWithVisibility descriptor,
|
||||
|
||||
@@ -197,7 +197,8 @@ class FunctionDescriptorResolver(
|
||||
if (function is KtFunctionLiteral) expectedFunctionType.getReceiverType() else null
|
||||
}
|
||||
|
||||
val contextReceiverTypes = function.contextReceiverTypeReferences.map {
|
||||
val contextReceivers = function.contextReceivers
|
||||
val contextReceiverTypes = contextReceivers.mapNotNull { it.typeReference() }.map {
|
||||
typeResolver.resolveType(headerScope, it, trace, true)
|
||||
}
|
||||
|
||||
@@ -225,23 +226,35 @@ class FunctionDescriptorResolver(
|
||||
}
|
||||
}
|
||||
|
||||
val receiverToLabelMap = linkedMapOf<ReceiverParameterDescriptor, String>()
|
||||
val extensionReceiver = receiverType?.let {
|
||||
val splitter = AnnotationSplitter(storageManager, receiverType.annotations, EnumSet.of(AnnotationUseSiteTarget.RECEIVER))
|
||||
DescriptorFactory.createExtensionReceiverParameterForCallable(
|
||||
functionDescriptor, it, splitter.getAnnotationsForTarget(AnnotationUseSiteTarget.RECEIVER)
|
||||
)
|
||||
}
|
||||
val contextReceivers = contextReceiverTypes.map {
|
||||
val splitter = AnnotationSplitter(storageManager, it.annotations, EnumSet.of(AnnotationUseSiteTarget.RECEIVER))
|
||||
DescriptorFactory.createExtensionReceiverParameterForCallable(
|
||||
functionDescriptor, it, splitter.getAnnotationsForTarget(AnnotationUseSiteTarget.RECEIVER)
|
||||
functionDescriptor, it, splitter.getAnnotationsForTarget(AnnotationUseSiteTarget.RECEIVER), false
|
||||
)
|
||||
}?.apply {
|
||||
val extensionReceiverName = receiverTypeRef?.nameForReceiverLabel()
|
||||
if (extensionReceiverName != null) {
|
||||
receiverToLabelMap[this] = extensionReceiverName
|
||||
}
|
||||
}
|
||||
|
||||
val contextReceiverDescriptors = contextReceiverTypes.mapNotNull { type ->
|
||||
val splitter = AnnotationSplitter(storageManager, type.annotations, EnumSet.of(AnnotationUseSiteTarget.RECEIVER))
|
||||
DescriptorFactory.createExtensionReceiverParameterForCallable(
|
||||
functionDescriptor, type, splitter.getAnnotationsForTarget(AnnotationUseSiteTarget.RECEIVER), true
|
||||
)
|
||||
}
|
||||
contextReceiverDescriptors.reversed().zip(contextReceivers.lastIndex downTo 0).forEach { (contextReceiverDescriptor, i) ->
|
||||
contextReceivers[i].name()?.let {
|
||||
receiverToLabelMap[contextReceiverDescriptor] = it
|
||||
}
|
||||
}
|
||||
trace.record(BindingContext.DESCRIPTOR_TO_NAMED_RECEIVERS, functionDescriptor, receiverToLabelMap)
|
||||
functionDescriptor.initialize(
|
||||
extensionReceiver,
|
||||
getDispatchReceiverParameterIfNeeded(container),
|
||||
contextReceivers,
|
||||
contextReceiverDescriptors,
|
||||
typeParameterDescriptors,
|
||||
valueParameterDescriptors,
|
||||
returnType,
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import kotlin.Unit;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
@@ -73,7 +74,9 @@ public class FunctionDescriptorUtil {
|
||||
}
|
||||
List<ReceiverParameterDescriptor> contextReceiverParameters = descriptor.getContextReceiverParameters();
|
||||
if (!contextReceiverParameters.isEmpty()) {
|
||||
implicitReceivers.addAll(contextReceiverParameters);
|
||||
implicitReceivers.addAll(
|
||||
Lists.reverse(contextReceiverParameters)
|
||||
);
|
||||
}
|
||||
return new LexicalScopeImpl(
|
||||
outerScope, descriptor, true, implicitReceivers,
|
||||
|
||||
+44
-12
@@ -180,7 +180,7 @@ internal fun getIdForStableIdentifier(
|
||||
|
||||
is KtThisExpression -> {
|
||||
val declarationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.instanceReference)
|
||||
getIdForThisReceiver(declarationDescriptor)
|
||||
getIdForThisReceiver(declarationDescriptor, bindingContext, expression.getLabelName())
|
||||
}
|
||||
|
||||
is KtPostfixExpression -> {
|
||||
@@ -229,7 +229,7 @@ private fun getIdForSimpleNameExpression(
|
||||
if (implicitReceiver == null) {
|
||||
selectorInfo
|
||||
} else {
|
||||
val receiverInfo = getIdForImplicitReceiver(implicitReceiver, simpleNameExpression)
|
||||
val receiverInfo = getIdForImplicitReceiver(implicitReceiver, simpleNameExpression, bindingContext)
|
||||
|
||||
if (receiverInfo == null) {
|
||||
selectorInfo
|
||||
@@ -255,9 +255,9 @@ private fun getIdForSimpleNameExpression(
|
||||
}
|
||||
}
|
||||
|
||||
private fun getIdForImplicitReceiver(receiverValue: ReceiverValue?, expression: KtExpression?) =
|
||||
private fun getIdForImplicitReceiver(receiverValue: ReceiverValue?, expression: KtExpression?, bindingContext: BindingContext) =
|
||||
when (receiverValue) {
|
||||
is ImplicitReceiver -> getIdForThisReceiver(receiverValue.declarationDescriptor)
|
||||
is ImplicitReceiver -> getIdForThisReceiver(receiverValue.declarationDescriptor, bindingContext)
|
||||
|
||||
is TransientReceiver ->
|
||||
throw AssertionError("Transient receiver is implicit for an explicit expression: $expression. Receiver: $receiverValue")
|
||||
@@ -265,16 +265,48 @@ private fun getIdForImplicitReceiver(receiverValue: ReceiverValue?, expression:
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun getIdForThisReceiver(descriptorOfThisReceiver: DeclarationDescriptor?) = when (descriptorOfThisReceiver) {
|
||||
is CallableDescriptor -> {
|
||||
val receiverParameter = descriptorOfThisReceiver.extensionReceiverParameter
|
||||
?: error("'This' refers to the callable member without a receiver parameter: $descriptorOfThisReceiver")
|
||||
IdentifierInfo.Receiver(receiverParameter.value)
|
||||
private fun getIdForThisReceiver(
|
||||
descriptorOfThisReceiver: DeclarationDescriptor?,
|
||||
bindingContext: BindingContext,
|
||||
labelName: String? = null
|
||||
) =
|
||||
when (descriptorOfThisReceiver) {
|
||||
is CallableDescriptor -> {
|
||||
val receiverParameter = findReceiverByLabelOrGetDefault(
|
||||
descriptorOfThisReceiver,
|
||||
descriptorOfThisReceiver.extensionReceiverParameter,
|
||||
bindingContext,
|
||||
labelName
|
||||
)
|
||||
IdentifierInfo.Receiver(receiverParameter.value)
|
||||
}
|
||||
|
||||
is ClassDescriptor -> {
|
||||
val receiverParameter = findReceiverByLabelOrGetDefault(
|
||||
descriptorOfThisReceiver,
|
||||
descriptorOfThisReceiver.thisAsReceiverParameter,
|
||||
bindingContext,
|
||||
labelName
|
||||
)
|
||||
IdentifierInfo.Receiver(receiverParameter.value)
|
||||
}
|
||||
|
||||
else -> IdentifierInfo.NO
|
||||
}
|
||||
|
||||
is ClassDescriptor -> IdentifierInfo.Receiver(descriptorOfThisReceiver.thisAsReceiverParameter.value)
|
||||
|
||||
else -> IdentifierInfo.NO
|
||||
private fun findReceiverByLabelOrGetDefault(
|
||||
descriptorOfThisReceiver: DeclarationDescriptor,
|
||||
default: ReceiverParameterDescriptor?,
|
||||
bindingContext: BindingContext,
|
||||
labelName: String? = null
|
||||
): ReceiverParameterDescriptor {
|
||||
val receiverToLabelMap = bindingContext.get(
|
||||
BindingContext.DESCRIPTOR_TO_NAMED_RECEIVERS,
|
||||
if (descriptorOfThisReceiver is PropertyAccessorDescriptor) descriptorOfThisReceiver.correspondingProperty else descriptorOfThisReceiver
|
||||
)
|
||||
return receiverToLabelMap?.entries?.find {
|
||||
it.value == labelName
|
||||
}?.key ?: default ?: error("'This' refers to the callable member without a receiver parameter: $descriptorOfThisReceiver")
|
||||
}
|
||||
|
||||
private fun postfix(argumentInfo: IdentifierInfo, op: KtToken): IdentifierInfo =
|
||||
|
||||
+12
-11
@@ -49,10 +49,7 @@ import org.jetbrains.kotlin.storage.StorageManager;
|
||||
import org.jetbrains.kotlin.types.*;
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static kotlin.collections.CollectionsKt.firstOrNull;
|
||||
@@ -308,13 +305,17 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
|
||||
if (classOrObject == null) {
|
||||
return CollectionsKt.emptyList();
|
||||
}
|
||||
return classOrObject.getContextReceiverTypeReferences().stream().map(typeReference -> {
|
||||
KotlinType kotlinType = c.getTypeResolver().resolveType(getScopeForClassHeaderResolution(), typeReference, c.getTrace(), true);
|
||||
return new ReceiverParameterDescriptorImpl(
|
||||
this,
|
||||
new ExtensionClassReceiver(this, kotlinType, null),
|
||||
Annotations.Companion.getEMPTY()
|
||||
);
|
||||
return classOrObject.getContextReceivers().stream()
|
||||
.map(KtContextReceiver::typeReference)
|
||||
.filter(Objects::nonNull)
|
||||
.map(typeReference -> {
|
||||
KotlinType kotlinType =
|
||||
c.getTypeResolver().resolveType(getScopeForClassHeaderResolution(), typeReference, c.getTrace(), true);
|
||||
return new ReceiverParameterDescriptorImpl(
|
||||
this,
|
||||
new ExtensionClassReceiver(this, kotlinType, null),
|
||||
Annotations.Companion.getEMPTY()
|
||||
);
|
||||
}).collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
||||
+8
-1
@@ -67,6 +67,7 @@ import org.jetbrains.kotlin.resolve.constants.*;
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind;
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.ScopeUtilsKt;
|
||||
import org.jetbrains.kotlin.types.*;
|
||||
@@ -596,7 +597,13 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
}
|
||||
}
|
||||
else if (!receivers.isEmpty()) {
|
||||
result = receivers.get(0);
|
||||
// `this` cannot point to context receiver
|
||||
for (ReceiverParameterDescriptor receiver : receivers) {
|
||||
if (!(receiver.getValue() instanceof ExtensionReceiver) || !((ExtensionReceiver) receiver.getValue()).isContextReceiver()) {
|
||||
result = receiver;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result != null) {
|
||||
context.trace.record(REFERENCE_TARGET, expression.getInstanceReference(), result.getContainingDeclaration());
|
||||
|
||||
@@ -17,28 +17,29 @@
|
||||
package org.jetbrains.kotlin.types.expressions
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.LABEL_NAME_CLASH
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.UNRESOLVED_REFERENCE
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.checkReservedYield
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.LABEL_TARGET
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.REFERENCE_TARGET
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.*
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.getDeclarationsByLabel
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
object LabelResolver {
|
||||
private fun getElementsByLabelName(labelName: Name, labelExpression: KtSimpleNameExpression): Set<KtElement> {
|
||||
private fun getElementsByLabelName(
|
||||
labelName: Name,
|
||||
labelExpression: KtSimpleNameExpression,
|
||||
isThisExpression: Boolean
|
||||
): Set<KtElement> {
|
||||
val elements = linkedSetOf<KtElement>()
|
||||
var parent: PsiElement? = labelExpression.parent
|
||||
while (parent != null) {
|
||||
val name = getLabelNameIfAny(parent)
|
||||
if (name != null && name == labelName) {
|
||||
val names = getLabelNamesIfAny(parent, isThisExpression)
|
||||
if (names.contains(labelName)) {
|
||||
elements.add(getExpressionUnderLabel(parent as KtExpression))
|
||||
}
|
||||
parent = if (parent is KtCodeFragment) parent.context else parent.parent
|
||||
@@ -46,20 +47,33 @@ object LabelResolver {
|
||||
return elements
|
||||
}
|
||||
|
||||
fun getLabelNameIfAny(element: PsiElement): Name? {
|
||||
return when (element) {
|
||||
is KtLabeledExpression -> element.getLabelNameAsName()
|
||||
is KtFunctionLiteral -> getLabelNameIfAny(element.parent)
|
||||
is KtLambdaExpression -> getLabelForFunctionalExpression(element)
|
||||
is KtNamedFunction -> element.nameAsName ?: getLabelForFunctionalExpression(element)
|
||||
else -> null
|
||||
fun getLabelNamesIfAny(element: PsiElement, addContextReceiverNames: Boolean): List<Name> {
|
||||
val result = mutableListOf<Name>()
|
||||
when (element) {
|
||||
is KtLabeledExpression -> result.addIfNotNull(element.getLabelNameAsName())
|
||||
// TODO: Support context receivers in function literals
|
||||
is KtFunctionLiteral -> return getLabelNamesIfAny(element.parent, false)
|
||||
is KtLambdaExpression -> result.addIfNotNull(getLabelForFunctionalExpression(element))
|
||||
}
|
||||
val functionOrProperty = when (element) {
|
||||
is KtNamedFunction -> element
|
||||
is KtPropertyAccessor -> element.property
|
||||
else -> return result
|
||||
}
|
||||
if (addContextReceiverNames) {
|
||||
functionOrProperty.contextReceivers
|
||||
.mapNotNullTo(result) { it.name()?.let { s -> Name.identifier(s) } }
|
||||
functionOrProperty.receiverTypeReference?.nameForReceiverLabel()?.let { result.add(Name.identifier(it)) }
|
||||
}
|
||||
val name = functionOrProperty.nameAsName ?: getLabelForFunctionalExpression(functionOrProperty)
|
||||
result.addIfNotNull(name)
|
||||
return result
|
||||
}
|
||||
|
||||
private fun getLabelForFunctionalExpression(element: KtExpression): Name? {
|
||||
val parent = element.parent
|
||||
return when (parent) {
|
||||
is KtLabeledExpression -> getLabelNameIfAny(parent)
|
||||
is KtLabeledExpression -> getLabelNamesIfAny(parent, false).singleOrNull()
|
||||
is KtBinaryExpression -> parent.operationReference.getReferencedNameAsName()
|
||||
else -> getCallerName(element)
|
||||
}
|
||||
@@ -105,7 +119,7 @@ object LabelResolver {
|
||||
val labelName = expression.getLabelNameAsName()
|
||||
if (labelElement == null || labelName == null) return null
|
||||
|
||||
return resolveNamedLabel(labelName, labelElement, context.trace) ?: run {
|
||||
return resolveNamedLabel(labelName, labelElement, context.trace, false) ?: run {
|
||||
context.trace.report(UNRESOLVED_REFERENCE.on(labelElement, labelElement))
|
||||
null
|
||||
}
|
||||
@@ -114,9 +128,10 @@ object LabelResolver {
|
||||
private fun resolveNamedLabel(
|
||||
labelName: Name,
|
||||
labelExpression: KtSimpleNameExpression,
|
||||
trace: BindingTrace
|
||||
trace: BindingTrace,
|
||||
isThisExpression: Boolean
|
||||
): KtElement? {
|
||||
val list = getElementsByLabelName(labelName, labelExpression)
|
||||
val list = getElementsByLabelName(labelName, labelExpression, isThisExpression)
|
||||
if (list.isEmpty()) return null
|
||||
|
||||
if (list.size > 1) {
|
||||
@@ -160,10 +175,14 @@ object LabelResolver {
|
||||
return LabeledReceiverResolutionResult.labelResolutionSuccess(thisReceiver)
|
||||
}
|
||||
0 -> {
|
||||
val element = resolveNamedLabel(labelName, targetLabel, context.trace)
|
||||
val declarationDescriptor = context.trace.bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, element]
|
||||
val element = resolveNamedLabel(labelName, targetLabel, context.trace, expression is KtThisExpression)
|
||||
val declarationDescriptor = context.trace.bindingContext[DECLARATION_TO_DESCRIPTOR, element]
|
||||
if (declarationDescriptor is FunctionDescriptor) {
|
||||
val thisReceiver = declarationDescriptor.extensionReceiverParameter
|
||||
val receiverToLabelMap =
|
||||
context.trace.bindingContext[DESCRIPTOR_TO_NAMED_RECEIVERS, if (declarationDescriptor is PropertyAccessorDescriptor) declarationDescriptor.correspondingProperty else declarationDescriptor]
|
||||
val thisReceiver = receiverToLabelMap?.entries?.find {
|
||||
it.value == labelName.identifier
|
||||
}?.key ?: declarationDescriptor.extensionReceiverParameter
|
||||
if (thisReceiver != null) {
|
||||
context.trace.record(LABEL_TARGET, targetLabel, element)
|
||||
context.trace.record(REFERENCE_TARGET, referenceExpression, declarationDescriptor)
|
||||
|
||||
Reference in New Issue
Block a user