Debugger: allow Evaluate Expression in context of File (for some synthetic methods or when file was changed during debug and breakpoint line no longer match the actual line)
This commit is contained in:
@@ -78,6 +78,10 @@ public fun JetCodeFragment.getScopeAndDataFlowForAnalyzeFragment(
|
|||||||
scopeForContextElement = contextForElement[BindingContext.RESOLUTION_SCOPE, correctedContext]
|
scopeForContextElement = contextForElement[BindingContext.RESOLUTION_SCOPE, correctedContext]
|
||||||
dataFlowInfo = contextForElement.getDataFlowInfo(correctedContext)
|
dataFlowInfo = contextForElement.getDataFlowInfo(correctedContext)
|
||||||
}
|
}
|
||||||
|
is JetFile -> {
|
||||||
|
scopeForContextElement = resolveSession.getFileScopeProvider().getFileScope(context)
|
||||||
|
dataFlowInfo = DataFlowInfo.EMPTY
|
||||||
|
}
|
||||||
else -> return null
|
else -> return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,9 +56,7 @@ class KotlinEditorTextProvider : EditorTextProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun findExpressionInner(element: PsiElement, allowMethodCalls: Boolean): JetExpression? {
|
fun findExpressionInner(element: PsiElement, allowMethodCalls: Boolean): JetExpression? {
|
||||||
if (PsiTreeUtil.getParentOfType(element, javaClass<JetUserType>(), javaClass<JetImportDirective>(), javaClass<JetPackageDirective>()) != null) {
|
if (!isAcceptedAsCodeFragmentContext(element)) return null
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
val jetElement = PsiTreeUtil.getParentOfType(element, javaClass<JetElement>())
|
val jetElement = PsiTreeUtil.getParentOfType(element, javaClass<JetElement>())
|
||||||
if (jetElement == null) return null
|
if (jetElement == null) return null
|
||||||
@@ -116,6 +114,14 @@ class KotlinEditorTextProvider : EditorTextProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val NOT_ACCEPTED_AS_CONTEXT_TYPES =
|
||||||
|
arrayOf(javaClass<JetUserType>(), javaClass<JetImportDirective>(), javaClass<JetPackageDirective>())
|
||||||
|
|
||||||
|
fun isAcceptedAsCodeFragmentContext(element: PsiElement): Boolean {
|
||||||
|
return element.javaClass !in NOT_ACCEPTED_AS_CONTEXT_TYPES &&
|
||||||
|
PsiTreeUtil.getParentOfType(element, *NOT_ACCEPTED_AS_CONTEXT_TYPES) == null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -131,10 +131,11 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val expressionAtOffset = PsiTreeUtil.findElementOfClassAtOffset(elementAt.getContainingFile()!!, elementAt.getTextOffset(), javaClass<JetExpression>(), false)
|
val expressionAtOffset = PsiTreeUtil.findElementOfClassAtOffset(elementAt.getContainingFile()!!, elementAt.getTextOffset(), javaClass<JetExpression>(), false)
|
||||||
if (expressionAtOffset != null) {
|
if (expressionAtOffset != null && KotlinEditorTextProvider.isAcceptedAsCodeFragmentContext(elementAt)) {
|
||||||
return expressionAtOffset
|
return expressionAtOffset
|
||||||
}
|
}
|
||||||
return KotlinEditorTextProvider.findExpressionInner(elementAt, true)
|
|
||||||
|
return KotlinEditorTextProvider.findExpressionInner(elementAt, true) ?: elementAt.getContainingFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
//internal for tests
|
//internal for tests
|
||||||
|
|||||||
+7
-6
@@ -77,11 +77,6 @@ fun getFunctionForExtractedFragment(
|
|||||||
val contextElement = getExpressionToAddDebugExpressionBefore(tmpFile, codeFragment.getContext(), breakpointLine)
|
val contextElement = getExpressionToAddDebugExpressionBefore(tmpFile, codeFragment.getContext(), breakpointLine)
|
||||||
if (contextElement == null) return null
|
if (contextElement == null) return null
|
||||||
|
|
||||||
// Don't evaluate smth when breakpoint is on package directive (ex. for package classes)
|
|
||||||
if (contextElement is JetFile) {
|
|
||||||
throw EvaluateExceptionUtil.createEvaluateException("Cannot perform an action at this breakpoint ${breakpointFile.getName()}:${breakpointLine}")
|
|
||||||
}
|
|
||||||
|
|
||||||
addImportsToFile(codeFragment.importsAsImportList(), tmpFile)
|
addImportsToFile(codeFragment.importsAsImportList(), tmpFile)
|
||||||
|
|
||||||
val newDebugExpressions = addDebugExpressionBeforeContextElement(codeFragment, contextElement)
|
val newDebugExpressions = addDebugExpressionBeforeContextElement(codeFragment, contextElement)
|
||||||
@@ -158,7 +153,7 @@ private fun getExpressionToAddDebugExpressionBefore(tmpFile: JetFile, contextEle
|
|||||||
return getExpressionToAddDebugExpressionBefore(tmpFile, containingFile.getContext(), line)
|
return getExpressionToAddDebugExpressionBefore(tmpFile, containingFile.getContext(), line)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun shouldStop(el: PsiElement?, p: PsiElement?) = p is JetBlockExpression || el is JetDeclaration
|
fun shouldStop(el: PsiElement?, p: PsiElement?) = p is JetBlockExpression || el is JetDeclaration || el is JetFile
|
||||||
|
|
||||||
var elementAt = tmpFile.getElementInCopy(contextElement)
|
var elementAt = tmpFile.getElementInCopy(contextElement)
|
||||||
|
|
||||||
@@ -192,6 +187,12 @@ private fun addDebugExpressionBeforeContextElement(codeFragment: JetCodeFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
val elementBefore = when {
|
val elementBefore = when {
|
||||||
|
contextElement is JetFile -> {
|
||||||
|
val fakeFunction = psiFactory.createFunction("fun _debug_fun_() {}")
|
||||||
|
contextElement.add(psiFactory.createNewLine())
|
||||||
|
val newFakeFun = contextElement.add(fakeFunction) as JetNamedFunction
|
||||||
|
newFakeFun.getBodyExpression()!!.getLastChild()
|
||||||
|
}
|
||||||
contextElement is JetProperty && !contextElement.isLocal() -> {
|
contextElement is JetProperty && !contextElement.isLocal() -> {
|
||||||
val delegateExpressionOrInitializer = contextElement.getDelegateExpressionOrInitializer()
|
val delegateExpressionOrInitializer = contextElement.getDelegateExpressionOrInitializer()
|
||||||
if (delegateExpressionOrInitializer != null) {
|
if (delegateExpressionOrInitializer != null) {
|
||||||
|
|||||||
Reference in New Issue
Block a user