fix(coverage): cover every line of a multi-line statement - #1339
Merged
Chemaclass merged 3 commits intoSep 6, 2026
Conversation
Bash reports one executed statement to the DEBUG trap on a single line, even when the statement is written over several. #722 handled the backslash chain; every other way a statement spans lines was left out. An array literal written one element per line therefore cost one uncovered line per element -- and on Bash 3.2, which attributes the assignment to its closing `)`, that line is non-executable, so the hit was discarded and the whole array read as uncovered. Multi-line strings and heredoc bodies had the same gap. Adds a small shell lexer, a Bash reference in coverage/lines.sh mirrored in awk, that groups lines into statement spans: a stack of open contexts (single quote, double quote, array literal, command substitution, plain paren) plus a pending heredoc delimiter. Propagation becomes span-max rather than a forward carry, so it works whichever end of the span the trap attributed the statement to. For a backslash chain it produces exactly what the forward carry did. A multi-line `$( )` is deliberately not a span: its interior lines are commands tracked in their own right, and crediting them from the line that opened the substitution would report lines that never ran. `bu_propagate` replaces five copies of the same loop across the LCOV, stats and HTML passes. The differential now compares the scanner as well as the classifier over every `git ls-files '*.sh'`, and asserts each file lexes to a clean end state -- real shell files balance their quotes, so a leftover context is the lexer misreading real code. Related #1338 Claude-Session: https://claude.ai/code/session_01MeysZ63ewZiFTgCDs172XJ
No behaviour change; the differential and the span tests pin that. The escape rule was written twice, once in the double-quoted branch and once in the unquoted one. A backslash escapes the next character in both, and it can never reach either from inside `'..'` -- that context reports nothing but its closing quote, and its branch returns first. So the rule is hoisted between the two, stated once. The stack now lives in a local for the length of the walk and is written back once at the end. Eight statements were longer than the work they did because the global's name is 30 characters. The comment case leaves by `break` rather than `return` so there is a single write-back point. Claude-Session: https://claude.ai/code/session_01MeysZ63ewZiFTgCDs172XJ
editorconfig-checker 4.0.0 reads the ANSI ESC byte in four recorded snapshots as Latin-1 and fails them against the global `charset = utf-8`. All four are pure ASCII -- `file` says so, and no byte in them is >= 0x80. The same job passed on main in August, so the checker upgraded under it; `make lint` has been red on main since, for every branch. Snapshots are byte-exact recordings of terminal output, not hand-written source, so there is no encoding to pin in the first place. Claude-Session: https://claude.ai/code/session_01MeysZ63ewZiFTgCDs172XJ
JesusValeraDev
approved these changes
Sep 6, 2026
Chemaclass
deleted the
fix/1338-multi-line-array-assignments-reported-uncovered
branch
September 6, 2026 10:43
2 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤔 Background
Related #1338
Bash reports one executed statement to the DEBUG trap on a single line, even when it is written over several. #722 handled the backslash chain; every other way a statement spans lines was left out, so an array literal written one element per line cost one uncovered line per element. On Bash 3.2 the assignment is reported on its closing
), which is non-executable, so the hit was discarded and the whole array read as uncovered.💡 Changes
#722backslash chain is unchanged.$( )is deliberately left alone: its interior lines are commands tracked in their own right, and crediting them would report lines that never ran.--coveragerun) — the cost of a per-line lexer. Verified on Bash 3.0, 3.2 and 5.3.