| name | doxygen-comments |
| description | Conventions and a checklist for writing, updating, and correcting Doxygen documentation comments in WIL's public C++ headers under `include/` so they match the repository's style and build without warnings. Applies only to headers under `include/` — not `tests/` or other code. Use when adding or fixing `//!` or `/** */` doc comments, `@param`/`@tparam`/`@return` tags, `@ref`/`@see` cross-references, or briefs, or when resolving warnings from the Doxygen `docs` build target. |
Updating and correcting Doxygen comments in WIL
WIL's public API is documented with Doxygen comments in the headers under include/wil/, and the docs are generated from
docs/Doxyfile. Use this skill to add, update, or fix those comments so they stay consistent with the codebase and generate
cleanly.
Scope
This skill applies only to WIL's public headers under include/ (primarily include/wil/*.h). Do not apply these
conventions to test code (tests/), documentation sources (docs/), packaging, or build scripts — those files are not part of
the generated API reference. If a request targets files outside include/, this skill does not apply.
When to use
- Writing new documentation comments for public functions, classes, templates, or macros.
- Correcting existing comments after a signature or behavior change.
- Fixing Doxygen build warnings (mismatched parameters, undocumented members, broken references, etc.).
Do not rewrite comments purely for style, and do not document private/internal helpers (see "Public API only" below).
WIL Doxygen conventions
- Comment markers. WIL documents public API with either
//! line comments or /** ... */ block comments. Match the style
already used in the surrounding file / nearby declarations instead of mixing both. //! is common for file banners and member
comments; /** */ is common for free functions and templates.
- Tag style is
@, never \. Use @param, @tparam, @return, @brief, @ingroup, @ref, @see, @note, @file,
etc. The codebase uses zero backslash-style tags — keep it that way.
- Brief = first sentence, on its own line.
JAVADOC_AUTOBRIEF makes the first sentence (up to the first period) the brief.
Keep it on its own physical line; start the detailed description on the next line. An explicit @brief is rarely needed.
- Wrap at 130 columns. This matches
.clang-format (ColumnLimit: 130) and applies to comment text too.
- Public API only.
EXTRACT_ALL = NO and EXTRACT_PRIVATE = NO, so private members and undocumented internals are not
emitted. Focus documentation on the public surface; don't add Doxygen tags to private helpers expecting them to appear in the
output.
- Hide internal
details namespaces. WIL's implementation details live in namespaces named details (and similarly named
variants such as details_abi). These must not emit documentation — wrap the entire namespace in a /// @cond … /// @endcond
pair (note the /// marker used for these structural tags) so Doxygen skips its contents. Put /// @cond on its own line
immediately before the namespace and /// @endcond immediately after its closing brace. See the example below.
- Add a usage example when the call pattern is non-obvious. Include a short
~~~ fenced example for functions whose correct
use isn't clear from the signature alone — e.g. callback or functor contracts (what the callback must do and return), paired or
multi-step call sequences, RAII helpers whose placement or lifetime matters, round-trip or reverse operations, or subtle
buffer/ownership conventions. Skip examples for self-explanatory helpers such as simple getters, predicates, or arithmetic.
Doxygen fenced code blocks are delimited with ~~~ (any matching run of three or more tildes); inside //! banners, prefix
each example line with //!.
- Cross-references. Link to other entities with
@ref <name> and @see, and group related members with @ingroup <group>
(for example @ingroup outparam).
- Namespaces. Public entities live under
wil::; STL-mirroring pieces live under wistd::.
- Prefer a
PREDEFINED macro over a per-guard escape; use WIL_DOXYGEN only when needed. Doxygen evaluates #if guards
against docs/Doxyfile's PREDEFINED list, which already forces many conditions true in docs — e.g.
WINAPI_FAMILY_PARTITION(partition)=1, WIL_USE_STL=1, WIL_ENABLE_EXCEPTIONS, WIL_RESOURCE_STL, and many __cpp_lib_*
feature macros. First check whether the guard is already satisfied there; if so, no escape is needed. If a declaration is
gated on a feature macro that is broadly useful, add that macro to PREDEFINED rather than sprinkling escapes. Only when the
condition can't be satisfied that way — notably the mutually-exclusive __WIL_* / __WIL_*_STL header-wrapper guards in
resource.h/registry.h — OR || defined(WIL_DOXYGEN) into the condition (convert #ifdef X / #ifndef X to
#if defined(X); when the line wraps, continue with a trailing \ and put defined(WIL_DOXYGEN) on the next line). A
standalone #ifdef WIL_DOXYGEN block is for doc-only constructs with no real declaration to attach to.
- Macros are expanded for docs. Several macros are expanded when generating documentation (
WI_NOEXCEPT → noexcept,
WI_NODISCARD → [[nodiscard]], and others in docs/Doxyfile's PREDEFINED), so document the logical signature rather than
the macro-heavy source.
Correction checklist
When adding or fixing comments, verify:
- Every
@param/@tparam name matches the signature — no stale, missing, misspelled, or reordered names. This is the most
common source of WARN_IF_DOC_ERROR warnings.
@return is present and accurate for functions that return a meaningful value; omit it for void.
- The error-handling flavor is described where relevant. WIL entities come in neutral, exception-based,
_failfast, and
_nothrow/NoThrow variants — state how the function reports failure (throws, fail-fasts, or returns an HRESULT).
- Tags use
@ (convert any \param, \brief, etc.).
- The brief is a real one-line summary on its own line (the first sentence), not a restatement of the name.
- Cross-references resolve —
@ref/@see targets exist and are spelled correctly.
- The description still matches behavior after any signature or behavior change.
- Lines wrap at 130 columns and the comment marker style matches the surrounding code.
- No documentation is added to private/internal members unless they are intentionally part of the documented surface.
- Internal
details/details_* namespaces are wrapped in /// @cond … /// @endcond so their contents are excluded from
the generated documentation.
- Conditionally-compiled public declarations are visible in docs — the guard is either already satisfied by
PREDEFINED
or ORs in || defined(WIL_DOXYGEN) (reserved for conditions PREDEFINED can't cover, like the header-wrapper guards).
- Non-obvious functions carry a
~~~ usage example — anything with a callback contract, a paired/multi-step call sequence,
or subtle ownership/buffer semantics shows how to call it; trivial helpers do not.
Validating changes
Doxygen is configured with WARN_IF_UNDOCUMENTED = YES and WARN_IF_DOC_ERROR = YES, and formats warnings as $file:$line: $text, so a docs build points directly at problems. From an already-configured build directory, run the docs target (it
requires Doxygen on PATH, and WIL_BUILD_TESTS = ON, which is the default):
ninja docs # run from the configured build directory, e.g. build/msvc
The docs target just runs Doxygen, so it is independent of the selected configuration. Review its output for new warnings
referencing the files you touched — mismatched parameters, undocumented public members, and broken references all surface there.
Generated HTML lands under the build directory. If Doxygen is not installed, at minimum re-check each comment against the current
signature using the checklist above.
Example
Correcting stale parameter names and backslash tags:
HRESULT open_widget_nothrow(PCWSTR name, wil::unique_hwidget& widget);
HRESULT open_widget_nothrow(PCWSTR name, wil::unique_hwidget& widget);
Hiding an internal details namespace so Doxygen excludes it from the output:
namespace details
{
template <typename T>
using ensure_trivially_destructible_t = typename ensure_trivially_destructible<T>::type;
}
Adding a WIL_DOXYGEN escape so a guarded public declaration still appears in the docs:
#if defined(__WIL_OBJBASE_H_)
template <typename T>
com_ptr<T> make_com_ptr(T* ptr);
#endif
#if defined(__WIL_OBJBASE_H_) || defined(WIL_DOXYGEN)
template <typename T>
com_ptr<T> make_com_ptr(T* ptr);
#endif
Status
This skill is an intentional starting point. The conventions above are grounded in the current headers and docs/Doxyfile, but
the checklist and examples are expected to grow as we refine it. When a rule here disagrees with real, nearby code in the file you
are editing, prefer matching the surrounding code and flag the discrepancy.