Debugger: Fix NPE in CFA during evaluation (KT-32830)
This commit is contained in:
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
|||||||
import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType
|
import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType
|
||||||
import org.jetbrains.kotlin.resolve.*
|
import org.jetbrains.kotlin.resolve.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext.*
|
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.isUsedAsExpression
|
||||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsResultOfLambda
|
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsResultOfLambda
|
||||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement
|
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement
|
||||||
@@ -471,7 +472,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
trace.get(BACKING_FIELD_REQUIRED, it)
|
trace.get(BACKING_FIELD_REQUIRED, it)
|
||||||
} ?: true
|
} ?: true
|
||||||
if (variableDescriptor is PropertyDescriptor && variableDescriptor.isVar) {
|
if (variableDescriptor is PropertyDescriptor && variableDescriptor.isVar) {
|
||||||
val descriptor = BindingContextUtils.getEnclosingDescriptor(trace.bindingContext, expression)
|
val descriptor = getEnclosingDescriptor(trace.bindingContext, expression)
|
||||||
val setterDescriptor = variableDescriptor.setter
|
val setterDescriptor = variableDescriptor.setter
|
||||||
|
|
||||||
val receiverValue = expression.getResolvedCall(trace.bindingContext)?.getDispatchReceiverWithSmartCast()
|
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.BindingContextUtils
|
||||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||||
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils
|
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.callUtil.getResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
|
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
@@ -916,8 +917,8 @@ class ControlFlowProcessor(
|
|||||||
private fun jumpDoesNotCrossFunctionBoundary(jumpExpression: KtExpressionWithLabel, jumpTarget: KtLoopExpression): Boolean {
|
private fun jumpDoesNotCrossFunctionBoundary(jumpExpression: KtExpressionWithLabel, jumpTarget: KtLoopExpression): Boolean {
|
||||||
val bindingContext = trace.bindingContext
|
val bindingContext = trace.bindingContext
|
||||||
|
|
||||||
val labelExprEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpExpression)
|
val labelExprEnclosingFunc = getEnclosingFunctionDescriptor(bindingContext, jumpExpression)
|
||||||
val labelTargetEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpTarget)
|
val labelTargetEnclosingFunc = getEnclosingFunctionDescriptor(bindingContext, jumpTarget)
|
||||||
return if (labelExprEnclosingFunc !== labelTargetEnclosingFunc) {
|
return if (labelExprEnclosingFunc !== labelTargetEnclosingFunc) {
|
||||||
// Check to report only once
|
// Check to report only once
|
||||||
if (builder.getLoopExitPoint(jumpTarget) != null ||
|
if (builder.getLoopExitPoint(jumpTarget) != null ||
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ package org.jetbrains.kotlin.resolve;
|
|||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.intellij.openapi.util.Pair;
|
import com.intellij.openapi.util.Pair;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import com.intellij.psi.util.PsiTreeUtil;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic;
|
import org.jetbrains.kotlin.diagnostics.Diagnostic;
|
||||||
import org.jetbrains.kotlin.psi.*;
|
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.callUtil.CallUtilKt;
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall;
|
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall;
|
||||||
@@ -111,31 +111,6 @@ public class BindingContextUtils {
|
|||||||
return value;
|
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(
|
public static void reportAmbiguousLabel(
|
||||||
@NotNull BindingTrace trace,
|
@NotNull BindingTrace trace,
|
||||||
@NotNull KtSimpleNameExpression targetLabel,
|
@NotNull KtSimpleNameExpression targetLabel,
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
package org.jetbrains.kotlin.resolve.bindingContextUtil
|
package org.jetbrains.kotlin.resolve.bindingContextUtil
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
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.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
|
||||||
@@ -114,4 +116,38 @@ fun KtTypeElement.getAbbreviatedTypeOrType(context: BindingContext): KotlinType?
|
|||||||
}
|
}
|
||||||
else -> null
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user