(javapOut: string)
| 338 | } |
| 339 | |
| 340 | parseAsmForClass(javapOut: string) { |
| 341 | const textsBeforeMethod: string[] = []; |
| 342 | const methods: {instructions: any[]; startLine?: number}[] = []; |
| 343 | // javap output puts ` Code:` after every signature. (Line will not be shown to user) |
| 344 | // We use this to find the individual methods. |
| 345 | // Before the first `Code:` occurrence, there is the method signature as well as the name of the class. |
| 346 | // Subsequent matches are always followed by lists of assembly instructions as well as line info mappings |
| 347 | |
| 348 | // Regex idea: make sure `Code:` is the only thing on the line. Also consume trailing line ending! |
| 349 | const [classNameAndFirstMethodSignature, ...codeAndLineNumberTables] = javapOut.split(/^\s+Code:\s*$\r?\n/m); |
| 350 | textsBeforeMethod.push(classNameAndFirstMethodSignature.trimEnd()); // possible trailing \r on windows |
| 351 | |
| 352 | for (const codeAndLineNumberTable of codeAndLineNumberTables) { |
| 353 | const method = { |
| 354 | instructions: [], |
| 355 | } as (typeof methods)[0]; |
| 356 | methods.push(method); |
| 357 | |
| 358 | for (const codeLineCandidate of utils.splitLines(codeAndLineNumberTable)) { |
| 359 | // Match |
| 360 | // 1: invokespecial #1 // Method java/lang/Object."<init>":()V |
| 361 | // Or match lines inside inside a lookupswitch instruction like: |
| 362 | // 8: <code> |
| 363 | // -1: <code> |
| 364 | // default: <code> |
| 365 | const match = codeLineCandidate.match(/\s+([\d-]+|default): (.*)/); |
| 366 | if (match) { |
| 367 | const instrOffset = Number.parseInt(match[1], 10); |
| 368 | method.instructions.push({ |
| 369 | instrOffset: instrOffset, |
| 370 | // Should an instruction ever not be followed by a line number table, |
| 371 | // it might contain a trailing \r on Windows -> trim it, otherwise this would not be necessary |
| 372 | text: codeLineCandidate.trimEnd(), |
| 373 | }); |
| 374 | } else { |
| 375 | // Attempt to match the closing } of a lookupswitch. If we don't include the closing bracket, then |
| 376 | // the brackets will be misaligned, and it may be confusing to read. |
| 377 | const isClosingCurlyBrace = codeLineCandidate.match(/\s+}/); |
| 378 | if (isClosingCurlyBrace) { |
| 379 | // Put closing curly brace in asm output |
| 380 | method.instructions.push({ |
| 381 | text: codeLineCandidate.trimEnd(), |
| 382 | }); |
| 383 | continue; |
| 384 | } |
| 385 | break; |
| 386 | } |
| 387 | } |
| 388 | |
| 389 | const lineRegex = /line\s*(\d+):\s*(\d+)/g; |
| 390 | let m; |
| 391 | let currentInstr = 0; |
| 392 | let currentSourceLine = -1; |
| 393 | let lastIndex = -1; |
| 394 | do { |
| 395 | m = lineRegex.exec(codeAndLineNumberTable); |
| 396 | if (m) { |
| 397 | // If exec doesn't find a match anymore, lineRegex.lastIndex will be reset to 0 |
no test coverage detected