Debugger, tests: Change ADDITIONAL_BREAKPOINT directive format

- Make it extendable and easier to parse
- Allow to create additional function breakpoints
This commit is contained in:
Yan Zhulanow
2020-02-06 21:14:48 +09:00
parent 4244f05307
commit bf890a1540
15 changed files with 49 additions and 44 deletions
@@ -87,7 +87,7 @@ internal class BreakpointCreator(
createLineBreakpoint(breakpointManager, file, lineIndex, ordinal, condition) createLineBreakpoint(breakpointManager, file, lineIndex, ordinal, condition)
} }
comment.startsWith("//FunctionBreakpoint!") -> { comment.startsWith("//FunctionBreakpoint!") -> {
createFunctionBreakpoint(breakpointManager, file, lineIndex) createFunctionBreakpoint(breakpointManager, file, lineIndex, false)
} }
else -> throw AssertionError("Cannot create breakpoint at line ${lineIndex + 1}") else -> throw AssertionError("Cannot create breakpoint at line ${lineIndex + 1}")
} }
@@ -104,19 +104,23 @@ internal class BreakpointCreator(
fun createAdditionalBreakpoints(fileContents: String) { fun createAdditionalBreakpoints(fileContents: String) {
val breakpoints = findLinesWithPrefixesRemoved(fileContents, "// ADDITIONAL_BREAKPOINT: ") val breakpoints = findLinesWithPrefixesRemoved(fileContents, "// ADDITIONAL_BREAKPOINT: ")
for (breakpoint in breakpoints) { for (breakpoint in breakpoints) {
val position = breakpoint.split(".kt:") val chunks = breakpoint.split('/').map { it.trim() }
assert(position.size == 2) { "Couldn't parse position from test directive: directive = $breakpoint" } val fileName = chunks.getOrNull(0) ?: continue
val lineMarker = chunks.getOrNull(1) ?: continue
val kind = chunks.getOrElse(2) { "line" }
val ordinal = chunks.getOrNull(3)?.toInt()
var lineMarker = position[1] val breakpointManager = XDebuggerManager.getInstance(project).breakpointManager
var ordinal: Int? = null
if (lineMarker.contains(":(") && lineMarker.endsWith(")")) { when (kind) {
val lineMarkerAndOrdinal = lineMarker.split(":(") "line" -> createBreakpoint(fileName, lineMarker) { psiFile, lineNumber ->
lineMarker = lineMarkerAndOrdinal[0] createLineBreakpoint(breakpointManager, psiFile, lineNumber + 1, ordinal, null)
ordinal = lineMarkerAndOrdinal[1].substringBefore(")").toInt() }
"fun" -> createBreakpoint(fileName, lineMarker) { psiFile, lineNumber ->
createFunctionBreakpoint(breakpointManager, psiFile, lineNumber, true)
}
else -> error("Unknown breakpoint kind: $kind")
} }
createBreakpoint(position[0], lineMarker, ordinal)
} }
} }
@@ -133,34 +137,35 @@ internal class BreakpointCreator(
return null return null
} }
private fun createBreakpoint(fileName: String, lineMarker: String, ordinal: Int?) { private fun createBreakpoint(fileName: String, lineMarker: String, action: (PsiFile, Int) -> Unit) {
val sourceFiles = runReadAction { val sourceFiles = runReadAction {
FilenameIndex.getAllFilesByExt(project, "kt") FilenameIndex.getAllFilesByExt(project, "kt")
.filter { it.name.contains(fileName) && it.contentsToByteArray().toString(Charsets.UTF_8).contains(lineMarker) } .filter { it.name == fileName && it.contentsToByteArray().toString(Charsets.UTF_8).contains(lineMarker) }
} }
assert(sourceFiles.size == 1) { "One source file should be found: name = $fileName, sourceFiles = $sourceFiles" } val sourceFile = sourceFiles.singleOrNull()
?: error("Single source file should be found: name = $fileName, sourceFiles = $sourceFiles")
val runnable = Runnable { val runnable = Runnable {
val psiSourceFile = PsiManager.getInstance(project).findFile(sourceFiles.first())!! val psiSourceFile = PsiManager.getInstance(project).findFile(sourceFile)
?: error("Psi file not found for $sourceFile")
val breakpointManager = XDebuggerManager.getInstance(project).breakpointManager
val document = PsiDocumentManager.getInstance(project).getDocument(psiSourceFile)!! val document = PsiDocumentManager.getInstance(project).getDocument(psiSourceFile)!!
val index = psiSourceFile.text!!.indexOf(lineMarker) val index = psiSourceFile.text!!.indexOf(lineMarker)
val lineNumber = document.getLineNumber(index) + 1 // lineMarker is for previous line val lineNumber = document.getLineNumber(index)
action(psiSourceFile, lineNumber)
createLineBreakpoint(breakpointManager, psiSourceFile, lineNumber, ordinal, null)
} }
DebuggerInvocationUtil.invokeAndWait(project, runnable, ModalityState.defaultModalityState()) DebuggerInvocationUtil.invokeAndWait(project, runnable, ModalityState.defaultModalityState())
} }
private fun createFunctionBreakpoint(breakpointManager: XBreakpointManager, file: PsiFile, lineIndex: Int) { private fun createFunctionBreakpoint(breakpointManager: XBreakpointManager, file: PsiFile, lineIndex: Int, fromLibrary: Boolean) {
val breakpointType = findBreakpointType(KotlinFunctionBreakpointType::class.java) val breakpointType = findBreakpointType(KotlinFunctionBreakpointType::class.java)
val breakpoint = createBreakpointOfType(breakpointManager, breakpointType, lineIndex, file.virtualFile) val breakpoint = createBreakpointOfType(breakpointManager, breakpointType, lineIndex, file.virtualFile)
if (breakpoint is KotlinFunctionBreakpoint) { if (breakpoint is KotlinFunctionBreakpoint) {
logger("FunctionBreakpoint created at ${file.virtualFile.name}:${lineIndex + 1}") val lineNumberSuffix = if (fromLibrary) "" else ":${lineIndex + 1}"
logger("FunctionBreakpoint created at ${file.virtualFile.name}$lineNumberSuffix")
} }
} }
@@ -55,23 +55,23 @@ class A {
} }
} }
// ADDITIONAL_BREAKPOINT: isInsideInlineLambdaInLibrary.kt:Breakpoint1:(1) // ADDITIONAL_BREAKPOINT: isInsideInlineLambdaInLibrary.kt / Breakpoint1 / line / 1
// EXPRESSION: it + 11 // EXPRESSION: it + 11
// RESULT: 12: I // RESULT: 12: I
// ADDITIONAL_BREAKPOINT: isInsideInlineLambdaInLibrary.kt:Breakpoint2:(1) // ADDITIONAL_BREAKPOINT: isInsideInlineLambdaInLibrary.kt / Breakpoint2 / line / 1
// EXPRESSION: it + 12 // EXPRESSION: it + 12
// RESULT: 14: I // RESULT: 14: I
// ADDITIONAL_BREAKPOINT: isInsideInlineLambdaInLibrary.kt:Breakpoint3:(1) // ADDITIONAL_BREAKPOINT: isInsideInlineLambdaInLibrary.kt / Breakpoint3 / line / 1
// EXPRESSION: it + 13 // EXPRESSION: it + 13
// RESULT: 16: I // RESULT: 16: I
// ADDITIONAL_BREAKPOINT: isInsideInlineLambdaInLibrary.kt:Breakpoint4:(1) // ADDITIONAL_BREAKPOINT: isInsideInlineLambdaInLibrary.kt / Breakpoint4 / line / 1
// EXPRESSION: it + 14 // EXPRESSION: it + 14
// RESULT: 18: I // RESULT: 18: I
// ADDITIONAL_BREAKPOINT: isInsideInlineLambdaInLibrary.kt:Breakpoint5:(1) // ADDITIONAL_BREAKPOINT: isInsideInlineLambdaInLibrary.kt / Breakpoint5 / line / 1
// EXPRESSION: it + 15 // EXPRESSION: it + 15
// RESULT: 20: I // RESULT: 20: I
@@ -9,23 +9,23 @@ fun main(args: Array<String>) {
customLib.simpleLibFile.foo() customLib.simpleLibFile.foo()
} }
// ADDITIONAL_BREAKPOINT: 1.kt:public fun oneFunSameFileNameFun(): Int { // ADDITIONAL_BREAKPOINT: a1.kt / public fun oneFunSameFileNameFun(): Int {
// EXPRESSION: 1 + 1 // EXPRESSION: 1 + 1
// RESULT: 2: I // RESULT: 2: I
// ADDITIONAL_BREAKPOINT: 1.kt:public fun twoFunDifferentSignatureFun(): Int { // ADDITIONAL_BREAKPOINT: a1.kt / public fun twoFunDifferentSignatureFun(): Int {
// EXPRESSION: 1 + 2 // EXPRESSION: 1 + 2
// RESULT: 3: I // RESULT: 3: I
// ADDITIONAL_BREAKPOINT: 1.kt:public val foo: Int = // ADDITIONAL_BREAKPOINT: a1.kt / public val foo: Int =
// EXPRESSION: 1 + 3 // EXPRESSION: 1 + 3
// RESULT: 4: I // RESULT: 4: I
// ADDITIONAL_BREAKPOINT: 1.kt:public fun breakpointOnLocalPropertyFun(): Int { // ADDITIONAL_BREAKPOINT: a1.kt / public fun breakpointOnLocalPropertyFun(): Int {
// EXPRESSION: 1 + 4 // EXPRESSION: 1 + 4
// RESULT: 5: I // RESULT: 5: I
// ADDITIONAL_BREAKPOINT: simpleLibFile.kt:public fun foo() { // ADDITIONAL_BREAKPOINT: simpleLibFile.kt / public fun foo() {
// EXPRESSION: 1 + 5 // EXPRESSION: 1 + 5
// RESULT: 6: I // RESULT: 6: I
@@ -5,7 +5,7 @@ fun main(args: Array<String>) {
customLib.localFunInLibraryCustomLib.localFunInLibraryCustomLibMainFun() customLib.localFunInLibraryCustomLib.localFunInLibraryCustomLibMainFun()
} }
// ADDITIONAL_BREAKPOINT: localFunCustomLib.kt:localFunInLibraryCustomLibProperty // ADDITIONAL_BREAKPOINT: localFunCustomLib.kt / localFunInLibraryCustomLibProperty
// EXPRESSION: localFun() // EXPRESSION: localFun()
// RESULT: 1: I // RESULT: 1: I
@@ -9,8 +9,8 @@ fun main(args: Array<String>) {
// RESUME: 2 // RESUME: 2
// ADDITIONAL_BREAKPOINT: inlineFunInLibrary.kt:public inline fun inlineFun // ADDITIONAL_BREAKPOINT: inlineFunInLibrary.kt / public inline fun inlineFun
// ADDITIONAL_BREAKPOINT: inlineFunInLibrary.kt: Breakpoint 2 // ADDITIONAL_BREAKPOINT: inlineFunInLibrary.kt / Breakpoint 2
// FILE: customLib/inlineFunInLibrary/inlineFunInLibrary.kt // FILE: customLib/inlineFunInLibrary/inlineFunInLibrary.kt
package customLib.inlineFunInLibrary package customLib.inlineFunInLibrary
@@ -6,7 +6,7 @@ fun main(args: Array<String>) {
fileWithInternal.test() fileWithInternal.test()
} }
// ADDITIONAL_BREAKPOINT: fileWithInternal.kt:Breakpoint // ADDITIONAL_BREAKPOINT: fileWithInternal.kt / Breakpoint
// EXPRESSION: 1 // EXPRESSION: 1
// RESULT: 1: I // RESULT: 1: I
@@ -11,7 +11,7 @@ fun main(args: Array<String>) {
} }
} }
// ADDITIONAL_BREAKPOINT: inlineFunctionWithBreakpoint.kt:inline fun myFun // ADDITIONAL_BREAKPOINT: inlineFunctionWithBreakpoint.kt / inline fun myFun
// FILE: inlineFunctionWithBreakpoint.kt // FILE: inlineFunctionWithBreakpoint.kt
package inlineFunctionWithBreakpoint package inlineFunctionWithBreakpoint
@@ -12,7 +12,7 @@ fun unused() {
secondInline() secondInline()
} }
// ADDITIONAL_BREAKPOINT: manyFilesWithInlineCalls1.First.kt: Breakpoint 1 // ADDITIONAL_BREAKPOINT: manyFilesWithInlineCalls1.First.kt / Breakpoint 1
// FILE: manyFilesWithInlineCalls1.First.kt // FILE: manyFilesWithInlineCalls1.First.kt
package manyFilesWithInlineCalls1.first package manyFilesWithInlineCalls1.first
@@ -12,7 +12,7 @@ fun unused() {
firstInline() firstInline()
} }
// ADDITIONAL_BREAKPOINT: manyFilesWithInlineCalls2.Second.kt: Breakpoint 1 // ADDITIONAL_BREAKPOINT: manyFilesWithInlineCalls2.Second.kt / Breakpoint 1
// FILE: manyFilesWithInlineCalls2.First.kt // FILE: manyFilesWithInlineCalls2.First.kt
package manyFilesWithInlineCalls2.first package manyFilesWithInlineCalls2.first
@@ -16,7 +16,7 @@ fun secondCall() {
} }
// RESUME: 2 // RESUME: 2
// ADDITIONAL_BREAKPOINT: severalInlineCallsFromOtherFile.Other.kt: Breakpoint 1 // ADDITIONAL_BREAKPOINT: severalInlineCallsFromOtherFile.Other.kt / Breakpoint 1
// FILE: severalInlineCallsFromOtherFile.Other.kt // FILE: severalInlineCallsFromOtherFile.Other.kt
package severalInlineCallsFromOtherFile package severalInlineCallsFromOtherFile
@@ -5,7 +5,7 @@ fun main(args: Array<String>) {
customLib.functionInLibrary.simpleFun() customLib.functionInLibrary.simpleFun()
} }
// ADDITIONAL_BREAKPOINT: functionInLibrary.kt:public inline fun simpleFun() // ADDITIONAL_BREAKPOINT: functionInLibrary.kt / public inline fun simpleFun()
// STEP_INTO: 5 // STEP_INTO: 5
// FILE: customLib/functionInLibrary/functionInLibrary.kt // FILE: customLib/functionInLibrary/functionInLibrary.kt
@@ -5,7 +5,7 @@ fun main(args: Array<String>) {
inlineInObject.other.TestInlineInObject.inlineFun() inlineInObject.other.TestInlineInObject.inlineFun()
} }
// ADDITIONAL_BREAKPOINT: inlineInObject.Other.kt: Breakpoint 1 // ADDITIONAL_BREAKPOINT: inlineInObject.Other.kt / Breakpoint 1
// FILE: inlineInObject.Other.kt // FILE: inlineInObject.Other.kt
package inlineInObject.other package inlineInObject.other
@@ -5,7 +5,7 @@ fun main(args: Array<String>) {
inlineFun() inlineFun()
} }
// ADDITIONAL_BREAKPOINT: stopInInlineInOtherFile.Other.kt: Breakpoint 1 // ADDITIONAL_BREAKPOINT: stopInInlineInOtherFile.Other.kt / Breakpoint 1
// FILE: stopInInlineInOtherFile.Other.kt // FILE: stopInInlineInOtherFile.Other.kt
package stopInInlineInOtherFile package stopInInlineInOtherFile
@@ -6,7 +6,7 @@ fun main(args: Array<String>) {
val i = 1 val i = 1
} }
// ADDITIONAL_BREAKPOINT: stopInInlineInOtherFileWithLambdaArgument.Other.kt: Breakpoint 1 // ADDITIONAL_BREAKPOINT: stopInInlineInOtherFileWithLambdaArgument.Other.kt / Breakpoint 1
// FILE: stopInInlineInOtherFileWithLambdaArgument.Other.kt // FILE: stopInInlineInOtherFileWithLambdaArgument.Other.kt
package stopInInlineInOtherFileWithLambdaArgument package stopInInlineInOtherFileWithLambdaArgument
@@ -19,7 +19,7 @@ fun main(args: Array<String>) {
AA().other() AA().other()
} }
// ADDITIONAL_BREAKPOINT: stopInWrongClass.Other.kt: Breakpoint 1 // ADDITIONAL_BREAKPOINT: stopInWrongClass.Other.kt / Breakpoint 1
// FILE: stopInWrongClass.Other.kt // FILE: stopInWrongClass.Other.kt
package stopInWrongClass package stopInWrongClass