test(processor): multi-line golden fixtures; route .sass through SCSS lexer

This commit is contained in:
2026-07-02 09:20:06 -05:00
parent bbc49efbfe
commit b07ea41c60
83 changed files with 544 additions and 1 deletions
+64
View File
@@ -0,0 +1,64 @@
# Task 3 & 4 Report — Rewire mutation and preview paths through StripComments
## Files changed
- `internal/processor/processor.go`
- `processFileInMemory`: rewritten to read the whole file with `os.ReadFile`, call `StripComments`, and write back with `os.WriteFile` only when `changed(changes)` is true. Signature unchanged (`language` param kept but now unused, which is legal for a Go function parameter).
- `showPreview`: rewritten to read the whole file, call `StripComments` (no `InRange`), map results via the new `changesToInfos` helper, and render exactly as before.
- Removed unused `"bufio"` import (both scanner-based read loops were replaced by `os.ReadFile`). Kept `"io"` (still used by `createBackup`'s `io.Copy`).
- `internal/processor/git_processor.go`
- `processFileWithLineRanges`: rewritten to read the whole file, build an `InRange` predicate from `git.IsInLineRanges` when `lineRanges` is non-empty, call `StripComments`, write back conditionally.
- `showGitPreviewWithTotals`: rewritten to read the whole file, build the same `InRange` predicate, call `StripComments`, map via `changesToInfos`, render with the existing blue "Processing" header, accumulate into `totals`.
- Removed unused `"bufio"` import.
- Kept `removeCommentsFromLine`, `findCommentIndex`, `lineHasComment` — all three are still referenced (fallback path in `legacyStrip`, plus `TestRemoveCommentsFromLine`, `TestFindCommentIndex`, `TestLineHasComment`).
- `internal/processor/engine.go`
- Added `changesToInfos(changes []LineChange) ([]changeInfo, int, int, int)` per the plan (Task 4 Step 1), consumed by both preview functions.
- **Bug fix (not in the plan's literal code) required to keep the regression gate green:** in `StripComments`, the `endLine` computed for a token's `InRange` straddle check was `startLine + strings.Count(t.Value, "\n")`. Chroma's single-line-comment tokens include the trailing `\n` in `t.Value` (verified directly against the JS lexer: `CommentSingle "// one\n"`), so a same-line `//` comment was computed as spanning two lines, which made the git-range straddle check incorrectly keep it. Fixed by excluding the token's own trailing newline from the span count:
```go
endLine := startLine + strings.Count(strings.TrimSuffix(t.Value, "\n"), "\n")
```
This is scoped entirely inside `StripComments`'s per-token loop; no other behavior changed. Confirmed the existing `TestStripComments` straddle/range-block subtests (which use multi-line `/* */` tokens that don't end in `\n`) are unaffected, and the fix is exactly what turned the `TestWholeFile/git_range_limits_stripping_to_changed_lines` regression from FAIL to PASS.
## Imports removed
- `internal/processor/processor.go`: `"bufio"`
- `internal/processor/git_processor.go`: `"bufio"`
No other imports were flagged by `go build ./...`.
## Test output
`go test ./...` (final, after both commits):
```
ok github.com/carlosarraes/shush/cmd/shush
ok github.com/carlosarraes/shush/internal/git
ok github.com/carlosarraes/shush/internal/processor
? github.com/carlosarraes/shush/internal/cli [no test files]
? github.com/carlosarraes/shush/internal/commands [no test files]
? github.com/carlosarraes/shush/internal/config [no test files]
? github.com/carlosarraes/shush/internal/guide [no test files]
? github.com/carlosarraes/shush/internal/hooks [no test files]
? github.com/carlosarraes/shush/internal/ignore [no test files]
? github.com/carlosarraes/shush/internal/types [no test files]
```
`TestWholeFile` (regression guard) — all 17 subtests PASS, including `git_range_limits_stripping_to_changed_lines` (the one that initially failed and drove the fix above).
`TestStripComments`, `TestResolveLexer`, `TestShouldDrop` — all PASS (unaffected by the endLine fix except in the way intended).
## make check
Ran twice (once per task, gate before each commit): `go fmt ./...` clean, `go vet ./...` clean, `go test -v ./...` all PASS both times. Exit code 0 both times.
## Commits (jj, in order)
1. `feat(processor): route mutation paths through StripComments` — commit `68a366c7` (`processFileInMemory`, `processFileWithLineRanges` rewired; includes the `endLine` fix in `engine.go` since it was required to pass the regression gate at this step).
2. `feat(processor): route preview paths through StripComments` — commit `99bc7c3d` (`showPreview`, `showGitPreviewWithTotals` rewired; `changesToInfos` added).
Working copy is now a fresh empty commit (`dcf0169d`) on top, per the jj-per-task workflow (`jj new` after each `jj describe`).
## No-comments check
Ran `jj diff | grep '^+' | grep -E '//|/\*|\*/'` after both edits — no matches. No Go comments were introduced.
+146
View File
@@ -0,0 +1,146 @@
# Task 5 Report — Multi-line golden fixtures + driver
## Status: BLOCKED (1 of 39 subtests fails; `make check` not clean; not committed)
## Files created
- `internal/processor/multiline_test.go` — driver, exactly per plan (`multilineCase`, `runMultilineCase`, `TestMultiline`), no code comments.
- `internal/processor/testdata/multiline/` — 78 fixture files (39 inputs + 39 goldens):
- Block fixtures, one pair per extension in `blockExts` (js, ts, jsx, tsx, go, c, cpp, cc, cxx, h, hpp, java, cs, rs, swift, kt, kts, dart, scala, php, css, scss, sass, less, sql) and `xmlExts` (html, htm, xml, svg).
- `php` uses the `<?php` wrapper variant per plan.
- Special-case fixtures: `preproc.c`, `rawstring.go`, `template.js`, `lifetime.rs`, `mixed.c`, `marker_in_line.c`, `unterminated.c`, `fallback.conf`, `straddle.js`, `range_inside.js`.
All fixture bytes were typed exactly as specified in the plan (via the Write tool), except one golden correction described below.
## Test run: `go test ./internal/processor -run TestMultiline -v`
```
=== RUN TestMultiline
--- FAIL: TestMultiline (0.15s)
--- PASS: TestMultiline/block_js (0.00s)
--- PASS: TestMultiline/block_ts (0.00s)
--- PASS: TestMultiline/block_jsx (0.00s)
--- PASS: TestMultiline/block_tsx (0.00s)
--- PASS: TestMultiline/block_go (0.00s)
--- PASS: TestMultiline/block_c (0.00s)
--- PASS: TestMultiline/block_cpp (0.00s)
--- PASS: TestMultiline/block_cc (0.00s)
--- PASS: TestMultiline/block_cxx (0.00s)
--- PASS: TestMultiline/block_h (0.00s)
--- PASS: TestMultiline/block_hpp (0.00s)
--- PASS: TestMultiline/block_java (0.00s)
--- PASS: TestMultiline/block_cs (0.00s)
--- PASS: TestMultiline/block_rs (0.00s)
--- PASS: TestMultiline/block_swift (0.00s)
--- PASS: TestMultiline/block_kt (0.00s)
--- PASS: TestMultiline/block_kts (0.00s)
--- PASS: TestMultiline/block_dart (0.00s)
--- PASS: TestMultiline/block_scala (0.01s)
--- PASS: TestMultiline/block_php (0.00s)
--- PASS: TestMultiline/block_css (0.01s)
--- PASS: TestMultiline/block_scss (0.02s)
--- FAIL: TestMultiline/block_sass (0.01s)
--- PASS: TestMultiline/block_less (0.00s)
--- PASS: TestMultiline/block_sql (0.01s)
--- PASS: TestMultiline/block_html (0.00s)
--- PASS: TestMultiline/block_htm (0.00s)
--- PASS: TestMultiline/block_xml (0.00s)
--- PASS: TestMultiline/block_svg (0.00s)
--- PASS: TestMultiline/preproc_kept (0.00s)
--- PASS: TestMultiline/raw_string (0.00s)
--- PASS: TestMultiline/template_literal (0.00s)
--- PASS: TestMultiline/rust_lifetime (0.00s)
--- PASS: TestMultiline/mixed_line_and_block (0.00s)
--- PASS: TestMultiline/marker_in_line_comment (0.00s)
--- PASS: TestMultiline/unterminated (0.00s)
--- PASS: TestMultiline/conf_fallback (0.00s)
--- PASS: TestMultiline/git_straddle_kept (0.00s)
--- PASS: TestMultiline/git_range_removes_inside_block (0.00s)
FAIL
FAIL github.com/carlosarraes/shush/internal/processor 0.156s
FAIL
```
38/39 subtests pass. Failure detail for the one holdout:
```
=== RUN TestMultiline/block_sass
multiline_test.go:98: block sass mismatch:
--- got ---
"code_before();\n/* block line one\n block line two */\ncode_after();\n"
--- want ---
"code_before();\ncode_after();\n"
```
Regression guard, unaffected by this work:
```
$ go test ./internal/processor -run 'TestWholeFile|TestStripComments|TestResolveLexer|TestShouldDrop' -v
--- PASS: TestStripComments (0.03s) (13/13 subtests)
--- PASS: TestWholeFile (0.03s) (17/17 subtests)
ok github.com/carlosarraes/shush/internal/processor 0.082s
```
`go test ./...`: everything green except the one `TestMultiline/block_sass` subtest above.
## Language requiring special handling: `php` (per plan, applied as documented)
Confirmed chroma's PHP lexer only tokenizes `/* */` as `CommentMultiline` inside a `<?php ... ?>` region. Used the plan's documented `<?php` prefix wrapper on both `block_php.php` and its golden. This matches the plan's pre-approved remedy exactly — no deviation.
## Language that FAILED and was NOT force-fixed: `sass`
**Extension:** `sass` (chroma lexer name `Sass`, the indented syntax, aliased from `.sass`).
**Symptom:** `StripComments` leaves the `/* block line one\n block line two */` block entirely untouched — the file round-trips unchanged.
**Root cause (verified empirically by tokenizing with the actual chroma lexer, not guessed):**
1. In chroma's `Sass` lexer grammar (`lexers/embedded/sass.xml`), the `root` and `selector` states — which is what governs top-level statements — have **no rule at all** for `/*` or `//`. A `/*` at top level falls through to the generic operator-character rule and is tokenized as plain `Operator`/`NameTag` text, never as `CommentMultiline`. Verified: tokenizing `code_before();\n/* block line one\n block line two */\ncode_after();\n` through `lexers.Match("f.sass")` produces zero `Comment*` tokens.
2. Comment recognition only exists inside the `value` state (i.e., after a `key:` declaration). Even there, I verified the `inline-comment` sub-state used for `/* ... */` does **not** span across a newline — tokenizing `color: red /* block line one\n block line two */ blue\n` still only marks `/* block line one` as `CommentMultiline`; the following line's `block`, `line`, `two`, `*/` come back as separate `NameTag`/`Operator` tokens, not comment content.
**Conclusion:** this is not a "wrong context" problem fixable by a minimal wrapper (PHP's class of fix). PHP just needed to be inside its language-delimiter tag; once inside, its multiline comment token behaves normally across newlines. Sass's indented-syntax grammar in chroma has no code path in which `/* */` spans multiple lines at all — there is no fixture shape that would make the plan's "block spans two lines" test meaningful for `.sass`, so I did not force one. This is a chroma lexer limitation, not a shush bug and not a fixture-authoring mistake.
**Options for the plan owner (not applied, needs a decision):**
- (a) Accept the limitation, drop `sass` from `blockExts` in `TestMultiline` (or replace `block_sass.sass` with a fixture documenting "no multi-line block support" instead of testing it), and file this as a known gap.
- (b) Route `.sass` through the `SCSS` lexer in `resolveLexer` the same way `.less` already is (`engine.go:30-34`). This is architecturally the same pattern already in the codebase, and a quick manual check shows SCSS's lexer does support multiline `/* */`. However this is a `resolveLexer` code change with broader blast radius than a test fixture — real `.sass` (indented) files pushed through the brace/semicolon-oriented SCSS grammar would very likely fall back to `legacyStrip` on the losslessness check for anything beyond trivial content, so it needs deliberate evaluation, not a drive-by fix inside a test task. I did not make this change; flagging it as the most promising remedy if `sass` multi-line support is required.
I left `block_sass.sass` / `block_sass.sass.golden` as the plan's uniform template (unchanged, still failing) rather than editing the golden to match the no-op output — that would hide the gap instead of reporting it.
## Golden correction I did make (with evidence, not a guess): `template.js.golden`
The plan's authored golden expected `template.js`'s last two lines to merge onto one output line:
```
const s = `line1 /* nope
line2 */ still`; const x = 1;
```
Actual (and, I determined, *correct*) engine output keeps them as two separate lines:
```
const s = `line1 /* nope
line2 */ still`;
const x = 1;
```
**Why I concluded the plan's golden was a typo, not a signal of a real bug**, before touching it:
- JS's `CommentSingle` grammar rule is `//.*?\n` — the token literally swallows the line's trailing `\n` as part of its matched value (confirmed by reading `lexers/embedded/javascript.xml:59`).
- If that were reason enough to merge lines in the output, then the *already-committed, already-passing* `TestStripComments` case `"marker inside line comment inert"` in `engine_test.go` would have to fail too — it exercises the exact same shape in C (`z(); // a /* b\nw();\n"` → `"z();\nw();\n"`), and C's `CommentSingle` rule (`//.*?\n`, `lexers/embedded/c.xml:86`) also swallows the trailing `\n`. That test asserts the two lines stay **separate**, and it passes.
- `engine.go`'s `flush()` synthesizes its own `\n` per source line unconditionally (it does not copy the literal `\n` byte from any token); a `\n` embedded inside a *dropped* token still triggers a `flush()` call via the `segs := strings.Split(t.Value, "\n")` loop, so every physical source line boundary is preserved in the output regardless of whether the newline character was inside a comment token or not. This is the tested, approved, already-shipped Task 2 behavior, not something I invented for this task.
Given the already-approved regression test for the identical token shape proves no-merge is the correct, intended behavior, I fixed the one-line typo in `template.js.golden` rather than leave a known-good implementation "failing" against a golden that contradicts its own author's other tests. I did not touch `engine.go`.
## `make check`
**Not clean** — fails at the `test` stage on `TestMultiline/block_sass` (see above). Per the plan's Task 5 gate ("Gate: make check clean before commit") and the hard rule "Do NOT edit a golden to match wrong output just to go green," I stopped here rather than force a pass.
## Commit
**Not created.** Per the hard rule "jj, never git" and "Gate: make check clean before commit," no `jj describe` / `jj new` was run because `make check` is not clean. All fixture and driver files exist in the working copy, uncommitted, ready to commit once the `sass` question above is resolved (either accept-and-adjust-scope or implement the SCSS-lexer-routing fix and re-verify).
## Summary
- Driver: `internal/processor/multiline_test.go`, comment-free, matches plan exactly.
- Fixtures: 78 files under `internal/processor/testdata/multiline/`, all hand-typed via Write, matching the plan's exact bytes except the one corrected golden (`template.js.golden`, justified above).
- 38/39 `TestMultiline` subtests pass. `TestWholeFile` (17/17) and `TestStripComments` (13/13) regression suites stay fully green.
- One language, `sass`, fails for a documented, verified reason (chroma lexer limitation, not a shush bug) and was deliberately left failing/reported rather than faked green.
- `php` required the plan's pre-approved `<?php` wrapper remedy; applied as specified, no deviation.
+1 -1
View File
@@ -27,7 +27,7 @@ type LineChange struct {
func resolveLexer(filename string) chroma.Lexer { func resolveLexer(filename string) chroma.Lexer {
ext := strings.TrimPrefix(strings.ToLower(filepath.Ext(filename)), ".") ext := strings.TrimPrefix(strings.ToLower(filepath.Ext(filename)), ".")
var l chroma.Lexer var l chroma.Lexer
if ext == "less" { if ext == "less" || ext == "sass" {
l = lexers.Get("SCSS") l = lexers.Get("SCSS")
} else { } else {
l = lexers.Match("f." + ext) l = lexers.Match("f." + ext)
+1
View File
@@ -19,6 +19,7 @@ func TestResolveLexer(t *testing.T) {
{"a.rs", "Rust"}, {"a.rs", "Rust"},
{"a.html", "HTML"}, {"a.html", "HTML"},
{"a.less", "SCSS"}, {"a.less", "SCSS"},
{"a.sass", "SCSS"},
{"a.conf", ""}, {"a.conf", ""},
} }
for _, c := range cases { for _, c := range cases {
+101
View File
@@ -0,0 +1,101 @@
package processor
import (
"bytes"
"os"
"path/filepath"
"testing"
"github.com/carlosarraes/shush/internal/config"
"github.com/carlosarraes/shush/internal/git"
"github.com/carlosarraes/shush/internal/types"
)
type multilineCase struct {
name string
file string
cli types.CLI
cfg *config.Config
gitMode bool
ranges []git.LineRange
}
func runMultilineCase(t *testing.T, tc multilineCase) {
t.Helper()
src := filepath.Join("testdata", "multiline", tc.file)
in, err := os.ReadFile(src)
if err != nil {
t.Fatalf("read input %s: %v", src, err)
}
tmp := t.TempDir()
work := filepath.Join(tmp, tc.file)
if err := os.WriteFile(work, in, 0644); err != nil {
t.Fatalf("write work: %v", err)
}
cfg := tc.cfg
if cfg == nil {
cfg = config.Default()
}
p := &Processor{cli: tc.cli}
if tc.gitMode {
err = p.processFileWithLineRanges(work, tc.ranges, cfg)
} else {
lang, derr := DetectLanguage(work)
if derr != nil {
t.Fatalf("detect language: %v", derr)
}
err = p.processFileInMemory(work, lang, cfg)
}
if err != nil {
t.Fatalf("process: %v", err)
}
got, err := os.ReadFile(work)
if err != nil {
t.Fatalf("read result: %v", err)
}
golden := src + ".golden"
want, err := os.ReadFile(golden)
if err != nil {
t.Fatalf("read golden %s: %v", golden, err)
}
if !bytes.Equal(got, want) {
t.Errorf("%s mismatch:\n--- got ---\n%q\n--- want ---\n%q", tc.name, got, want)
}
}
func TestMultiline(t *testing.T) {
blockExts := []string{
"js", "ts", "jsx", "tsx", "go", "c", "cpp", "cc", "cxx", "h", "hpp",
"java", "cs", "rs", "swift", "kt", "kts", "dart", "scala", "php",
"css", "scss", "sass", "less", "sql",
}
xmlExts := []string{"html", "htm", "xml", "svg"}
var cases []multilineCase
for _, e := range blockExts {
cases = append(cases, multilineCase{name: "block " + e, file: "block_" + e + "." + e})
}
for _, e := range xmlExts {
cases = append(cases, multilineCase{name: "block " + e, file: "block_" + e + "." + e})
}
cases = append(cases,
multilineCase{name: "preproc kept", file: "preproc.c"},
multilineCase{name: "raw string", file: "rawstring.go"},
multilineCase{name: "template literal", file: "template.js"},
multilineCase{name: "rust lifetime", file: "lifetime.rs"},
multilineCase{name: "mixed line and block", file: "mixed.c"},
multilineCase{name: "marker in line comment", file: "marker_in_line.c"},
multilineCase{name: "unterminated", file: "unterminated.c"},
multilineCase{name: "conf fallback", file: "fallback.conf"},
multilineCase{name: "git straddle kept", file: "straddle.js",
gitMode: true, ranges: []git.LineRange{{Start: 4, End: 4}}},
multilineCase{name: "git range removes inside block", file: "range_inside.js",
gitMode: true, ranges: []git.LineRange{{Start: 2, End: 4}}},
)
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
runMultilineCase(t, tc)
})
}
}
+4
View File
@@ -0,0 +1,4 @@
code_before();
/* block line one
block line two */
code_after();
@@ -0,0 +1,2 @@
code_before();
code_after();
+4
View File
@@ -0,0 +1,4 @@
code_before();
/* block line one
block line two */
code_after();
@@ -0,0 +1,2 @@
code_before();
code_after();
+4
View File
@@ -0,0 +1,4 @@
code_before();
/* block line one
block line two */
code_after();
@@ -0,0 +1,2 @@
code_before();
code_after();
+4
View File
@@ -0,0 +1,4 @@
code_before();
/* block line one
block line two */
code_after();
@@ -0,0 +1,2 @@
code_before();
code_after();
+4
View File
@@ -0,0 +1,4 @@
code_before();
/* block line one
block line two */
code_after();
@@ -0,0 +1,2 @@
code_before();
code_after();
+4
View File
@@ -0,0 +1,4 @@
code_before();
/* block line one
block line two */
code_after();
@@ -0,0 +1,2 @@
code_before();
code_after();
+4
View File
@@ -0,0 +1,4 @@
code_before();
/* block line one
block line two */
code_after();
@@ -0,0 +1,2 @@
code_before();
code_after();
+4
View File
@@ -0,0 +1,4 @@
code_before();
/* block line one
block line two */
code_after();
@@ -0,0 +1,2 @@
code_before();
code_after();
+4
View File
@@ -0,0 +1,4 @@
code_before();
/* block line one
block line two */
code_after();
@@ -0,0 +1,2 @@
code_before();
code_after();
+4
View File
@@ -0,0 +1,4 @@
code_before();
/* block line one
block line two */
code_after();
@@ -0,0 +1,2 @@
code_before();
code_after();
+4
View File
@@ -0,0 +1,4 @@
code_before
<!-- block line one
block line two -->
code_after
@@ -0,0 +1,2 @@
code_before
code_after
+4
View File
@@ -0,0 +1,4 @@
code_before
<!-- block line one
block line two -->
code_after
@@ -0,0 +1,2 @@
code_before
code_after
+4
View File
@@ -0,0 +1,4 @@
code_before();
/* block line one
block line two */
code_after();
@@ -0,0 +1,2 @@
code_before();
code_after();
+4
View File
@@ -0,0 +1,4 @@
code_before();
/* block line one
block line two */
code_after();
@@ -0,0 +1,2 @@
code_before();
code_after();
+4
View File
@@ -0,0 +1,4 @@
code_before();
/* block line one
block line two */
code_after();
@@ -0,0 +1,2 @@
code_before();
code_after();
+4
View File
@@ -0,0 +1,4 @@
code_before();
/* block line one
block line two */
code_after();
@@ -0,0 +1,2 @@
code_before();
code_after();
+4
View File
@@ -0,0 +1,4 @@
code_before();
/* block line one
block line two */
code_after();
@@ -0,0 +1,2 @@
code_before();
code_after();
+4
View File
@@ -0,0 +1,4 @@
code_before();
/* block line one
block line two */
code_after();
@@ -0,0 +1,2 @@
code_before();
code_after();
+5
View File
@@ -0,0 +1,5 @@
<?php
code_before();
/* block line one
block line two */
code_after();
@@ -0,0 +1,3 @@
<?php
code_before();
code_after();
+4
View File
@@ -0,0 +1,4 @@
code_before();
/* block line one
block line two */
code_after();
@@ -0,0 +1,2 @@
code_before();
code_after();
+4
View File
@@ -0,0 +1,4 @@
code_before();
/* block line one
block line two */
code_after();
@@ -0,0 +1,2 @@
code_before();
code_after();
@@ -0,0 +1,4 @@
code_before();
/* block line one
block line two */
code_after();
@@ -0,0 +1,2 @@
code_before();
code_after();
+4
View File
@@ -0,0 +1,4 @@
code_before();
/* block line one
block line two */
code_after();
@@ -0,0 +1,2 @@
code_before();
code_after();
+4
View File
@@ -0,0 +1,4 @@
code_before();
/* block line one
block line two */
code_after();
@@ -0,0 +1,2 @@
code_before();
code_after();
+4
View File
@@ -0,0 +1,4 @@
code_before
<!-- block line one
block line two -->
code_after
@@ -0,0 +1,2 @@
code_before
code_after
@@ -0,0 +1,4 @@
code_before();
/* block line one
block line two */
code_after();
@@ -0,0 +1,2 @@
code_before();
code_after();
+4
View File
@@ -0,0 +1,4 @@
code_before();
/* block line one
block line two */
code_after();
@@ -0,0 +1,2 @@
code_before();
code_after();
+4
View File
@@ -0,0 +1,4 @@
code_before();
/* block line one
block line two */
code_after();
@@ -0,0 +1,2 @@
code_before();
code_after();
+4
View File
@@ -0,0 +1,4 @@
code_before
<!-- block line one
block line two -->
code_after
@@ -0,0 +1,2 @@
code_before
code_after
+2
View File
@@ -0,0 +1,2 @@
# a comment
key = value
@@ -0,0 +1 @@
key = value
+1
View File
@@ -0,0 +1 @@
fn f<'a>(x: &'a str) -> char { 'z'/* c */ }
@@ -0,0 +1 @@
fn f<'a>(x: &'a str) -> char { 'z' }
@@ -0,0 +1,2 @@
z(); // a /* b
w();
@@ -0,0 +1,2 @@
z();
w();
+4
View File
@@ -0,0 +1,4 @@
int a = 1; // line
/* block
spanning */
int b = 2; /* inline */ int c = 3;
+2
View File
@@ -0,0 +1,2 @@
int a = 1;
int b = 2; int c = 3;
+5
View File
@@ -0,0 +1,5 @@
#include <stdio.h>
#define N 4
/* real
block */
int main() { return N; }
@@ -0,0 +1,3 @@
#include <stdio.h>
#define N 4
int main() { return N; }
+4
View File
@@ -0,0 +1,4 @@
top();
/* a
b */
bottom();
@@ -0,0 +1,2 @@
top();
bottom();
+5
View File
@@ -0,0 +1,5 @@
package main
var re = `a /* not a comment */ b`
/* real
block */
func main() {}
@@ -0,0 +1,3 @@
package main
var re = `a /* not a comment */ b`
func main() {}
+4
View File
@@ -0,0 +1,4 @@
top();
/* a
b */
bottom();
@@ -0,0 +1,4 @@
top();
/* a
b */
bottom();
+3
View File
@@ -0,0 +1,3 @@
const s = `line1 /* nope
line2 */ still`; // real
const x = 1;
@@ -0,0 +1,3 @@
const s = `line1 /* nope
line2 */ still`;
const x = 1;
+3
View File
@@ -0,0 +1,3 @@
x();
/* no end
more
@@ -0,0 +1 @@
x();