mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-13 15:52:01 +07:00
[debugger dfa] IDEA-373993 Move getJdiValueForDfaVariable computation to BGT
GitOrigin-RevId: 3a386ea3fa6f8c2c39a3c77e90ced78f9899dce5
This commit is contained in:
committed by
intellij-monorepo-bot
parent
3f2444f6d9
commit
cd9e39eb6e
@@ -14,10 +14,8 @@ import com.intellij.debugger.impl.DebuggerContextImpl
|
||||
import com.intellij.debugger.impl.DebuggerUtilsEx
|
||||
import com.intellij.debugger.jdi.StackFrameProxyEx
|
||||
import com.intellij.openapi.application.EDT
|
||||
import com.intellij.openapi.application.ReadAction
|
||||
import com.intellij.openapi.application.ReadConstraint
|
||||
import com.intellij.openapi.application.constrainedReadAction
|
||||
import com.intellij.openapi.progress.blockingContext
|
||||
import com.intellij.openapi.project.DumbService.Companion.isDumb
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.SmartPointerManager
|
||||
@@ -30,7 +28,6 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jetbrains.annotations.VisibleForTesting
|
||||
import java.util.concurrent.ExecutionException
|
||||
|
||||
|
||||
@Throws(EvaluateException::class)
|
||||
@@ -96,7 +93,7 @@ private suspend fun resolveJdiValue(
|
||||
// Assume that assertions are enabled if we cannot fetch the status
|
||||
return location.virtualMachine().mirrorOf(status == ThreeState.NO)
|
||||
}
|
||||
return syncReadAction { provider.getJdiValueForDfaVariable(proxy, variableValue, anchor) }
|
||||
return provider.getJdiValueForDfaVariable(proxy, variableValue, anchor)
|
||||
}
|
||||
|
||||
private suspend fun makePupa(proxy: StackFrameProxyEx, pointer: SmartPsiElementPointer<PsiElement?>): Pupa? {
|
||||
@@ -195,12 +192,3 @@ private data class LarvaData(
|
||||
val offset: Int,
|
||||
val dfaVariableValues: List<DfaVariableValue>,
|
||||
)
|
||||
|
||||
private suspend fun <T> syncReadAction(action: () -> T): T =
|
||||
try {
|
||||
ReadAction.nonBlocking(action).executeSynchronously()
|
||||
}
|
||||
catch (e: ExecutionException) {
|
||||
throw e.cause ?: e
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ interface DfaAssistProvider {
|
||||
* @throws EvaluateException if proxy throws
|
||||
*/
|
||||
@Throws(EvaluateException::class)
|
||||
fun getJdiValueForDfaVariable(
|
||||
suspend fun getJdiValueForDfaVariable(
|
||||
proxy: StackFrameProxyEx,
|
||||
dfaVar: DfaVariableValue,
|
||||
anchor: PsiElement,
|
||||
|
||||
@@ -102,7 +102,7 @@ private class JavaDfaAssistProvider : DfaAssistProvider {
|
||||
}
|
||||
|
||||
@Throws(EvaluateException::class)
|
||||
override fun getJdiValueForDfaVariable(
|
||||
override suspend fun getJdiValueForDfaVariable(
|
||||
proxy: StackFrameProxyEx,
|
||||
dfaVar: DfaVariableValue,
|
||||
anchor: PsiElement,
|
||||
@@ -116,12 +116,12 @@ private class JavaDfaAssistProvider : DfaAssistProvider {
|
||||
}
|
||||
val qualifierValue = getJdiValueForDfaVariable(proxy, qualifier, anchor)
|
||||
if (qualifierValue == null) return null
|
||||
val element = descriptor.psiElement
|
||||
val element = readAction { descriptor.psiElement }
|
||||
if (element is PsiField && qualifierValue is ObjectReference) {
|
||||
val type = qualifierValue.referenceType()
|
||||
val psiClass = element.getContainingClass()
|
||||
if (psiClass != null && type.name() == JVMNameUtil.getClassVMName(psiClass)) {
|
||||
val field = DebuggerUtils.findField(type, element.getName())
|
||||
val psiClass = readAction { element.getContainingClass() }
|
||||
if (psiClass != null && type.name() == readAction { JVMNameUtil.getClassVMName(psiClass) }) {
|
||||
val field = DebuggerUtils.findField(type, readAction { element.getName() })
|
||||
if (field != null) {
|
||||
return wrap(qualifierValue.getValue(field))
|
||||
}
|
||||
@@ -136,15 +136,19 @@ private class JavaDfaAssistProvider : DfaAssistProvider {
|
||||
}
|
||||
return null
|
||||
}
|
||||
val psi = dfaVar.psiVariable
|
||||
val psi = readAction { dfaVar.psiVariable }
|
||||
if (psi is PsiClass) {
|
||||
// this; probably qualified
|
||||
val currentClass = PsiTreeUtil.getParentOfType(anchor, PsiClass::class.java)
|
||||
return CaptureTraverser.create(psi, currentClass, true).traverse(proxy.thisObject())
|
||||
val captureTraverser = readAction {
|
||||
val currentClass = PsiTreeUtil.getParentOfType(anchor, PsiClass::class.java)
|
||||
CaptureTraverser.create(psi, currentClass, true)
|
||||
}
|
||||
return captureTraverser.traverse(proxy.thisObject())
|
||||
}
|
||||
if (psi is PsiLocalVariable || psi is PsiParameter) {
|
||||
val varName: String = psi.getName()!!
|
||||
if (PsiResolveHelper.getInstance(psi.getProject()).resolveReferencedVariable(varName, anchor) !== psi) {
|
||||
val varName: String = readAction { psi.getName()!! }
|
||||
val resolveVariable = readAction { PsiResolveHelper.getInstance(psi.getProject()).resolveReferencedVariable(varName, anchor) }
|
||||
if (resolveVariable !== psi) {
|
||||
// Another variable with the same name could be tracked by DFA in different code branch but not visible at current code location
|
||||
return null
|
||||
}
|
||||
@@ -152,10 +156,12 @@ private class JavaDfaAssistProvider : DfaAssistProvider {
|
||||
if (variable != null) {
|
||||
return wrap(proxy.getVariableValue(variable))
|
||||
}
|
||||
val currentClass = PsiTreeUtil.getParentOfType(anchor, PsiClass::class.java)
|
||||
val varClass = PsiTreeUtil.getParentOfType(psi, PsiClass::class.java)
|
||||
val thisRef = CaptureTraverser.create(varClass, currentClass, false)
|
||||
.oneLevelLess().traverse(proxy.thisObject())
|
||||
val captureTraverser = readAction {
|
||||
val currentClass = PsiTreeUtil.getParentOfType(anchor, PsiClass::class.java)
|
||||
val varClass = PsiTreeUtil.getParentOfType(psi, PsiClass::class.java)
|
||||
CaptureTraverser.create(varClass, currentClass, false).oneLevelLess()
|
||||
}
|
||||
val thisRef = captureTraverser.traverse(proxy.thisObject())
|
||||
if (thisRef != null) {
|
||||
val type = thisRef.referenceType()
|
||||
if (type is ClassType && type.isPrepared) {
|
||||
@@ -166,10 +172,10 @@ private class JavaDfaAssistProvider : DfaAssistProvider {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (psi is PsiField && psi.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
val psiClass = psi.getContainingClass()
|
||||
if (psi is PsiField && readAction { psi.hasModifierProperty(PsiModifier.STATIC) }) {
|
||||
val psiClass = readAction { psi.getContainingClass() }
|
||||
if (psiClass != null) {
|
||||
val name = psiClass.getQualifiedName()
|
||||
val name = readAction { psiClass.getQualifiedName() }
|
||||
if (name != null) {
|
||||
val type = ContainerUtil.getOnlyItem(proxy.getVirtualMachine().classesByName(name))
|
||||
if (type != null && type.isPrepared) {
|
||||
|
||||
@@ -4,6 +4,7 @@ package com.intellij.debugger.mockJDI.types;
|
||||
import com.intellij.debugger.mockJDI.MockVirtualMachine;
|
||||
import com.intellij.debugger.mockJDI.members.MockPsiMethod;
|
||||
import com.intellij.debugger.mockJDI.values.MockClassLoaderReference;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiModifier;
|
||||
import com.intellij.psi.util.ClassUtil;
|
||||
@@ -28,7 +29,7 @@ public class MockPsiReferenceType extends MockType implements ReferenceType {
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return ClassUtil.getJVMClassName(myClass);
|
||||
return ReadAction.compute(() -> ClassUtil.getJVMClassName(myClass));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -72,15 +72,15 @@ private class KotlinDfaAssistProvider : DfaAssistProvider {
|
||||
}
|
||||
}
|
||||
|
||||
override fun getJdiValueForDfaVariable(proxy: StackFrameProxyEx, dfaVar: DfaVariableValue, anchor: PsiElement): Value? {
|
||||
override suspend fun getJdiValueForDfaVariable(proxy: StackFrameProxyEx, dfaVar: DfaVariableValue, anchor: PsiElement): Value? {
|
||||
val qualifier = dfaVar.qualifier
|
||||
val psiVariable = dfaVar.psiVariable
|
||||
val psiVariable = readAction { dfaVar.psiVariable }
|
||||
if (qualifier == null) {
|
||||
val descriptor = dfaVar.descriptor
|
||||
if (descriptor is KtThisDescriptor) {
|
||||
val declarationDescriptor = descriptor.descriptor
|
||||
if (declarationDescriptor is FunctionDescriptor) {
|
||||
val thisName = "\$this\$${declarationDescriptor.name}"
|
||||
val thisName = readAction { "\$this\$${declarationDescriptor.name}" }
|
||||
val thisVar = proxy.visibleVariableByName(thisName)
|
||||
if (thisVar != null) {
|
||||
return postprocess(proxy.getVariableValue(thisVar))
|
||||
@@ -90,7 +90,7 @@ private class KotlinDfaAssistProvider : DfaAssistProvider {
|
||||
val thisObject = proxy.thisObject()
|
||||
if (thisObject != null) {
|
||||
val signature = AsmType.getType(thisObject.referenceType().signature()).className
|
||||
val jvmName = KotlinPsiHeuristics.getJvmName(declarationDescriptor.fqNameSafe)
|
||||
val jvmName = readAction { KotlinPsiHeuristics.getJvmName(declarationDescriptor.fqNameSafe) }
|
||||
if (signature == jvmName) {
|
||||
return thisObject
|
||||
}
|
||||
@@ -100,7 +100,8 @@ private class KotlinDfaAssistProvider : DfaAssistProvider {
|
||||
}
|
||||
else if (descriptor is KtVariableDescriptor && psiVariable is KtCallableDeclaration) {
|
||||
// TODO: check/support inlined functions
|
||||
val variable = proxy.visibleVariableByName((psiVariable as KtNamedDeclaration).name)
|
||||
val name = readAction { (psiVariable as KtNamedDeclaration).name }
|
||||
val variable = proxy.visibleVariableByName(name)
|
||||
if (variable != null) {
|
||||
return postprocess(proxy.getVariableValue(variable))
|
||||
}
|
||||
@@ -108,7 +109,8 @@ private class KotlinDfaAssistProvider : DfaAssistProvider {
|
||||
} else {
|
||||
val jdiQualifier = getJdiValueForDfaVariable(proxy, qualifier, anchor)
|
||||
if (jdiQualifier is ObjectReference && psiVariable is KtCallableDeclaration) {
|
||||
val field = psiVariable.name?.let { DebuggerUtils.findField(jdiQualifier.referenceType(), it) }
|
||||
val name = readAction { psiVariable.name }
|
||||
val field = name?.let { DebuggerUtils.findField(jdiQualifier.referenceType(), it) }
|
||||
if (field != null) {
|
||||
return postprocess(jdiQualifier.getValue(field))
|
||||
}
|
||||
|
||||
@@ -86,14 +86,14 @@ private class K2DfaAssistProvider : DfaAssistProvider {
|
||||
}
|
||||
}
|
||||
|
||||
override fun getJdiValueForDfaVariable(
|
||||
override suspend fun getJdiValueForDfaVariable(
|
||||
proxy: StackFrameProxyEx,
|
||||
dfaVar: DfaVariableValue,
|
||||
anchor: PsiElement
|
||||
): Value? {
|
||||
if (anchor !is KtElement) return null
|
||||
if ((dfaVar.descriptor as? KtBaseDescriptor)?.isInlineClassReference() == true) return null
|
||||
return runDumbAction(anchor.project, null) {
|
||||
if (readAction { (dfaVar.descriptor as? KtBaseDescriptor)?.isInlineClassReference() == true }) return null
|
||||
return runDumbAction(readAction { anchor.project }, null) {
|
||||
getJdiValueInner(proxy, dfaVar, anchor)
|
||||
}
|
||||
}
|
||||
@@ -124,7 +124,7 @@ private class K2DfaAssistProvider : DfaAssistProvider {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getJdiValueInner(
|
||||
private suspend fun getJdiValueInner(
|
||||
proxy: StackFrameProxyEx,
|
||||
dfaVar: DfaVariableValue,
|
||||
anchor: KtElement
|
||||
@@ -136,10 +136,12 @@ private class K2DfaAssistProvider : DfaAssistProvider {
|
||||
val inlineSuffix = KotlinDebuggerConstants.INLINE_FUN_VAR_SUFFIX.repeat(inlineDepth)
|
||||
if (qualifier == null) {
|
||||
if (descriptor is KtLambdaThisVariableDescriptor) {
|
||||
val scopeName = (descriptor.lambda.parentOfType<KtFunction>() as? KtNamedFunction)?.name
|
||||
val scopePart = scopeName?.replace(Regex("[^\\p{L}\\d]"), "_")?.let(Regex::escape) ?: ".+"
|
||||
val inlinedPart = Regex.escape(inlineSuffix)
|
||||
val regex = Regex("\\\$this\\$${scopePart}(_\\w+)?_u\\d+lambda_u\\d+$inlinedPart")
|
||||
val regex = readAction {
|
||||
val scopeName = (descriptor.lambda.parentOfType<KtFunction>() as? KtNamedFunction)?.name
|
||||
val scopePart = scopeName?.replace(Regex("[^\\p{L}\\d]"), "_")?.let(Regex::escape) ?: ".+"
|
||||
val inlinedPart = Regex.escape(inlineSuffix)
|
||||
Regex("\\\$this\\$${scopePart}(_\\w+)?_u\\d+lambda_u\\d+$inlinedPart")
|
||||
}
|
||||
val lambdaThis = proxy.stackFrame.visibleVariables().filter { it.name().matches(regex) }
|
||||
if (lambdaThis.size == 1) {
|
||||
return postprocess(proxy.stackFrame.getValue(lambdaThis.first()))
|
||||
@@ -155,7 +157,9 @@ private class K2DfaAssistProvider : DfaAssistProvider {
|
||||
return postprocess(proxy.getVariableValue(thisVar))
|
||||
}
|
||||
}
|
||||
val nameString = analyze(anchor) { (pointer?.restoreSymbol() as? KaNamedClassSymbol)?.classId?.asSingleFqName() }
|
||||
val nameString = readAction {
|
||||
analyze(anchor) { (pointer?.restoreSymbol() as? KaNamedClassSymbol)?.classId?.asSingleFqName() }
|
||||
}
|
||||
if (nameString != null) {
|
||||
if (inlineDepth > 0) {
|
||||
val thisName = AsmUtil.INLINE_DECLARATION_SITE_THIS + inlineSuffix
|
||||
@@ -187,32 +191,50 @@ private class K2DfaAssistProvider : DfaAssistProvider {
|
||||
}
|
||||
if (descriptor is KtVariableDescriptor) {
|
||||
val pointer = descriptor.pointer
|
||||
analyze(anchor) {
|
||||
val symbol = pointer.restoreSymbol()
|
||||
if (symbol is KaJavaFieldSymbol && symbol.isStatic) {
|
||||
val classId = (symbol.containingDeclaration as? KaNamedClassSymbol)?.classId
|
||||
if (classId != null) {
|
||||
val declaringClasses = proxy.virtualMachine.classesByName(JvmClassName.byClassId(classId).internalName.replace("/", "."))
|
||||
if (declaringClasses.size == 1) {
|
||||
val declaringClass = declaringClasses.first()
|
||||
val field = DebuggerUtils.findField(declaringClass, symbol.name.identifier)
|
||||
if (field != null && field.isStatic) {
|
||||
return postprocess(declaringClass.getValue(field))
|
||||
}
|
||||
val result = readAction {
|
||||
analyze(anchor) {
|
||||
val symbol = pointer.restoreSymbol()
|
||||
if (symbol is KaJavaFieldSymbol && symbol.isStatic) {
|
||||
val classId = (symbol.containingDeclaration as? KaNamedClassSymbol)?.classId
|
||||
if (classId != null) {
|
||||
val className = JvmClassName.byClassId(classId).internalName.replace("/", ".")
|
||||
val fieldName = symbol.name.identifier
|
||||
return@readAction VariableResult.JavaField(className, fieldName)
|
||||
}
|
||||
return@readAction null
|
||||
}
|
||||
if (symbol is KaVariableSymbol) {
|
||||
val name = symbol.name.asString() + inlineSuffix
|
||||
val expectedType = symbol.returnType
|
||||
val isNonNullPrimitiveType = expectedType.isPrimitive && !expectedType.canBeNull
|
||||
return@readAction VariableResult.Variable(name, symbol.psi, isNonNullPrimitiveType)
|
||||
}
|
||||
}
|
||||
null
|
||||
}
|
||||
when (result) {
|
||||
is VariableResult.JavaField -> {
|
||||
val declaringClasses = proxy.virtualMachine.classesByName(result.className)
|
||||
if (declaringClasses.size == 1) {
|
||||
val declaringClass = declaringClasses.first()
|
||||
val field = DebuggerUtils.findField(declaringClass, result.fieldName)
|
||||
if (field != null && field.isStatic) {
|
||||
return postprocess(declaringClass.getValue(field))
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
if (symbol is KaVariableSymbol) {
|
||||
val name = symbol.name.asString() + inlineSuffix
|
||||
var variable = proxy.visibleVariableByName(name)
|
||||
|
||||
is VariableResult.Variable -> {
|
||||
var variable = proxy.visibleVariableByName(result.name)
|
||||
var value: Value? = null
|
||||
if (variable == null) {
|
||||
val psi = symbol.psi
|
||||
val scope = anchor.getScope()
|
||||
if (psi != null && scope != null && psi.containingFile == scope.containingFile && !scope.isAncestor(psi)) {
|
||||
val psi = result.psi
|
||||
val scope = readAction { anchor.getScope() }
|
||||
if (psi != null && scope != null
|
||||
&& readAction { psi.containingFile == scope.containingFile && !scope.isAncestor(psi) }
|
||||
) {
|
||||
// Captured variable
|
||||
val capturedName = AsmUtil.CAPTURED_PREFIX + name
|
||||
val capturedName = AsmUtil.CAPTURED_PREFIX + result.name
|
||||
variable = proxy.visibleVariableByName(capturedName)
|
||||
if (variable == null) {
|
||||
// Captured variable in Kotlin 1.x
|
||||
@@ -232,8 +254,7 @@ private class K2DfaAssistProvider : DfaAssistProvider {
|
||||
value = postprocess(proxy.getVariableValue(variable))
|
||||
}
|
||||
if (value != null) {
|
||||
val expectedType = symbol.returnType
|
||||
if (inlineDepth > 0 && value.type() is PrimitiveType && !(expectedType.isPrimitive && !expectedType.canBeNull)) {
|
||||
if (inlineDepth > 0 && value.type() is PrimitiveType && !result.isNonNullPrimitiveReturnType) {
|
||||
val typeKind = JvmPrimitiveTypeKind.getKindByName(value.type().name())
|
||||
if (typeKind != null) {
|
||||
val referenceType = proxy.virtualMachine.classesByName(typeKind.boxedFqn).firstOrNull()
|
||||
@@ -242,37 +263,62 @@ private class K2DfaAssistProvider : DfaAssistProvider {
|
||||
}
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
null -> {}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val jdiQualifier = getJdiValueInner(proxy, qualifier, anchor)
|
||||
if (descriptor is KtVariableDescriptor) {
|
||||
val type = (jdiQualifier as? ObjectReference)?.referenceType()
|
||||
val pointer = descriptor.pointer
|
||||
analyze(anchor) {
|
||||
val symbol = pointer.restoreSymbol()
|
||||
if (symbol is KaPropertySymbol) {
|
||||
val parent = symbol.containingDeclaration
|
||||
if (parent is KaNamedClassSymbol && parent.isInline) {
|
||||
// Inline class sole property is represented by inline class itself
|
||||
return jdiQualifier
|
||||
}
|
||||
}
|
||||
if (symbol is KaVariableSymbol && type != null) {
|
||||
val field = DebuggerUtils.findField(type, symbol.name.asString())
|
||||
if (field != null) {
|
||||
return postprocess(jdiQualifier.getValue(field))
|
||||
val result = readAction {
|
||||
analyze(anchor) {
|
||||
val symbol = pointer.restoreSymbol()
|
||||
if (symbol is KaPropertySymbol) {
|
||||
val parent = symbol.containingDeclaration
|
||||
if (parent is KaNamedClassSymbol && parent.isInline) {
|
||||
// Inline class sole property is represented by inline class itself
|
||||
return@readAction QualifierVariableResult.InlineClassProperty
|
||||
}
|
||||
}
|
||||
if (symbol is KaVariableSymbol) {
|
||||
return@readAction QualifierVariableResult.NamedVariable(symbol.name.asString())
|
||||
}
|
||||
null
|
||||
}
|
||||
}
|
||||
when (result) {
|
||||
QualifierVariableResult.InlineClassProperty -> return jdiQualifier
|
||||
is QualifierVariableResult.NamedVariable -> {
|
||||
val type = (jdiQualifier as? ObjectReference)?.referenceType()
|
||||
if (type != null) {
|
||||
val field = DebuggerUtils.findField(type, result.name)
|
||||
if (field != null) {
|
||||
return postprocess(jdiQualifier.getValue(field))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private sealed interface VariableResult {
|
||||
data class JavaField(val className: String, val fieldName: String) : VariableResult
|
||||
data class Variable(val name: String, val psi: PsiElement?, val isNonNullPrimitiveReturnType: Boolean) : VariableResult
|
||||
}
|
||||
|
||||
private sealed interface QualifierVariableResult {
|
||||
object InlineClassProperty : QualifierVariableResult
|
||||
data class NamedVariable(val name: String) : QualifierVariableResult
|
||||
}
|
||||
|
||||
private fun postprocess(value: Value?): Value {
|
||||
return DfaAssistProvider.wrap(EvaluatorValueConverter.unref(value))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user