Debugger: Fix NPE in CFA during evaluation (KT-32830)

This commit is contained in:
Yan Zhulanow
2019-07-24 21:56:48 +09:00
parent ecce34e02b
commit 79a5375ad1
4 changed files with 42 additions and 29 deletions
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.BindingContext.*
import org.jetbrains.kotlin.resolve.bindingContextUtil.getEnclosingDescriptor
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsResultOfLambda
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement
@@ -471,7 +472,7 @@ class ControlFlowInformationProvider private constructor(
trace.get(BACKING_FIELD_REQUIRED, it)
} ?: true
if (variableDescriptor is PropertyDescriptor && variableDescriptor.isVar) {
val descriptor = BindingContextUtils.getEnclosingDescriptor(trace.bindingContext, expression)
val descriptor = getEnclosingDescriptor(trace.bindingContext, expression)
val setterDescriptor = variableDescriptor.setter
val receiverValue = expression.getResolvedCall(trace.bindingContext)?.getDispatchReceiverWithSmartCast()
@@ -50,6 +50,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingContextUtils
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils
import org.jetbrains.kotlin.resolve.bindingContextUtil.getEnclosingFunctionDescriptor
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
@@ -916,8 +917,8 @@ class ControlFlowProcessor(
private fun jumpDoesNotCrossFunctionBoundary(jumpExpression: KtExpressionWithLabel, jumpTarget: KtLoopExpression): Boolean {
val bindingContext = trace.bindingContext
val labelExprEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpExpression)
val labelTargetEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpTarget)
val labelExprEnclosingFunc = getEnclosingFunctionDescriptor(bindingContext, jumpExpression)
val labelTargetEnclosingFunc = getEnclosingFunctionDescriptor(bindingContext, jumpTarget)
return if (labelExprEnclosingFunc !== labelTargetEnclosingFunc) {
// Check to report only once
if (builder.getLoopExitPoint(jumpTarget) != null ||
@@ -8,12 +8,12 @@ package org.jetbrains.kotlin.resolve;
import com.google.common.collect.Lists;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall;
@@ -111,31 +111,6 @@ public class BindingContextUtils {
return value;
}
@NotNull
public static DeclarationDescriptor getEnclosingDescriptor(@NotNull BindingContext context, @NotNull KtElement element) {
KtNamedDeclaration declaration = PsiTreeUtil.getParentOfType(element, KtNamedDeclaration.class);
if (declaration instanceof KtFunctionLiteral) {
return getEnclosingDescriptor(context, declaration);
}
DeclarationDescriptor descriptor = context.get(DECLARATION_TO_DESCRIPTOR, declaration);
assert descriptor != null : "No descriptor for named declaration: " + declaration.getText() + "\n(of type " + declaration.getClass() + ")";
return descriptor;
}
@Nullable
public static FunctionDescriptor getEnclosingFunctionDescriptor(@NotNull BindingContext context, @NotNull KtElement element) {
KtElement functionOrClass = PsiTreeUtil.getParentOfType(element, KtFunction.class, KtClassOrObject.class);
DeclarationDescriptor descriptor = context.get(DECLARATION_TO_DESCRIPTOR, functionOrClass);
if (functionOrClass instanceof KtFunction) {
if (descriptor instanceof FunctionDescriptor) return (FunctionDescriptor) descriptor;
return null;
}
else {
if (descriptor instanceof ClassDescriptor) return ((ClassDescriptor) descriptor).getUnsubstitutedPrimaryConstructor();
return null;
}
}
public static void reportAmbiguousLabel(
@NotNull BindingTrace trace,
@NotNull KtSimpleNameExpression targetLabel,
@@ -17,6 +17,8 @@
package org.jetbrains.kotlin.resolve.bindingContextUtil
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
@@ -114,4 +116,38 @@ fun KtTypeElement.getAbbreviatedTypeOrType(context: BindingContext): KotlinType?
}
else -> null
}
}
fun <T : PsiElement> KtElement.getParentOfTypeCodeFragmentAware(vararg parentClasses: Class<out T>): T? {
PsiTreeUtil.getParentOfType(this, *parentClasses)?.let { return it }
val containingFile = this.containingFile
if (containingFile is KtCodeFragment) {
val context = containingFile.context
if (context != null) {
return PsiTreeUtil.getParentOfType(context, *parentClasses)
}
}
return null
}
fun getEnclosingDescriptor(context: BindingContext, element: KtElement): DeclarationDescriptor {
val declaration = element.getParentOfTypeCodeFragmentAware(KtNamedDeclaration::class.java)
return if (declaration is KtFunctionLiteral) {
getEnclosingDescriptor(context, declaration)
} else {
context.get(DECLARATION_TO_DESCRIPTOR, declaration)
?: error("No descriptor for named declaration: " + declaration?.text + "\n(of type " + declaration?.javaClass + ")")
}
}
fun getEnclosingFunctionDescriptor(context: BindingContext, element: KtElement): FunctionDescriptor? {
val functionOrClass = element.getParentOfTypeCodeFragmentAware(KtFunction::class.java, KtClassOrObject::class.java)
val descriptor = context.get(DECLARATION_TO_DESCRIPTOR, functionOrClass)
return if (functionOrClass is KtFunction) {
if (descriptor is FunctionDescriptor) descriptor else null
} else {
if (descriptor is ClassDescriptor) descriptor.unsubstitutedPrimaryConstructor else null
}
}