J2K: convert & prettify LabelResolver

This commit is contained in:
Mikhail Zarechenskiy
2017-04-10 13:34:49 +03:00
parent 9ebbb73487
commit 1c3f546319
2 changed files with 152 additions and 216 deletions
@@ -654,7 +654,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
ReceiverParameterDescriptor receiverParameterDescriptor = resolutionResult.getReceiverParameterDescriptor(); ReceiverParameterDescriptor receiverParameterDescriptor = resolutionResult.getReceiverParameterDescriptor();
recordThisOrSuperCallInTraceAndCallExtension(context, receiverParameterDescriptor, expression); recordThisOrSuperCallInTraceAndCallExtension(context, receiverParameterDescriptor, expression);
if (onlyClassReceivers && !isDeclaredInClass(receiverParameterDescriptor)) { if (onlyClassReceivers && !isDeclaredInClass(receiverParameterDescriptor)) {
return LabelResolver.LabeledReceiverResolutionResult.labelResolutionSuccess(null); return LabelResolver.LabeledReceiverResolutionResult.Companion.labelResolutionSuccess(null);
} }
} }
return resolutionResult; return resolutionResult;
@@ -677,7 +677,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
context.trace.record(REFERENCE_TARGET, expression.getInstanceReference(), result.getContainingDeclaration()); context.trace.record(REFERENCE_TARGET, expression.getInstanceReference(), result.getContainingDeclaration());
recordThisOrSuperCallInTraceAndCallExtension(context, result, expression); recordThisOrSuperCallInTraceAndCallExtension(context, result, expression);
} }
return LabelResolver.LabeledReceiverResolutionResult.labelResolutionSuccess(result); return LabelResolver.LabeledReceiverResolutionResult.Companion.labelResolutionSuccess(result);
} }
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2015 JetBrains s.r.o. * Copyright 2010-2017 JetBrains s.r.o.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -14,290 +14,226 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.kotlin.types.expressions; package org.jetbrains.kotlin.types.expressions
import com.google.common.collect.Sets; import com.google.common.collect.Sets
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement
import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.diagnostics.Errors.LABEL_NAME_CLASH
import org.jetbrains.kotlin.psi.psiUtil.KtPsiUtilKt; import org.jetbrains.kotlin.diagnostics.Errors.UNRESOLVED_REFERENCE
import org.jetbrains.kotlin.resolve.*; import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext; import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.scopes.utils.ScopeUtilsKt; 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.calls.context.ResolutionContext
import org.jetbrains.kotlin.resolve.scopes.utils.getDeclarationsByLabel
import java.util.Collection; object LabelResolver {
import java.util.Set; private fun getElementsByLabelName(labelName: Name, labelExpression: KtSimpleNameExpression): Set<KtElement> {
val elements = Sets.newLinkedHashSet<KtElement>()
import static org.jetbrains.kotlin.diagnostics.Errors.LABEL_NAME_CLASH; var parent: PsiElement? = labelExpression.parent
import static org.jetbrains.kotlin.diagnostics.Errors.UNRESOLVED_REFERENCE;
import static org.jetbrains.kotlin.resolve.BindingContext.LABEL_TARGET;
import static org.jetbrains.kotlin.resolve.BindingContext.REFERENCE_TARGET;
public class LabelResolver {
public static LabelResolver INSTANCE = new LabelResolver();
private LabelResolver() {}
@NotNull
private Set<KtElement> getElementsByLabelName(@NotNull Name labelName, @NotNull KtSimpleNameExpression labelExpression) {
Set<KtElement> elements = Sets.newLinkedHashSet();
PsiElement parent = labelExpression.getParent();
while (parent != null) { while (parent != null) {
Name name = getLabelNameIfAny(parent); val name = getLabelNameIfAny(parent)
if (name != null && name.equals(labelName)) { if (name != null && name == labelName) {
elements.add(getExpressionUnderLabel((KtExpression) parent)); elements.add(getExpressionUnderLabel(parent as KtExpression))
} }
parent = parent.getParent(); parent = parent.parent
} }
return elements; return elements
} }
@Nullable fun getLabelNameIfAny(element: PsiElement): Name? {
public Name getLabelNameIfAny(@NotNull PsiElement element) { return when (element) {
if (element instanceof KtLabeledExpression) { is KtLabeledExpression -> element.getLabelNameAsName()
return ((KtLabeledExpression) element).getLabelNameAsName(); is KtFunctionLiteral -> getLabelNameIfAny(element.parent)
is KtLambdaExpression -> getLabelForFunctionalExpression(element)
is KtNamedFunction -> element.nameAsName ?: getLabelForFunctionalExpression(element)
else -> null
} }
if (element instanceof KtFunctionLiteral) {
return getLabelNameIfAny(element.getParent());
}
if (element instanceof KtLambdaExpression) {
return getLabelForFunctionalExpression((KtExpression) element);
}
if (element instanceof KtNamedFunction) {
Name name = ((KtNamedFunction) element).getNameAsName();
if (name != null) return name;
return getLabelForFunctionalExpression((KtExpression) element);
}
return null;
} }
private Name getLabelForFunctionalExpression(@NotNull KtExpression element) { private fun getLabelForFunctionalExpression(element: KtExpression): Name? {
if (element.getParent() instanceof KtLabeledExpression) { val parent = element.parent
return getLabelNameIfAny(element.getParent()); return if (parent is KtLabeledExpression) getLabelNameIfAny(parent) else getCallerName(element)
}
return getCallerName(element);
} }
@NotNull private fun getExpressionUnderLabel(labeledExpression: KtExpression): KtExpression {
private KtExpression getExpressionUnderLabel(@NotNull KtExpression labeledExpression) { val expression = KtPsiUtil.safeDeparenthesize(labeledExpression)
KtExpression expression = KtPsiUtil.safeDeparenthesize(labeledExpression); return if (expression is KtLambdaExpression) expression.functionLiteral else expression
if (expression instanceof KtLambdaExpression) {
return ((KtLambdaExpression) expression).getFunctionLiteral();
}
return expression;
} }
@Nullable private fun getCallerName(expression: KtExpression): Name? {
private Name getCallerName(@NotNull KtExpression expression) { val callExpression = getContainingCallExpression(expression) ?: return null
KtCallExpression callExpression = getContainingCallExpression(expression); val calleeExpression = callExpression.calleeExpression as? KtSimpleNameExpression
if (callExpression == null) return null; return calleeExpression?.getReferencedNameAsName()
KtExpression calleeExpression = callExpression.getCalleeExpression();
if (calleeExpression instanceof KtSimpleNameExpression) {
KtSimpleNameExpression nameExpression = (KtSimpleNameExpression) calleeExpression;
return nameExpression.getReferencedNameAsName();
}
return null;
} }
@Nullable private fun getContainingCallExpression(expression: KtExpression): KtCallExpression? {
private KtCallExpression getContainingCallExpression(@NotNull KtExpression expression) { val parent = expression.parent
PsiElement parent = expression.getParent(); if (parent is KtLambdaArgument) {
if (parent instanceof KtLambdaArgument) {
// f {} // f {}
PsiElement call = parent.getParent(); val call = parent.parent
if (call instanceof KtCallExpression) { if (call is KtCallExpression) {
return (KtCallExpression) call; return call
} }
} }
if (parent instanceof KtValueArgument) { if (parent is KtValueArgument) {
// f ({}) or f(p = {}) or f (fun () {}) // f ({}) or f(p = {}) or f (fun () {})
KtValueArgument argument = (KtValueArgument) parent; val argList = parent.parent ?: return null
PsiElement argList = argument.getParent(); val call = argList.parent
if (argList == null) return null; if (call is KtCallExpression) {
PsiElement call = argList.getParent(); return call
if (call instanceof KtCallExpression) {
return (KtCallExpression) call;
} }
} }
return null; return null
} }
@Nullable fun resolveControlLabel(expression: KtExpressionWithLabel, context: ResolutionContext<*>): KtElement? {
public KtElement resolveControlLabel( val labelElement = expression.getTargetLabel()
@NotNull KtExpressionWithLabel expression, checkReservedYield(labelElement, context.trace)
@NotNull ResolutionContext context
) {
KtSimpleNameExpression labelElement = expression.getTargetLabel();
KtPsiUtilKt.checkReservedYield(labelElement, context.trace);
Name labelName = expression.getLabelNameAsName(); val labelName = expression.getLabelNameAsName()
if (labelElement == null || labelName == null) return null; if (labelElement == null || labelName == null) return null
Collection<DeclarationDescriptor> declarationsByLabel = ScopeUtilsKt.getDeclarationsByLabel(context.scope, labelName); val declarationsByLabel = context.scope.getDeclarationsByLabel(labelName)
int size = declarationsByLabel.size(); val size = declarationsByLabel.size
if (size > 1) { if (size > 1) {
BindingContextUtils.reportAmbiguousLabel(context.trace, labelElement, declarationsByLabel); BindingContextUtils.reportAmbiguousLabel(context.trace, labelElement, declarationsByLabel)
return null; return null
} }
if (size == 0) { if (size == 0) {
KtElement element = resolveNamedLabel(labelName, labelElement, context.trace); val element = resolveNamedLabel(labelName, labelElement, context.trace)
if (element == null) { if (element == null) {
context.trace.report(UNRESOLVED_REFERENCE.on(labelElement, labelElement)); context.trace.report(UNRESOLVED_REFERENCE.on(labelElement, labelElement))
} }
return element; return element
} }
DeclarationDescriptor declarationDescriptor = declarationsByLabel.iterator().next();
KtElement element; val declarationDescriptor = declarationsByLabel.iterator().next()
if (declarationDescriptor instanceof FunctionDescriptor || declarationDescriptor instanceof ClassDescriptor) { if (declarationDescriptor is FunctionDescriptor || declarationDescriptor is ClassDescriptor) {
element = (KtElement) DescriptorToSourceUtils.descriptorToDeclaration(declarationDescriptor); val element = DescriptorToSourceUtils.descriptorToDeclaration(declarationDescriptor)
if (element is KtElement) {
context.trace.record(LABEL_TARGET, labelElement, element)
return element
}
} }
else { else {
throw new UnsupportedOperationException(declarationDescriptor.getClass().toString()); // TODO throw UnsupportedOperationException(declarationDescriptor.javaClass.toString()) // TODO
}
context.trace.record(LABEL_TARGET, labelElement, element);
return element;
}
private KtElement resolveNamedLabel(
@NotNull Name labelName,
@NotNull KtSimpleNameExpression labelExpression,
@NotNull BindingTrace trace
) {
Set<KtElement> list = getElementsByLabelName(labelName, labelExpression);
if (list.isEmpty()) return null;
if (list.size() > 1) {
trace.report(LABEL_NAME_CLASH.on(labelExpression));
} }
KtElement result = list.iterator().next(); return null
trace.record(LABEL_TARGET, labelExpression, result);
return result;
} }
@NotNull
public LabeledReceiverResolutionResult resolveThisOrSuperLabel(
@NotNull KtInstanceExpressionWithLabel expression,
@NotNull ResolutionContext context,
@NotNull Name labelName
) {
KtReferenceExpression referenceExpression = expression.getInstanceReference();
KtSimpleNameExpression targetLabel = expression.getTargetLabel();
assert targetLabel != null : expression;
Collection<DeclarationDescriptor> declarationsByLabel = ScopeUtilsKt.getDeclarationsByLabel(context.scope, labelName); private fun resolveNamedLabel(
int size = declarationsByLabel.size(); labelName: Name,
labelExpression: KtSimpleNameExpression,
trace: BindingTrace
): KtElement? {
val list = getElementsByLabelName(labelName, labelExpression)
if (list.isEmpty()) return null
if (list.size > 1) {
trace.report(LABEL_NAME_CLASH.on(labelExpression))
}
return list.single().also { trace.record(LABEL_TARGET, labelExpression, it) }
}
fun resolveThisOrSuperLabel(
expression: KtInstanceExpressionWithLabel,
context: ResolutionContext<*>,
labelName: Name
): LabeledReceiverResolutionResult {
val referenceExpression = expression.instanceReference
val targetLabel = expression.getTargetLabel() ?: error(expression)
val declarationsByLabel = context.scope.getDeclarationsByLabel(labelName)
val size = declarationsByLabel.size
if (size == 1) { if (size == 1) {
DeclarationDescriptor declarationDescriptor = declarationsByLabel.iterator().next(); val declarationDescriptor = declarationsByLabel.single()
ReceiverParameterDescriptor thisReceiver; val thisReceiver = when (declarationDescriptor) {
if (declarationDescriptor instanceof ClassDescriptor) { is ClassDescriptor -> declarationDescriptor.thisAsReceiverParameter
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; is FunctionDescriptor -> declarationDescriptor.extensionReceiverParameter
thisReceiver = classDescriptor.getThisAsReceiverParameter(); is PropertyDescriptor -> declarationDescriptor.extensionReceiverParameter
else -> throw UnsupportedOperationException("Unsupported descriptor: " + declarationDescriptor) // TODO
} }
else if (declarationDescriptor instanceof FunctionDescriptor) {
FunctionDescriptor functionDescriptor = (FunctionDescriptor) declarationDescriptor;
thisReceiver = functionDescriptor.getExtensionReceiverParameter();
}
else if (declarationDescriptor instanceof PropertyDescriptor) {
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) declarationDescriptor;
thisReceiver = propertyDescriptor.getExtensionReceiverParameter();
}
else {
throw new UnsupportedOperationException("Unsupported descriptor: " + declarationDescriptor); // TODO
}
PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(declarationDescriptor);
assert element != null : "No PSI element for descriptor: " + declarationDescriptor;
context.trace.record(LABEL_TARGET, targetLabel, element);
context.trace.record(REFERENCE_TARGET, referenceExpression, declarationDescriptor);
if (declarationDescriptor instanceof ClassDescriptor) { val element = DescriptorToSourceUtils.descriptorToDeclaration(declarationDescriptor) ?: error("No PSI element for descriptor: " + declarationDescriptor)
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; context.trace.record(LABEL_TARGET, targetLabel, element)
if (!DescriptorResolver.checkHasOuterClassInstance(context.scope, context.trace, targetLabel, classDescriptor)) { context.trace.record(REFERENCE_TARGET, referenceExpression, declarationDescriptor)
return LabeledReceiverResolutionResult.labelResolutionFailed();
if (declarationDescriptor is ClassDescriptor) {
if (!DescriptorResolver.checkHasOuterClassInstance(context.scope, context.trace, targetLabel, declarationDescriptor)) {
return LabeledReceiverResolutionResult.labelResolutionFailed()
} }
} }
return LabeledReceiverResolutionResult.labelResolutionSuccess(thisReceiver); return LabeledReceiverResolutionResult.labelResolutionSuccess(thisReceiver)
} }
else if (size == 0) { else if (size == 0) {
KtElement element = resolveNamedLabel(labelName, targetLabel, context.trace); val element = resolveNamedLabel(labelName, targetLabel, context.trace)
if (element instanceof KtFunctionLiteral) { if (element is KtFunctionLiteral) {
DeclarationDescriptor declarationDescriptor = val declarationDescriptor = context.trace.bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element)
context.trace.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, element); if (declarationDescriptor is FunctionDescriptor) {
if (declarationDescriptor instanceof FunctionDescriptor) { val thisReceiver = declarationDescriptor.extensionReceiverParameter
ReceiverParameterDescriptor thisReceiver = ((FunctionDescriptor) declarationDescriptor).getExtensionReceiverParameter();
if (thisReceiver != null) { if (thisReceiver != null) {
context.trace.record(LABEL_TARGET, targetLabel, element); context.trace.record(LABEL_TARGET, targetLabel, element)
context.trace.record(REFERENCE_TARGET, referenceExpression, declarationDescriptor); context.trace.record(REFERENCE_TARGET, referenceExpression, declarationDescriptor)
} }
return LabeledReceiverResolutionResult.labelResolutionSuccess(thisReceiver); return LabeledReceiverResolutionResult.labelResolutionSuccess(thisReceiver)
} }
else { else {
context.trace.report(UNRESOLVED_REFERENCE.on(targetLabel, targetLabel)); context.trace.report(UNRESOLVED_REFERENCE.on(targetLabel, targetLabel))
} }
} }
else { else {
context.trace.report(UNRESOLVED_REFERENCE.on(targetLabel, targetLabel)); context.trace.report(UNRESOLVED_REFERENCE.on(targetLabel, targetLabel))
} }
} }
else { else {
BindingContextUtils.reportAmbiguousLabel(context.trace, targetLabel, declarationsByLabel); BindingContextUtils.reportAmbiguousLabel(context.trace, targetLabel, declarationsByLabel)
} }
return LabeledReceiverResolutionResult.labelResolutionFailed(); return LabeledReceiverResolutionResult.labelResolutionFailed()
} }
public static final class LabeledReceiverResolutionResult { class LabeledReceiverResolutionResult private constructor(
public static LabeledReceiverResolutionResult labelResolutionSuccess(@Nullable ReceiverParameterDescriptor receiverParameterDescriptor) { val code: LabeledReceiverResolutionResult.Code,
if (receiverParameterDescriptor == null) { private val receiverParameterDescriptor: ReceiverParameterDescriptor?
return new LabeledReceiverResolutionResult(Code.NO_THIS, null); ) {
} enum class Code {
return new LabeledReceiverResolutionResult(Code.SUCCESS, receiverParameterDescriptor);
}
public static LabeledReceiverResolutionResult labelResolutionFailed() {
return new LabeledReceiverResolutionResult(Code.LABEL_RESOLUTION_ERROR, null);
}
public enum Code {
LABEL_RESOLUTION_ERROR, LABEL_RESOLUTION_ERROR,
NO_THIS, NO_THIS,
SUCCESS SUCCESS
} }
private final Code code; fun success(): Boolean {
private final ReceiverParameterDescriptor receiverParameterDescriptor; return code == Code.SUCCESS
private LabeledReceiverResolutionResult(
Code code,
ReceiverParameterDescriptor receiverParameterDescriptor
) {
this.code = code;
this.receiverParameterDescriptor = receiverParameterDescriptor;
} }
public Code getCode() { fun getReceiverParameterDescriptor(): ReceiverParameterDescriptor? {
return code; assert(success()) { "Don't try to obtain the receiver when resolution failed with " + code }
return receiverParameterDescriptor
} }
public boolean success() { companion object {
return code == Code.SUCCESS; fun labelResolutionSuccess(receiverParameterDescriptor: ReceiverParameterDescriptor?): LabeledReceiverResolutionResult {
} if (receiverParameterDescriptor == null) {
return LabeledReceiverResolutionResult(Code.NO_THIS, null)
}
return LabeledReceiverResolutionResult(Code.SUCCESS, receiverParameterDescriptor)
}
public ReceiverParameterDescriptor getReceiverParameterDescriptor() { fun labelResolutionFailed(): LabeledReceiverResolutionResult {
assert success() : "Don't try to obtain the receiver when resolution failed with " + code; return LabeledReceiverResolutionResult(Code.LABEL_RESOLUTION_ERROR, null)
return receiverParameterDescriptor; }
} }
} }
} }