Skip to content

Commit c1ce891

Browse files
committed
feat: support macros
This adds support for preprocessing macros: `#define` directives are captured via a `clang::PPCallbacks` subclass and exposed as `MacroSymbol` instances at the corpus root (macros aren't in any C++ scope, so they sit alongside the global namespace rather than under it). Doc-comment association: Clang doesn't link comments to macros, so we look up a preceding doc-comment by source location. A comment is attached only when the lines between it and the directive are blank. Filters apply to macros, too: - `extract-all`: when off, undocumented macros are dropped. - `exclude-symbols`, `include-symbols`, `implementation-defined`, `see-below`: matched against the macro name. - File-pattern filters: matched against the directive's source location. Schema additions: `<macro>` is a new top-level element in mrdocs.rnc, sibling of `<namespace>`, with `<source>` carrying the verbatim definition (modulo a minor normalization). New output pages: multipage mode now produces `macros.{ext}` at the output root, listing every macro with a link to its per-symbol page. The global-namespace page gains a "See also: Macros" navigation hint at the bottom (multipage-only) so the new page is discoverable. Macro `@param` blocks are validated. Golden tests also cover the three filter paths (`extract-all: false`, `include-symbols`, `exclude-symbols`). Closes issue #1127.
1 parent 9c7a140 commit c1ce891

89 files changed

Lines changed: 4875 additions & 25 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

include/mrdocs/Corpus.hpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,19 @@ class MRDOCS_VISIBLE
155155
NamespaceSymbol const&
156156
globalNamespace() const noexcept;
157157

158+
/** Return all preprocessor macros in the corpus.
159+
160+
Macros are stored at the corpus root, not under any
161+
namespace, since they are not in any C++ scope. The
162+
result is sorted by macro name, with source location
163+
as a tiebreaker, so iteration order is stable across
164+
runs.
165+
166+
@return All MacroSymbols in stable iteration order.
167+
*/
168+
std::vector<MacroSymbol const*>
169+
macros() const;
170+
158171
/** Visit the specified Symbol IDs
159172
160173
This function invokes the specified function `f`

include/mrdocs/Metadata.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <mrdocs/Metadata/Symbol/Friend.hpp>
2424
#include <mrdocs/Metadata/Symbol/Function.hpp>
2525
#include <mrdocs/Metadata/Symbol/Guide.hpp>
26+
#include <mrdocs/Metadata/Symbol/Macro.hpp>
2627
#include <mrdocs/Metadata/Symbol/Namespace.hpp>
2728
#include <mrdocs/Metadata/Symbol/NamespaceAlias.hpp>
2829
#include <mrdocs/Metadata/Symbol/Overloads.hpp>
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
//
2+
// Licensed under the Apache License v2.0 with LLVM Exceptions.
3+
// See https://llvm.org/LICENSE.txt for license information.
4+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5+
//
6+
// Copyright (c) 2026 Gennaro Prota (gennaro.prota@gmail.com)
7+
//
8+
// Official repository: https://github.com/cppalliance/mrdocs
9+
//
10+
11+
#ifndef MRDOCS_API_METADATA_SYMBOL_MACRO_HPP
12+
#define MRDOCS_API_METADATA_SYMBOL_MACRO_HPP
13+
14+
#include <mrdocs/Metadata/Symbol.hpp>
15+
#include <mrdocs/Support/Describe.hpp>
16+
#include <string>
17+
#include <vector>
18+
19+
namespace mrdocs {
20+
21+
/** Info for preprocessor macros.
22+
23+
Covers both object-like and function-like macros.
24+
*/
25+
struct MacroSymbol final
26+
: SymbolCommonBase<SymbolKind::Macro>
27+
{
28+
/** Whether this is a function-like macro.
29+
*/
30+
bool IsFunctionLike = false;
31+
32+
/** The names of the macro's parameters.
33+
34+
Empty for object-like macros. For variadic
35+
function-like macros, this lists only the
36+
named parameters; variadicness is indicated
37+
by @ref IsVariadic.
38+
*/
39+
std::vector<std::string> Parameters;
40+
41+
/** Whether the macro takes a variadic argument list.
42+
43+
True for macros declared with `...`, such as
44+
`#define LOG(fmt, ...) ...`.
45+
*/
46+
bool IsVariadic = false;
47+
48+
/** The full source of the macro definition.
49+
50+
Captured from the start of the line containing
51+
the `#define` directive through the end of the
52+
macro definition, line continuations and all,
53+
with one normalization: whitespace between `#`
54+
and `define` (typically used when the macro
55+
definition is in a `#if`/`#ifdef`/`#ifndef`),
56+
and the matching leading whitespace on
57+
continuation lines, is stripped; so the
58+
definition in the synopsis reads as a
59+
top-level directive without a surrounding
60+
`#if`/`#ifdef`/`#ifndef`.
61+
*/
62+
std::string Source;
63+
64+
//--------------------------------------------
65+
66+
/** Create a macro symbol bound to an ID.
67+
*/
68+
explicit MacroSymbol(SymbolID const& ID) noexcept
69+
: SymbolCommonBase(ID)
70+
{
71+
}
72+
};
73+
74+
MRDOCS_DESCRIBE_STRUCT(
75+
MacroSymbol,
76+
(SymbolCommonBase<SymbolKind::Macro>),
77+
(IsFunctionLike, Parameters, IsVariadic, Source)
78+
)
79+
80+
} // mrdocs
81+
82+
#endif // MRDOCS_API_METADATA_SYMBOL_MACRO_HPP

include/mrdocs/Metadata/Symbol/SymbolKind.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ enum class SymbolKind {
3030
MRDOCS_DESCRIBE_ENUM(SymbolKind,
3131
Namespace, Record, Function, Overloads, Enum,
3232
EnumConstant, Typedef, Variable, Guide,
33-
NamespaceAlias, Using, Concept)
33+
NamespaceAlias, Using, Concept, Macro)
3434

3535
/** Count the number of SymbolKind enumerators.
3636
@return Number of `SymbolKind` values generated from SymbolNodes.inc.

include/mrdocs/Metadata/Symbol/SymbolNodes.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ INFO(Guide)
2424
INFO(NamespaceAlias)
2525
INFO(Using)
2626
INFO(Concept)
27+
INFO(Macro)
2728

2829
#undef INFO
2930

mrdocs.rnc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,18 @@ grammar
555555

556556
#---------------------------------------------
557557

558+
Macro =
559+
element macro
560+
{
561+
SymbolBase,
562+
element is-function-like { Bool }?,
563+
element parameters { text }*,
564+
element is-variadic { Bool }?,
565+
element source { text }?
566+
}
567+
568+
#---------------------------------------------
569+
558570
Overloads =
559571
element overloads
560572
{
@@ -582,6 +594,7 @@ grammar
582594
NamespaceAlias |
583595
Using |
584596
Concept |
597+
Macro |
585598
Overloads
586599
)
587600

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{{!--
2+
Layout for the corpus-level Macros index page (multipage mode).
3+
The wrapper template handles the title, footer, etc.; this
4+
template only emits the page contents.
5+
--}}
6+
{{>symbol/detail/members-table-impl members=corpusMacros isName=false includeBrief=true title=""}}

share/mrdocs/addons/generator/adoc/partials/symbol.adoc.hbs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@
8686
{{! Namespace members }}
8787
{{else if (eq symbol.kind "namespace")}}
8888
{{>symbol/tranche tranche=symbol.members label="" is-namespace=true}}
89+
{{! Navigation hint: macros live on their own page since they
90+
are not in any C++ scope. }}
91+
{{#if (and @root.config.multipage (not symbol.parent) @root.corpusMacros)}}
92+
93+
See also: <<macros#,Macros>>
94+
{{/if}}
8995
{{! Enum members }}
9096
{{else if (eq symbol.kind "enum")}}
9197
{{>symbol/members-table members=symbol.constants title="Members"}}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{{!--
2+
Render the synopsis for a preprocessor macro.
3+
4+
For regular macros, the synopsis is the normalized
5+
source of the `#define` directive.
6+
7+
For see-below macros, the body is replaced by a
8+
`/* see-below */` marker. Implementation-defined
9+
macros are not rendered at all (see
10+
`shouldGenerate` in VisitorHelpers.cpp).
11+
12+
Expected Context: {Symbol Object} (kind == "macro")
13+
--}}
14+
{{#isSeeBelow~}}
15+
#define {{name}}{{#if isFunctionLike}}({{#each parameters}}{{this}}{{#unless @last}}, {{/unless}}{{/each}}{{#if isVariadic}}{{#if parameters}}, {{/if}}...{{/if}}){{/if}} /* see-below */
16+
{{~else~}}
17+
{{ source }}
18+
{{~/isSeeBelow}}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{{!--
2+
Layout for the corpus-level Macros index page (multipage mode).
3+
The wrapper template handles <html>, <head>, footer, etc.; this
4+
template only emits the page contents.
5+
--}}
6+
{{>symbol/detail/members-table-impl members=corpusMacros isName=false includeBrief=true title=""}}

0 commit comments

Comments
 (0)