Fix a number of potential exceptions in debugger (EA-119717)
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
+2
-1
@@ -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()
|
||||
|
||||
|
||||
+2
-1
@@ -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
|
||||
|
||||
+9
-5
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
+6
-4
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user