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:
Natalia Ukhorskaya
2015-07-16 13:09:26 +03:00
parent 75edfa6527
commit ec3c667f38
4 changed files with 23 additions and 11 deletions
@@ -78,6 +78,10 @@ public fun JetCodeFragment.getScopeAndDataFlowForAnalyzeFragment(
scopeForContextElement = contextForElement[BindingContext.RESOLUTION_SCOPE, correctedContext]
dataFlowInfo = contextForElement.getDataFlowInfo(correctedContext)
}
is JetFile -> {
scopeForContextElement = resolveSession.getFileScopeProvider().getFileScope(context)
dataFlowInfo = DataFlowInfo.EMPTY
}
else -> return null
}
@@ -56,9 +56,7 @@ class KotlinEditorTextProvider : EditorTextProvider {
}
fun findExpressionInner(element: PsiElement, allowMethodCalls: Boolean): JetExpression? {
if (PsiTreeUtil.getParentOfType(element, javaClass<JetUserType>(), javaClass<JetImportDirective>(), javaClass<JetPackageDirective>()) != null) {
return null
}
if (!isAcceptedAsCodeFragmentContext(element)) return null
val jetElement = PsiTreeUtil.getParentOfType(element, javaClass<JetElement>())
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)
if (expressionAtOffset != null) {
if (expressionAtOffset != null && KotlinEditorTextProvider.isAcceptedAsCodeFragmentContext(elementAt)) {
return expressionAtOffset
}
return KotlinEditorTextProvider.findExpressionInner(elementAt, true)
return KotlinEditorTextProvider.findExpressionInner(elementAt, true) ?: elementAt.getContainingFile()
}
//internal for tests
@@ -77,11 +77,6 @@ fun getFunctionForExtractedFragment(
val contextElement = getExpressionToAddDebugExpressionBefore(tmpFile, codeFragment.getContext(), breakpointLine)
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)
val newDebugExpressions = addDebugExpressionBeforeContextElement(codeFragment, contextElement)
@@ -158,7 +153,7 @@ private fun getExpressionToAddDebugExpressionBefore(tmpFile: JetFile, contextEle
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)
@@ -192,6 +187,12 @@ private fun addDebugExpressionBeforeContextElement(codeFragment: JetCodeFragment
}
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() -> {
val delegateExpressionOrInitializer = contextElement.getDelegateExpressionOrInitializer()
if (delegateExpressionOrInitializer != null) {