From a25e93d82a42456b5e0c43b19e75f2cc369e547c Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Thu, 8 Feb 2018 00:54:09 +0300 Subject: [PATCH] Debugger: (EA-112731) Do not crash miserably if we don't know the anonymous class name Continue to log the exception, avoid breaking UX --- .../codegen/binding/CodegenBinding.java | 32 ++++++++++++++++--- .../debugger/DebuggerClassNameProvider.kt | 23 +++++++++---- 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenBinding.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenBinding.java index ffa7fc0182a..e72b7c20971 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenBinding.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenBinding.java @@ -95,23 +95,33 @@ public class CodegenBinding { @NotNull public static Type asmTypeForAnonymousClass(@NotNull BindingContext bindingContext, @NotNull KtElement expression) { + Type result = asmTypeForAnonymousClassOrNull(bindingContext, expression); + if (result == null) { + throw new IllegalStateException("Type must not be null: " + expression.getText()); + } + + return result; + } + + @Nullable + public static Type asmTypeForAnonymousClassOrNull(@NotNull BindingContext bindingContext, @NotNull KtElement expression) { if (expression instanceof KtObjectLiteralExpression) { expression = ((KtObjectLiteralExpression) expression).getObjectDeclaration(); } ClassDescriptor descriptor = bindingContext.get(CLASS, expression); if (descriptor != null) { - return getAsmType(bindingContext, descriptor); + return bindingContext.get(ASM_TYPE, descriptor); } SimpleFunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression); if (functionDescriptor != null) { - return asmTypeForAnonymousClass(bindingContext, functionDescriptor); + return asmTypeForAnonymousClassOrNull(bindingContext, functionDescriptor); } VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, expression); if (variableDescriptor != null) { - return asmTypeForAnonymousClass(bindingContext, variableDescriptor); + return asmTypeForAnonymousClassOrNull(bindingContext, variableDescriptor); } throw new KotlinExceptionWithAttachments("Couldn't compute ASM type for expression") @@ -120,7 +130,17 @@ public class CodegenBinding { @NotNull public static Type asmTypeForAnonymousClass(@NotNull BindingContext bindingContext, @NotNull CallableDescriptor descriptor) { - return getAsmType(bindingContext, anonymousClassForCallable(bindingContext, descriptor)); + Type result = asmTypeForAnonymousClassOrNull(bindingContext, descriptor); + if (result == null) { + throw new IllegalStateException("Type must not be null: " + descriptor); + } + + return result; + } + + @Nullable + public static Type asmTypeForAnonymousClassOrNull(@NotNull BindingContext bindingContext, @NotNull CallableDescriptor descriptor) { + return bindingContext.get(ASM_TYPE, anonymousClassForCallable(bindingContext, descriptor)); } public static boolean canHaveOuter(@NotNull BindingContext bindingContext, @NotNull ClassDescriptor classDescriptor) { @@ -216,7 +236,9 @@ public class CodegenBinding { @NotNull public static Type getAsmType(@NotNull BindingContext bindingContext, @NotNull ClassDescriptor klass) { Type type = bindingContext.get(ASM_TYPE, klass); - assert type != null : "Type is not yet recorded for " + klass; + if (type == null) { + throw new IllegalStateException("Type is not yet recorded for " + klass); + } return type; } diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/DebuggerClassNameProvider.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/DebuggerClassNameProvider.kt index 25d2a3c3237..ef1a571ad9c 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/DebuggerClassNameProvider.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/DebuggerClassNameProvider.kt @@ -24,6 +24,7 @@ import com.intellij.psi.util.PsiTreeUtil import com.sun.jdi.AbsentInformationException import com.sun.jdi.ReferenceType import org.jetbrains.kotlin.codegen.binding.CodegenBinding.asmTypeForAnonymousClass +import org.jetbrains.kotlin.codegen.binding.CodegenBinding.asmTypeForAnonymousClassOrNull import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil import org.jetbrains.kotlin.idea.debugger.breakpoints.getLambdasAtLineIfAny import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches @@ -32,6 +33,7 @@ import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches.Computed import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches.ComputedClassNames.Companion.Cached import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches.ComputedClassNames.Companion.EMPTY import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches.ComputedClassNames.Companion.NonCached +import org.jetbrains.kotlin.idea.debugger.evaluate.LOG import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.load.java.JvmAbi @@ -187,13 +189,20 @@ class DebuggerClassNameProvider( val classNamesOfContainingDeclaration = getOuterClassNamesForElement(element.relevantParentInReadAction) - val nonInlineClasses: ComputedClassNames = if (runReadAction { element.name == null || element.isLocal }) { - classNamesOfContainingDeclaration + ComputedClassNames.Cached( - asmTypeForAnonymousClass(typeMapper.bindingContext, element).internalName.toJdiName()) - } - else { - classNamesOfContainingDeclaration - } + val nonInlineClasses: ComputedClassNames = + if (runReadAction { element.name == null || element.isLocal }) { + val typeForAnonymousClass = asmTypeForAnonymousClassOrNull(typeMapper.bindingContext, element) + + if (typeForAnonymousClass == null) { + val parentText = element.relevantParentInReadAction?.text ?: "" + LOG.error("Can not get type for ${element.text}, parent: $parentText") + classNamesOfContainingDeclaration + } else { + classNamesOfContainingDeclaration + ComputedClassNames.Cached(typeForAnonymousClass.internalName.toJdiName()) + } + } else { + classNamesOfContainingDeclaration + } if (!findInlineUseSites || !element.isInlineInReadAction) { return NonCached(nonInlineClasses.classNames)