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 {
|
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 {
|
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?> {
|
private fun mapArguments(arguments: List<Value>, expectedTypes: List<jdi_Type>): List<jdi_Value?> {
|
||||||
return arguments.zip(expecetedTypes).map {
|
return arguments.zip(expectedTypes).map {
|
||||||
val (arg, expectedType) = it
|
val (arg, expectedType) = it
|
||||||
arg.asJdiValue(vm, expectedType.asType())
|
arg.asJdiValue(vm, expectedType.asType())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
|
|||||||
if (location == null) throw NoDataException.INSTANCE
|
if (location == null) throw NoDataException.INSTANCE
|
||||||
|
|
||||||
val fileName = location.safeSourceName ?: throw NoDataException.INSTANCE
|
val fileName = location.safeSourceName ?: throw NoDataException.INSTANCE
|
||||||
val lineNumber = location.safeLineNumber
|
val lineNumber = location.safeLineNumber()
|
||||||
if (lineNumber < 0) {
|
if (lineNumber < 0) {
|
||||||
throw NoDataException.INSTANCE
|
throw NoDataException.INSTANCE
|
||||||
}
|
}
|
||||||
@@ -136,7 +136,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
|
|||||||
|
|
||||||
if (psiFile !is KtFile) throw NoDataException.INSTANCE
|
if (psiFile !is KtFile) throw NoDataException.INSTANCE
|
||||||
|
|
||||||
val sourceLineNumber = location.safeSourceLineNumber
|
val sourceLineNumber = location.safeSourceLineNumber()
|
||||||
if (sourceLineNumber < 0) {
|
if (sourceLineNumber < 0) {
|
||||||
throw NoDataException.INSTANCE
|
throw NoDataException.INSTANCE
|
||||||
}
|
}
|
||||||
@@ -156,7 +156,10 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
|
|||||||
return SourcePosition.createFromLine(ktFile ?: psiFile, line - 1)
|
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) {
|
if (sameLineLocations != null) {
|
||||||
// There're several locations for same source line. If same source position would be created for all of them,
|
// 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.
|
// 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? {
|
private fun getPsiFileByLocation(location: Location): PsiFile? {
|
||||||
val sourceName = location.safeSourceName ?: return null
|
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.descriptors.ValueParameterDescriptor
|
||||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
|
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
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.idea.util.application.runReadAction
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.psi.KtCallableDeclaration
|
import org.jetbrains.kotlin.psi.KtCallableDeclaration
|
||||||
@@ -210,7 +211,7 @@ class KotlinFieldBreakpoint(
|
|||||||
|
|
||||||
private fun createMethodBreakpoint(debugProcess: DebugProcessImpl, refType: ReferenceType, accessor: Method) {
|
private fun createMethodBreakpoint(debugProcess: DebugProcessImpl, refType: ReferenceType, accessor: Method) {
|
||||||
val manager = debugProcess.requestsManager
|
val manager = debugProcess.requestsManager
|
||||||
val line = accessor.allLineLocations().firstOrNull()
|
val line = accessor.safeAllLineLocations().firstOrNull()
|
||||||
if (line != null) {
|
if (line != null) {
|
||||||
val request = manager.createBreakpointRequest(this, line)
|
val request = manager.createBreakpointRequest(this, line)
|
||||||
debugProcess.requestsManager.enableRequest(request)
|
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.DebuggerManagerThreadImpl
|
||||||
import com.intellij.debugger.engine.events.DebuggerCommandImpl
|
import com.intellij.debugger.engine.events.DebuggerCommandImpl
|
||||||
import com.intellij.debugger.impl.DebuggerContextImpl
|
import com.intellij.debugger.impl.DebuggerContextImpl
|
||||||
|
import com.intellij.debugger.impl.DebuggerUtilsEx
|
||||||
import com.intellij.debugger.jdi.LocalVariableProxyImpl
|
import com.intellij.debugger.jdi.LocalVariableProxyImpl
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.sun.jdi.*
|
import com.sun.jdi.*
|
||||||
@@ -28,6 +29,42 @@ import org.jetbrains.kotlin.resolve.BindingContext
|
|||||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||||
import java.util.*
|
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 {
|
fun isInsideInlineFunctionBody(visibleVariables: List<LocalVariableProxyImpl>): Boolean {
|
||||||
return visibleVariables.any { it.name().startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION) }
|
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() {
|
private fun createVisibleVariables() {
|
||||||
if (visibleVariables == null) {
|
if (visibleVariables == null) {
|
||||||
val allVariables = location.method().variables()
|
val allVariables = location.method().safeVariables()
|
||||||
val map = HashMap<String, LocalVariable>(allVariables.size)
|
val map = HashMap<String, LocalVariable>(allVariables.size)
|
||||||
|
|
||||||
for (allVariable in allVariables) {
|
for (allVariable in allVariables) {
|
||||||
@@ -176,13 +213,7 @@ fun isOnSuspendReturnOrReenter(location: Location): Boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun isLastLineLocationInMethod(location: Location): Boolean {
|
fun isLastLineLocationInMethod(location: Location): Boolean {
|
||||||
val allLineLocations = try {
|
val knownLines = location.method().safeAllLineLocations().map { it.lineNumber() }.filter { it != -1 }
|
||||||
location.method().allLineLocations()
|
|
||||||
} catch (e: AbsentInformationException) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
val knownLines = allLineLocations.map { it.lineNumber() }.filter { it != -1 }
|
|
||||||
if (knownLines.isEmpty()) {
|
if (knownLines.isEmpty()) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -191,7 +222,7 @@ fun isLastLineLocationInMethod(location: Location): Boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun isOneLineMethod(location: Location): Boolean {
|
fun isOneLineMethod(location: Location): Boolean {
|
||||||
val allLineLocations = location.method().allLineLocations()
|
val allLineLocations = location.method().safeAllLineLocations()
|
||||||
val firstLine = allLineLocations.firstOrNull()?.lineNumber()
|
val firstLine = allLineLocations.firstOrNull()?.lineNumber()
|
||||||
val lastLine = allLineLocations.lastOrNull()?.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.intellij.debugger.engine.SyntheticTypeComponentProvider
|
||||||
import com.sun.jdi.*
|
import com.sun.jdi.*
|
||||||
|
import org.jetbrains.kotlin.idea.debugger.safeAllLineLocations
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
@@ -71,7 +72,7 @@ class KotlinSyntheticTypeComponentProvider: SyntheticTypeComponentProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun Method.isDelegateToDefaultInterfaceImpl(): Boolean {
|
private fun Method.isDelegateToDefaultInterfaceImpl(): Boolean {
|
||||||
if (allLineLocations().size != 1) return false
|
if (safeAllLineLocations().size != 1) return false
|
||||||
if (!virtualMachine().canGetBytecodes()) return false
|
if (!virtualMachine().canGetBytecodes()) return false
|
||||||
|
|
||||||
if (!hasOnlyInvokeStatic(this)) 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.debugger.ui.impl.watch.FieldDescriptorImpl
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.PsiExpression
|
import com.intellij.psi.PsiExpression
|
||||||
import com.sun.jdi.Field
|
import com.sun.jdi.*
|
||||||
import com.sun.jdi.Method
|
|
||||||
import com.sun.jdi.ObjectReference
|
|
||||||
import com.sun.jdi.Value
|
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
@@ -76,6 +73,13 @@ class DelegatedPropertyFieldDescriptor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getDeclaredType(): String? {
|
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
|
// this filter locations with too big code indexes manually
|
||||||
val returnCodeIndex: Long = if (isDexDebug) {
|
val returnCodeIndex: Long = if (isDexDebug) {
|
||||||
val method = location.method()
|
val method = location.method()
|
||||||
val locationsOfLine = method.locationsOfLine(range.last)
|
val locationsOfLine = method.safeLocationsOfLine(range.last)
|
||||||
if (locationsOfLine.isNotEmpty()) {
|
if (locationsOfLine.isNotEmpty()) {
|
||||||
locationsOfLine.map { it.codeIndex() }.max() ?: -1L
|
locationsOfLine.map { it.codeIndex() }.max() ?: -1L
|
||||||
}
|
}
|
||||||
@@ -439,7 +439,7 @@ fun getStepOutAction(
|
|||||||
): Action {
|
): Action {
|
||||||
val computedReferenceType = location.declaringType() ?: return Action.STEP_OUT()
|
val computedReferenceType = location.declaringType() ?: return Action.STEP_OUT()
|
||||||
|
|
||||||
val locations = computedReferenceType.allLineLocations()
|
val locations = computedReferenceType.safeAllLineLocations()
|
||||||
val nextLineLocations = locations
|
val nextLineLocations = locations
|
||||||
.dropWhile { it != location }
|
.dropWhile { it != location }
|
||||||
.drop(1)
|
.drop(1)
|
||||||
@@ -531,8 +531,10 @@ private fun getInlineArgumentIfAny(elementAt: PsiElement?): KtFunctionLiteral? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun findReturnFromDexBytecode(method: Method): Long {
|
private fun findReturnFromDexBytecode(method: Method): Long {
|
||||||
val methodLocations = method.allLineLocations()
|
val methodLocations = method.safeAllLineLocations()
|
||||||
if (methodLocations.isEmpty()) return -1L
|
if (methodLocations.isEmpty()) {
|
||||||
|
return -1L
|
||||||
|
}
|
||||||
|
|
||||||
var lastMethodCodeIndex = methodLocations.last().codeIndex()
|
var lastMethodCodeIndex = methodLocations.last().codeIndex()
|
||||||
// Continue while it's possible to get location
|
// Continue while it's possible to get location
|
||||||
|
|||||||
Reference in New Issue
Block a user