Skip to content

fix(go): a comment a blank line separates from a declaration is not its doc - #2678

Merged
colbymchenry merged 3 commits into
mainfrom
claude/heuristic-brattain-cb7db3
Oct 19, 2026
Merged

colbymchenry merged 3 commits into
mainfrom
claude/heuristic-brattain-cb7db3

Conversation

@colbymchenry

Copy link
Copy Markdown
Owner

Go's doc comment, the one go doc, pkg.go.dev and gopls show (go/parser's lead comment), is only the comment group that ends on the line right above a declaration: comments on consecutive lines form one group, and a blank line ends it. Both extractors joined every comment above a Go declaration instead. A section banner, a TODO, a lint line or commented-out code above a blank line was put in front of the declaration's docstring, or became its whole docstring when the declaration had none of its own:

  • gin Context.Next: "/\nFLOW CONTROL\n/\nNext should be used only inside middleware.…" becomes "Next should be used only inside middleware.…" (seven gin Context methods carried such a banner)
  • gin TestTreeTrailingSlashRedirect: a commented-out func TestTreeDuplicateWildcard(t *testing.T) {…} becomes no docstring
  • etcd ReadTx: an orphaned copy of IsSafeRangeBucket's doc, a blank line above type ReadTx interface, becomes no docstring

Decision. Go docstrings now follow go doc exactly (this chat's open question, settled with go doc as the oracle). Other languages keep joining every comment above a declaration.

Change

  • A Go-only extractor option beside fix(go): a type declared on its own keeps its doc comment #2438's trailing-comment rule: docstringSkipsDetachedComments in TS (getPrecedingDocstring's new skipDetached), and preceding_docstring_skipping_trailing_and_detached in the kernel. The kernel function replaces preceding_docstring_skipping_trailing, whose only caller was Go.
  • How it works: once the comments that trail the line above are dropped, it walks back from the declaration. The last comment must end on the line right above the declaration. Each earlier comment joins while it ends on the line where the next one starts, or the line before. That is go/parser's consumeCommentGroup(1) grouping plus its endline+1 == line lead test.
  • A comment that ends on the declaration's own line (/* x */ func f() {}) documents nothing, as in go doc.
  • Applies to every Go docstring codegraph stores: functions, methods, types (including fix(go): a type declared on its own keeps its doc comment #2438's single-spec type declarations) and const/var declarations.

Verification

  • New __tests__/go-detached-doc-comments.test.ts, kernel and wasm, each on LF and CRLF:
    • fails 4/4 on main 22d420e and passes 4/4 here;
    • covers banners, TODOs, an orphaned doc, methods, const/var, a type group's members, a block comment with a blank line inside, a two-paragraph // doc, a line+block+line group, /* x */ func f(), and a doc right under a trailing comment.
  • New kernel unit test skips_the_comments_a_blank_line_detaches. The trailing-comment unit test now calls the shared helper directly. All 5 docstring unit tests pass.
  • The torture.go parity fixture gains a detached banner and a banner above a doc; kernel-tsjs-parity passes 96/96, CRLF cases included. fix(go): a type declared on its own keeps its doc comment #2438's go-type-doc-comments.test.ts is unchanged and passes.
  • Full suite with the kernel built and CODEGRAPH_KERNEL_EXPECT=1 (--maxWorkers=4 --minWorkers=1): 7,505 passed, 0 failed, 80 skipped (7,585 tests, 0 failed files).

A/B on real repos

main 22d420e vs this branch; etcd 6782f522, prometheus 0b57789d, gin 0f09c3a9.

Nodes, edges, unresolved refs and files are byte-identical on all three repos, on both the kernel and wasm paths. Only docstrings change, and the two paths change exactly the same ones:

repo trimmed to go doc's comment dropped (go doc shows none)
etcd 7 12
prometheus 15 18
gin 7 9
  • Every change equals go doc's lead comment. The oracle is read from the file text, independently of tree-sitter: the comment-only lines right above the declaration, with no blank line between. A block comment must open at the start of its line.
  • Full-coverage check over every ungrouped func/type/const/var declaration (12,117 / 14,332 / 1,738 Go declarations): main disagrees with go doc on 19 / 31 / 16 of them, this branch on 0 / 0 / 0.
  • What the 39 dropped docstrings were:
    • 16 banners or section comments;
    • 6 TODOs;
    • 4 commented-out code blocks;
    • 3 file-level notes;
    • 2 revive:enable lint lines;
    • 2 go test -v command lines;
    • 1 orphaned copy of another declaration's doc;
    • 5 real descriptions written with a blank line before the declaration: etcd LazyCluster, mmapSize, isOpenEnded; prometheus triton Discovery.refresh, TestBucketIterator. go doc doesn't show these either.
  • Kernel parity (kernel-parity.mjs --lang go), same on both arms:
    • etcd: 1065/1105 files, 0 diffs (the same 40 erroring example_*_test.go files defer to wasm as on main);
    • prometheus: 746/746;
    • gin: 99/99.
  • Cost: a few integer comparisons over comments the walk already collected; no measurable change.

Notes

  • go/doc also gives an undocumented member of a type ( … ) group the group's doc. fix(go): a type declared on its own keeps its doc comment #2438 keeps the group comment off members on purpose, and this PR doesn't change that.
  • Follow-ups found while validating, to be done next as their own PRs:
    • (1) a docstring keeps comment directives that go doc drops from a doc comment's text (//nolint:unparam, //go:embed testdata, //revive:disable:var-naming): 18 docstrings on these repos, 8 of which are nothing but a directive;
    • (2) a const/var declared inside a const ( … )/var ( … ) group loses its own doc comment (gin's ErrorTypeBind is used when Context.Bind() fails. is stored as nothing): 341 documented members on these repos.

🤖 Generated with Claude Code

colbymchenry and others added 3 commits October 19, 2026 15:09
…ts doc

Go's doc comment, the one go doc shows (go/parser's lead comment), is the
comment group that ends on the line right above a declaration: comments
on consecutive lines form one group, and a blank line ends it. Both
extractors joined every comment above a Go declaration instead, so a
section banner, a TODO or commented-out code above a blank line became
part of the declaration's docstring, or its whole docstring when the
declaration had no doc of its own.

Go now keeps only that group, through a Go-only extractor option beside
the trailing-comment one (docstringSkipsDetachedComments in TS,
preceding_docstring_skipping_trailing_and_detached in the kernel). A
comment that ends on the declaration's own line documents nothing, as
in go doc.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant