Debugger: (EA-112731) Do not crash miserably if we don't know the anonymous class name

Continue to log the exception, avoid breaking UX
This commit is contained in:
Yan Zhulanow
2018-02-08 00:54:09 +03:00
parent 2a3bab0a0f
commit a25e93d82a
2 changed files with 43 additions and 12 deletions
@@ -95,23 +95,33 @@ public class CodegenBinding {
@NotNull @NotNull
public static Type asmTypeForAnonymousClass(@NotNull BindingContext bindingContext, @NotNull KtElement expression) { 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) { if (expression instanceof KtObjectLiteralExpression) {
expression = ((KtObjectLiteralExpression) expression).getObjectDeclaration(); expression = ((KtObjectLiteralExpression) expression).getObjectDeclaration();
} }
ClassDescriptor descriptor = bindingContext.get(CLASS, expression); ClassDescriptor descriptor = bindingContext.get(CLASS, expression);
if (descriptor != null) { if (descriptor != null) {
return getAsmType(bindingContext, descriptor); return bindingContext.get(ASM_TYPE, descriptor);
} }
SimpleFunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression); SimpleFunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression);
if (functionDescriptor != null) { if (functionDescriptor != null) {
return asmTypeForAnonymousClass(bindingContext, functionDescriptor); return asmTypeForAnonymousClassOrNull(bindingContext, functionDescriptor);
} }
VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, expression); VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, expression);
if (variableDescriptor != null) { if (variableDescriptor != null) {
return asmTypeForAnonymousClass(bindingContext, variableDescriptor); return asmTypeForAnonymousClassOrNull(bindingContext, variableDescriptor);
} }
throw new KotlinExceptionWithAttachments("Couldn't compute ASM type for expression") throw new KotlinExceptionWithAttachments("Couldn't compute ASM type for expression")
@@ -120,7 +130,17 @@ public class CodegenBinding {
@NotNull @NotNull
public static Type asmTypeForAnonymousClass(@NotNull BindingContext bindingContext, @NotNull CallableDescriptor descriptor) { 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) { public static boolean canHaveOuter(@NotNull BindingContext bindingContext, @NotNull ClassDescriptor classDescriptor) {
@@ -216,7 +236,9 @@ public class CodegenBinding {
@NotNull @NotNull
public static Type getAsmType(@NotNull BindingContext bindingContext, @NotNull ClassDescriptor klass) { public static Type getAsmType(@NotNull BindingContext bindingContext, @NotNull ClassDescriptor klass) {
Type type = bindingContext.get(ASM_TYPE, 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; return type;
} }
@@ -24,6 +24,7 @@ import com.intellij.psi.util.PsiTreeUtil
import com.sun.jdi.AbsentInformationException import com.sun.jdi.AbsentInformationException
import com.sun.jdi.ReferenceType import com.sun.jdi.ReferenceType
import org.jetbrains.kotlin.codegen.binding.CodegenBinding.asmTypeForAnonymousClass 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.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.idea.debugger.breakpoints.getLambdasAtLineIfAny import org.jetbrains.kotlin.idea.debugger.breakpoints.getLambdasAtLineIfAny
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches 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.Cached
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches.ComputedClassNames.Companion.EMPTY 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.KotlinDebuggerCaches.ComputedClassNames.Companion.NonCached
import org.jetbrains.kotlin.idea.debugger.evaluate.LOG
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAbi
@@ -187,13 +189,20 @@ class DebuggerClassNameProvider(
val classNamesOfContainingDeclaration = getOuterClassNamesForElement(element.relevantParentInReadAction) val classNamesOfContainingDeclaration = getOuterClassNamesForElement(element.relevantParentInReadAction)
val nonInlineClasses: ComputedClassNames = if (runReadAction { element.name == null || element.isLocal }) { val nonInlineClasses: ComputedClassNames =
classNamesOfContainingDeclaration + ComputedClassNames.Cached( if (runReadAction { element.name == null || element.isLocal }) {
asmTypeForAnonymousClass(typeMapper.bindingContext, element).internalName.toJdiName()) val typeForAnonymousClass = asmTypeForAnonymousClassOrNull(typeMapper.bindingContext, element)
}
else { if (typeForAnonymousClass == null) {
classNamesOfContainingDeclaration val parentText = element.relevantParentInReadAction?.text ?: "<parent was null>"
} 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) { if (!findInlineUseSites || !element.isInlineInReadAction) {
return NonCached(nonInlineClasses.classNames) return NonCached(nonInlineClasses.classNames)