Skip to content

feat: warn when a documented declaration names a filtered symbol - #1316

Open
gennaroprota wants to merge 5 commits into
cppalliance:developfrom
gennaroprota:feat/warn_when_a_documented_declaration_names_a_filtered_symbol
Open

gennaroprota wants to merge 5 commits into
cppalliance:developfrom
gennaroprota:feat/warn_when_a_documented_declaration_names_a_filtered_symbol

Conversation

@gennaroprota

@gennaroprota gennaroprota commented Sep 22, 2026 •

Copy link
Copy Markdown
Collaborator

This PR:

  • Fixes the interaction between filters and @implementationdefined/@seebelow. Before it, the filters won and the commands were thrown away. This meant that, for instance, a function returning a filtered type was rendered with the filtered type name in the docs, and the user had no way to avoid this.

  • Adds the warning issue warning: filtered namespace in public API #337 asks for, and a corresponding option to silence it. Thanks to the above, the user can choose to avoid the warning by marking the filtered symbol @implementationdefined.

Changes

  • Source: A command written on the declaration itself outranks the filters that hide kinds of symbols, and survives an exclusion of the file it is in; a glob or a mode inherited from a parent does neither. On a private member, only @implementationdefined does so: a @seebelow member would get a page reachable only from the list of private members. The warning is one of the warn-* diagnostics of the doc-comment finalizer, so it is grouped and printed like them and counts toward max-errors. It reports a filtered symbol named in a return type, a parameter, a public base, an alias, a variable, a data member or a template argument, and a filtered template named with arguments.
  • Tests: Golden fixtures for the two filter fixes, including the glob and inherited-mode cases that must not override the filters, and runs over inputs that name filtered symbols: one entry per position checks the warning it prints, one checks that the warning stays off when the option is off, one checks that nothing is reported where it shouldn't be, and two check symbols from outside the inputs.
  • Build: A new warn-if-filtered-in-public-api option, with the generated config schema updated.
  • Breaking changes: The new warning is on by default, so a project running with warn-as-error over an API that names a filtered symbol will start failing. Setting warn-if-filtered-in-public-api: false restores the old behavior, and marking the symbol @implementationdefined fixes the issue properly.

Testing

The ctest entries in tests/CMakeLists.txt run the tool over three inputs in tests/diagnostics/. filtered-in-public-api names a filtered symbol in each position the warning covers: mrdocs-warn-filtered-in-public-api runs it with --warn-as-error and expects the failure, each mrdocs-warn-filtered-<position> entry matches the warning for one position, so one working position can't hide a broken one, and mrdocs-quiet-filtered-in-public-api runs the same input with the option off and expects a clean exit. filtered-not-reported holds the cases that must stay silent (a private base, an @implementationdefined target, a specialization of a documented template, a member reached through a specialization), and mrdocs-unreported-filtered-in-public-api expects a clean --warn-as-error run. filtered-outside-inputs checks that a filtered symbol from a header outside the inputs isn't reported, and that the same symbol is reported once its directory is an input, even an excluded one.

The two filter fixes are covered by golden fixtures instead, because their effect is in the generated page. Under tests/golden/fixtures/filters/symbol-type, private-implementation-defined, private-see-below and private-implementation-defined-glob pin which private members a command or a glob brings back. Under tests/golden/fixtures/filters/file, excluded-implementation-defined, excluded-directory-implementation-defined, excluded-directory-see-below-glob and outside-input-implementation-defined pin the rendered signature of a marked type in an excluded file, in an excluded directory, under a glob, and outside the inputs.

Documentation

warn-if-filtered-in-public-api joins the warn-* list on the Diagnostics page, with a pointer to @implementationdefined as the way to settle the warning rather than switch it off. Its own entry in the options reference comes from ConfigOptions.json and needs no separate edit.

Closes #337.

@github-actions

github-actions Bot commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

✨ Highlights

  • 🧪 Existing golden tests changed (behavior likely shifted)

🧾 Changes by Scope

Scope Lines Δ% Lines Δ Lines + Lines - Files Δ Files + Files ~ Files ↔ Files -
🥇 Golden Tests 46% 603 603 - 25 24 1 - -
🛠️ Source 35% 453 383 70 8 2 6 - -
📦 Other 18% 232 232 - 9 8 1 - -
📄 Docs 1% 11 11 - 2 - 2 - -
Total 100% 1299 1229 70 44 34 10 - -

Legend: Files + (added), Files ~ (modified), Files ↔ (renamed), Files - (removed)

🔝 Top Files

  • src/mrdocs/AST/ASTVisitor.cpp (Source): 140 lines Δ (+72 / -68)
  • src/mrdocs/Metadata/Finalizers/DocCommentFinalizer.cpp (Source): 135 lines Δ (+135 / -0)
  • tests/golden/fixtures/filters/symbol-type/private-implementation-defined.xml (Golden Tests): 123 lines Δ (+123 / -0)

Generated by 🚫 dangerJS against 15166a6

@codecov

codecov Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 83.12%. Comparing base (b45d019) to head (15166a6).
⚠️ Report is 35 commits behind head on develop.

Additional details and impacted files
@@           Coverage Diff            @@
##           develop    #1316   +/-   ##
========================================
  Coverage    83.12%   83.12%           
========================================
  Files           35       35           
  Lines         3662     3662           
  Branches       844      844           
========================================
  Hits          3044     3044           
  Misses         410      410           
  Partials       208      208           
Flag Coverage Δ
bootstrap 83.12% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@gennaroprota
gennaroprota force-pushed the feat/warn_when_a_documented_declaration_names_a_filtered_symbol branch from 67d7bde to 4e976d6 Compare September 22, 2026 07:12
@gennaroprota gennaroprota changed the title Feat: warn when a documented declaration names a filtered symbol feat: warn when a documented declaration names a filtered symbol Sep 22, 2026
@cppalliance-bot

cppalliance-bot commented Sep 22, 2026 •

Copy link
Copy Markdown

An automated preview of the documentation is available at https://1316.mrdocs.prtest2.cppalliance.org/index.html

If more commits are pushed to the pull request, the docs will rebuild at the same URL.

2026-10-01 10:37:26 UTC

@gennaroprota
gennaroprota force-pushed the feat/warn_when_a_documented_declaration_names_a_filtered_symbol branch from 4e976d6 to 264c2f3 Compare September 23, 2026 08:14
The filters that drop whole kinds of symbol, such as private members,
anonymous namespaces and file-level statics, ran before the ones that
match names, so `@implementationdefined` on a private member was read
too late to matter: the member stayed a dependency, and a public
signature naming it printed the name instead of the placeholder.

We now read the command written on the declaration when one of those
filters rejects it. A glob, or a mode inherited from a parent, still
doesn't override those filters, since it doesn't speak for that one
declaration. I've added tests.

Note that a private member marked `@seebelow` is still dropped: it would
get a page, and the only way to reach that page would be the list of
private members, which `extract-private: false` hides.
A file excluded with `exclude` or `exclude-patterns` lost every symbol
in it, commands and all, so `@implementationdefined` on a type in an
excluded header did nothing: a function returning that type, for
instance, was documented with the real name of the type instead of the
placeholder. We now let the command win, as it says how the symbol
should appear when something else names it, which is more specific than
excluding a file. Only a command written on the declaration counts,
though: a glob, or a mode inherited from a parent, doesn't speak for
that declaration, so a symbol it covers in an excluded file is still
dropped. I've added tests.

Note that a file which was never in `input` is another matter: a command
in a third-party header speaks for that library, not for the project
being documented, so a symbol from such a header is still dropped.
The documented accessor `dom::Function::impl` returned a reference to
`impl_type`, a private alias. The alias has no page, so a reader of the
signature met a name that led nowhere.

This makes the alias public and documents it, as `dom::Array` and
`dom::Object` already do.
A symbol removed by the filters has no page, so a declaration naming it
sends the reader nowhere. We now report such names in return types,
parameters, public bases, aliases, variables and data members, and in
the type arguments of a template. A filtered template named with
arguments, such as `detail::impl<int>`, is reported as well. The report
goes through the same list as the other `warn-*` diagnostics, so it's
printed under the same file, line and column header and counts toward
`max-errors`.

Only symbols declared in the input files are reported, since a symbol
from anywhere else belongs to another library. A member reached through
a specialization of its enclosing template, such as `inner` in
`outer<int>::inner`, isn't reported either, since the primary template
documents it.
This gives projects which deliberately use filtered symbols in their
public API a way to silence the new warning in one place, instead of,
e.g., marking each such symbol `@implementationdefined`. As for most of
the other `warn-*` options, the default is `true`.

Note that the golden fixtures set the option to `false`, as several of
them exist precisely to exercise a filtered symbol reached from the
documented API.
@gennaroprota
gennaroprota force-pushed the feat/warn_when_a_documented_declaration_names_a_filtered_symbol branch from 264c2f3 to 15166a6 Compare October 1, 2026 10:28

This branch has not been deployed

No deployments
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.

warning: filtered namespace in public API

2 participants