Skip to content

[Repo Assist] Fix doc comment (///) at end of file being duplicated#3266

Merged
nojaf merged 8 commits into
mainfrom
repo-assist/fix-issue-2499-duplicate-doc-comment-10e89c3f45a0db9c
Mar 11, 2026
Merged

[Repo Assist] Fix doc comment (///) at end of file being duplicated#3266
nojaf merged 8 commits into
mainfrom
repo-assist/fix-issue-2499-duplicate-doc-comment-10e89c3f45a0db9c

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

Closes #2499

Problem

A /// XML doc comment without an associated declaration (e.g. at end of file) was duplicated when formatting:

Input:

/// Returns `unit` if validation was successful otherwise will throw an `Exception`.

Before this fix:

/// Returns `unit` if validation was successful otherwise will throw an `Exception`.
/// Returns `unit` if validation was successful otherwise will throw an `Exception`.

After this fix:

/// Returns `unit` if validation was successful otherwise will throw an `Exception`.

Root cause

In collectCodeComments (Parse.fs in the vendored FCS), when a /// comment is at end-of-file, the lexer saves it in both CommentStore (via SaveSingleLineComment) and XmlDocStore (via trySaveXmlDocSaveXmlDocLine). Both stores are then yielded in the combined list, producing two identical LineComment trivia entries at the same source position.

This is a lexer-level issue: a /// comment followed by a newline is only saved to XmlDocStore (guarded by if Option.isNone buff), but the EOF case unconditionally calls both trySaveXmlDoc and CommentStore.SaveSingleLineComment. Since lex.fs is generated code, the fix is applied in Parse.fs where the two stores are combined.

Fix

Deduplicate the combined comment list by (StartLine, StartColumn) before sorting. No two comments can legitimately share the same source position, so this is safe and has no effect on normal code.

[ yield! CommentStore.GetComments(lexbuf)
  yield! List.map CommentTrivia.LineComment tripleSlashComments ]
|> List.distinctBy (function
    | CommentTrivia.LineComment r
    | CommentTrivia.BlockComment r -> r.StartLine, r.StartColumn)
|> List.sortBy ...

Test Status

  • ✅ Build succeeded
  • ✅ 2728 tests pass, 7 skipped, 0 failed (1 new regression test added)

🤖 This PR was created by Repo Assist, an automated AI assistant. Please review carefully.

Generated by Repo Assist ·

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/repo-assist.md@346204513ecfa08b81566450d7d599556807389f

A triple-slash doc comment (///) without an associated declaration
was duplicated when formatting. For example, a file containing only:

    /// Returns `unit` if validation was successful.

would be formatted to:

    /// Returns `unit` if validation was successful.
    /// Returns `unit` if validation was successful.

Root cause: in `collectCodeComments` (Parse.fs), when a `///` comment
appears at end-of-file, the lexer saves it in both `CommentStore` (via
`SaveSingleLineComment`) AND `XmlDocStore` (via `SaveXmlDocLine`/
`trySaveXmlDoc`). Both stores are then combined in `collectCodeComments`,
resulting in two identical `LineComment` trivia entries for the same
source range.

Fix: deduplicate the combined comment list by `(StartLine, StartColumn)`
before sorting, so no two entries share the same source position.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@nojaf

nojaf commented Mar 10, 2026

Copy link
Copy Markdown
Contributor

/repo-assist looks reasonable but misses a changelog entry.
It also makes you wonder if all users should play that minimal List.distinctBy cost because 1 user had a bad comment in their empty file. Is this really worth having?

- Replace List.distinctBy (runs for every format) with a conditional
  that only builds a position Set when orphan /// comments exist.
  For well-formed code tripleSlashComments is empty so there is zero
  overhead; the Set is only constructed in the rare EOF edge-case.
- Add CHANGELOG entry for #2499 under [Unreleased].

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor Author

Commit pushed: 432c597

Generated by Repo Assist

@github-actions

This comment has been minimized.

@nojaf

nojaf commented Mar 10, 2026

Copy link
Copy Markdown
Contributor

/repo-assist you can probably be even more strict when check for the first three / in | CommentTrivia.LineComment r -> Some(r.StartLine, r.StartColumn). Update PR

When deduplicating /// comments that appear in both CommentStore and
XmlDocStore at EOF, verify that the LineComment from CommentStore
actually starts with '///' before treating it as a duplicate.

This is achieved by stashing the ISourceText in lexbuf.BufferLocalStore
during createLexbuf and reading it back in collectCodeComments to
inspect the character content at the comment's range position.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor Author

Commit pushed: 39bd5b7

Generated by Repo Assist

@nojaf nojaf closed this Mar 10, 2026
@nojaf nojaf reopened this Mar 10, 2026
@nojaf

nojaf commented Mar 10, 2026

Copy link
Copy Markdown
Contributor

/repo-assist I think you are not checking if line even has more than three characters.
I also noticed a .filter + .map combo: should be a choose

@nojaf

nojaf commented Mar 10, 2026

Copy link
Copy Markdown
Contributor

/repo-assist you did not format your code. How dare you!

- Rewrite `col + 2 < line.Length` as `line.Length > col + 2` for clarity
- Replace `List.filter + List.map` with `List.choose`

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor Author

Commit pushed: b95e298

Generated by Repo Assist

@nojaf nojaf marked this pull request as ready for review March 10, 2026 17:46
nojaf and others added 2 commits March 10, 2026 18:48
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor Author

Commit pushed: c8e0daf

Generated by Repo Assist

@github-actions

Copy link
Copy Markdown
Contributor Author

🤖 This is an automated response from Repo Assist.

My sincerest apologies for the unformatted code! I've now run dotnet fantomas src docs build.fsx and pushed the formatting fix. The change adds two blank lines in src/Fantomas.FCS/Parse.fs within the collectCodeComments function.

Generated by Repo Assist for issue #3266 ·

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/repo-assist.md@346204513ecfa08b81566450d7d599556807389f

@nojaf nojaf closed this Mar 10, 2026
@nojaf nojaf reopened this Mar 10, 2026
@nojaf nojaf merged commit f33fb6e into main Mar 11, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fantomas duplicates commented line at the end of the file

1 participant