Fix a number of potential exceptions in debugger (EA-119717)

This commit is contained in:
Yan Zhulanow
2018-05-24 00:47:08 +03:00
parent 0f15dfdfdc
commit d851c8679a
7 changed files with 78 additions and 31 deletions
+13 -3
View File
@@ -357,7 +357,17 @@ class JDIEval(
}
private fun shouldInvokeMethodWithReflection(method: Method, args: List<com.sun.jdi.Value?>): Boolean {
return !method.isVarArgs && args.zip(method.argumentTypes()).any { isArrayOfInterfaces(it.first?.type(), it.second) }
if (method.isVarArgs) {
return false
}
val argumentTypes = try {
method.argumentTypes()
} catch (e: ClassNotLoadedException) {
return false
}
return args.zip(argumentTypes).any { isArrayOfInterfaces(it.first?.type(), it.second) }
}
private fun isArrayOfInterfaces(valueType: jdi_Type?, expectedType: jdi_Type?): Boolean {
@@ -413,8 +423,8 @@ class JDIEval(
}
private fun mapArguments(arguments: List<Value>, expecetedTypes: List<jdi_Type>): List<jdi_Value?> {
return arguments.zip(expecetedTypes).map {
private fun mapArguments(arguments: List<Value>, expectedTypes: List<jdi_Type>): List<jdi_Value?> {
return arguments.zip(expectedTypes).map {
val (arg, expectedType) = it
arg.asJdiValue(vm, expectedType.asType())
}
@@ -102,7 +102,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
if (location == null) throw NoDataException.INSTANCE
val fileName = location.safeSourceName ?: throw NoDataException.INSTANCE
val lineNumber = location.safeLineNumber
val lineNumber = location.safeLineNumber()
if (lineNumber < 0) {
throw NoDataException.INSTANCE
}
@@ -136,7 +136,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
if (psiFile !is KtFile) throw NoDataException.INSTANCE
val sourceLineNumber = location.safeSourceLineNumber
val sourceLineNumber = location.safeSourceLineNumber()
if (sourceLineNumber < 0) {
throw NoDataException.INSTANCE
}
@@ -156,7 +156,10 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
return SourcePosition.createFromLine(ktFile ?: psiFile, line - 1)
}
val sameLineLocations = location.safeMethod?.safeAllLineLocations?.filter { it.safeLineNumber == lineNumber && it.safeSourceName == fileName }
val sameLineLocations = location.safeMethod()?.safeAllLineLocations()?.filter {
it.safeLineNumber() == lineNumber && it.safeSourceName == fileName
}
if (sameLineLocations != null) {
// There're several locations for same source line. If same source position would be created for all of them,
// breakpoints at this line will stop on every location.
@@ -262,11 +265,6 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
}
}
private val Location.safeLineNumber: Int get() = DebuggerUtilsEx.getLineNumber(this, false)
private val Location.safeSourceLineNumber: Int get() = DebuggerUtilsEx.getLineNumber(this, true)
private val Location.safeMethod: Method? get() = DebuggerUtilsEx.getMethod(this)
private val Method.safeAllLineLocations: MutableList<Location>? get() = DebuggerUtilsEx.allLineLocations(this)
private fun getPsiFileByLocation(location: Location): PsiFile? {
val sourceName = location.safeSourceName ?: return null
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.debugger.safeAllLineLocations
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.psi.KtCallableDeclaration
@@ -210,7 +211,7 @@ class KotlinFieldBreakpoint(
private fun createMethodBreakpoint(debugProcess: DebugProcessImpl, refType: ReferenceType, accessor: Method) {
val manager = debugProcess.requestsManager
val line = accessor.allLineLocations().firstOrNull()
val line = accessor.safeAllLineLocations().firstOrNull()
if (line != null) {
val request = manager.createBreakpointRequest(this, line)
debugProcess.requestsManager.enableRequest(request)
@@ -9,6 +9,7 @@ import com.intellij.debugger.engine.DebugProcessImpl
import com.intellij.debugger.engine.DebuggerManagerThreadImpl
import com.intellij.debugger.engine.events.DebuggerCommandImpl
import com.intellij.debugger.impl.DebuggerContextImpl
import com.intellij.debugger.impl.DebuggerUtilsEx
import com.intellij.debugger.jdi.LocalVariableProxyImpl
import com.intellij.psi.PsiElement
import com.sun.jdi.*
@@ -28,6 +29,42 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import java.util.*
fun Method.safeAllLineLocations(): List<Location> {
return DebuggerUtilsEx.allLineLocations(this) ?: emptyList()
}
fun ReferenceType.safeAllLineLocations(): List<Location> {
return DebuggerUtilsEx.allLineLocations(this) ?: emptyList()
}
fun Method.safeLocationsOfLine(line: Int): List<Location> {
return try {
locationsOfLine(line)
} catch (e: AbsentInformationException) {
emptyList()
}
}
fun Method.safeVariables(): List<LocalVariable> {
return try {
variables()
} catch (e: AbsentInformationException) {
emptyList()
}
}
fun Location.safeLineNumber(): Int {
return DebuggerUtilsEx.getLineNumber(this, false)
}
fun Location.safeSourceLineNumber(): Int {
return DebuggerUtilsEx.getLineNumber(this, true)
}
fun Location.safeMethod(): Method? {
return DebuggerUtilsEx.getMethod(this)
}
fun isInsideInlineFunctionBody(visibleVariables: List<LocalVariableProxyImpl>): Boolean {
return visibleVariables.any { it.name().startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION) }
}
@@ -108,7 +145,7 @@ private class MockStackFrame(private val location: Location, private val vm: Vir
private fun createVisibleVariables() {
if (visibleVariables == null) {
val allVariables = location.method().variables()
val allVariables = location.method().safeVariables()
val map = HashMap<String, LocalVariable>(allVariables.size)
for (allVariable in allVariables) {
@@ -176,13 +213,7 @@ fun isOnSuspendReturnOrReenter(location: Location): Boolean {
}
fun isLastLineLocationInMethod(location: Location): Boolean {
val allLineLocations = try {
location.method().allLineLocations()
} catch (e: AbsentInformationException) {
return false
}
val knownLines = allLineLocations.map { it.lineNumber() }.filter { it != -1 }
val knownLines = location.method().safeAllLineLocations().map { it.lineNumber() }.filter { it != -1 }
if (knownLines.isEmpty()) {
return false
}
@@ -191,7 +222,7 @@ fun isLastLineLocationInMethod(location: Location): Boolean {
}
fun isOneLineMethod(location: Location): Boolean {
val allLineLocations = location.method().allLineLocations()
val allLineLocations = location.method().safeAllLineLocations()
val firstLine = allLineLocations.firstOrNull()?.lineNumber()
val lastLine = allLineLocations.lastOrNull()?.lineNumber()
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea.debugger.filter
import com.intellij.debugger.engine.SyntheticTypeComponentProvider
import com.sun.jdi.*
import org.jetbrains.kotlin.idea.debugger.safeAllLineLocations
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.org.objectweb.asm.Opcodes
@@ -71,7 +72,7 @@ class KotlinSyntheticTypeComponentProvider: SyntheticTypeComponentProvider {
}
private fun Method.isDelegateToDefaultInterfaceImpl(): Boolean {
if (allLineLocations().size != 1) return false
if (safeAllLineLocations().size != 1) return false
if (!virtualMachine().canGetBytecodes()) return false
if (!hasOnlyInvokeStatic(this)) return false
@@ -22,10 +22,7 @@ import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
import com.intellij.debugger.ui.impl.watch.FieldDescriptorImpl
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiExpression
import com.sun.jdi.Field
import com.sun.jdi.Method
import com.sun.jdi.ObjectReference
import com.sun.jdi.Value
import com.sun.jdi.*
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.Name
@@ -76,6 +73,13 @@ class DelegatedPropertyFieldDescriptor(
}
override fun getDeclaredType(): String? {
return findGetterForDelegatedProperty()?.returnType()?.name()
val getter = findGetterForDelegatedProperty() ?: return null
val returnType = try {
getter.returnType()
} catch (e: ClassNotLoadedException) {
// Behavior copied from LocalVariableDescriptorImpl (in platform)
return "<unknown>"
}
return returnType?.name()
}
}
@@ -409,7 +409,7 @@ fun getStepOverAction(
// this filter locations with too big code indexes manually
val returnCodeIndex: Long = if (isDexDebug) {
val method = location.method()
val locationsOfLine = method.locationsOfLine(range.last)
val locationsOfLine = method.safeLocationsOfLine(range.last)
if (locationsOfLine.isNotEmpty()) {
locationsOfLine.map { it.codeIndex() }.max() ?: -1L
}
@@ -439,7 +439,7 @@ fun getStepOutAction(
): Action {
val computedReferenceType = location.declaringType() ?: return Action.STEP_OUT()
val locations = computedReferenceType.allLineLocations()
val locations = computedReferenceType.safeAllLineLocations()
val nextLineLocations = locations
.dropWhile { it != location }
.drop(1)
@@ -531,8 +531,10 @@ private fun getInlineArgumentIfAny(elementAt: PsiElement?): KtFunctionLiteral? {
}
private fun findReturnFromDexBytecode(method: Method): Long {
val methodLocations = method.allLineLocations()
if (methodLocations.isEmpty()) return -1L
val methodLocations = method.safeAllLineLocations()
if (methodLocations.isEmpty()) {
return -1L
}
var lastMethodCodeIndex = methodLocations.last().codeIndex()
// Continue while it's possible to get location