Skip to content

parser: truncated blocks are emitted, -1 line numbers navigate to the wrong file, unicode filenames are invisible #7

Description

@GabrielBBaldez

Three parser bugs in core/src/main/java/io/github/gabrielbbaldez/stacktale/idea/StReportParser.java, all of which end with the user looking at the wrong thing or at nothing. :core has no IntelliJ dependency, so each is testable with a plain unit test.

1. Truncated blocks are emitted, and the spec says they must not

FORMAT.md is explicit: a block whose closing line is absent is incomplete, and parsers must discard it rather than emit a partial entry.

The inner loop at :41-54 breaks on the next START or on end-of-input and then calls parseBlock unconditionally — there is no check that the block ended in END. The existing test aTruncatedTrailingBlockIsStillSurfaced asserts the wrong behaviour as if it were intended, so it needs flipping too.

Why it is visible: the writer emits the header, the session marker and the block as separate writes, and a multi-KB block is not an atomic append. A poll landing in that window shows a report with a headline, no culprit, no stack and no story; double-clicking it does nothing. It heals on the next poll, so it reads as random rather than reproducible.

Fix: only accept a block whose last line starts with END. Keep the trailing partial and re-evaluate it on the next refresh, so a genuinely killed process drops the tail instead of flickering it.

2. A frame with no line number navigates to the wrong file

The frame regex at :21 requires \d+. But the library writes getLineNumber() verbatim (StackDistiller.java:203 in the main repo), and StackTraceElement.getLineNumber() returns -1 when the class was compiled without -g:lines and -2 for a native method. A line such as at OrderService.confirm(OrderService.java:-1) <- YOUR CODE is legal, routinely produced, and matches nothing.

The marked culprit then yields no frame, and we fall back to the first frame (:77) — which for a wrapped exception is the frame on the wrapped by: line. The user double-clicks an IllegalStateException attributed to OrderService and silently lands in CheckoutService.java:88.

Fix: allow -?\d+; treat a line number <= 0 as found but not navigable; only fall back to the first frame when the block contained no marked frame at all.

Related, same method: Integer.parseInt at :70 throws out of parse() on an absurd line number, which — until the refresh loop is hardened — kills the poll for the session. Parse into a long and clamp.

3. Non-ASCII source file names are invisible

[\w$]+ is ASCII-only in Java without UNICODE_CHARACTER_CLASS. Names like Acao.java, Groesse.java or a CJK class name are legal Java source names — Java identifiers accept Unicode letters — so those frames match nothing and the report ends up with no culprit at all.

Fix: [\p{L}\p{N}_$]+ with Pattern.UNICODE_CHARACTER_CLASS, or simply [^\s:()]+\.\w+. Add .kts while you are there.

Verify

A case in core/src/test/java/.../StReportParserTest.java per bug, and flip aTruncatedTrailingBlockIsStillSurfaced. ./gradlew :core:test needs no IDE download.

Worth doing at the same time: the main repo ships conformance fixtures at stacktale-core/src/test/resources/golden/*.txt that FORMAT.md declares authoritative, and neither editor parser uses them. Vendoring those in would have caught all three of these.

The same three bugs exist in the VS Code extension — the parsers are deliberate twins, so please keep the fixes in step.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingformatThe st/1 / st-json/1 report format (public API)good first issueGood for newcomers

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions