Skip to content

Commit b05a7e0

Browse files
committed
add documentation (pr desc) to ASTMatchers.h's file comment
1 parent 066ea2b commit b05a7e0

File tree

1 file changed

+156
-0
lines changed

1 file changed

+156
-0
lines changed

clang/include/clang/ASTMatchers/ASTMatchers.h

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,162 @@
3939
// See ASTMatchFinder.h for how to use the generated matchers to run over
4040
// an AST.
4141
//
42+
// The doxygen comments on matchers are used to:
43+
// - create the doxygen documentation
44+
// - get information in the editor via signature help and goto definition
45+
// - generate the AST matcher reference html file
46+
// - test the documentation using a special syntax
47+
//
48+
// TLDR:
49+
//
50+
// The automatic testing uses doxygen commands (aliases) to extract the
51+
// relevant information about an example of using a matcher from the
52+
// documentation.
53+
//
54+
// \header{a.h}
55+
// \endheader <- zero or more header
56+
//
57+
// \code
58+
// int a = 42;
59+
// \endcode
60+
// \compile_args{-std=c++,c23-or-later} <- optional, the std flag supports
61+
// std ranges and
62+
// whole languages
63+
//
64+
// \matcher{expr()} <- one or more matchers in succession
65+
// \matcher{integerLiteral()} <- one or more matchers in succession
66+
// both matcher will have to match the
67+
// following matches
68+
// \match{42} <- one or more matches in succession
69+
//
70+
// \matcher{varDecl()} <- new matcher resets the context, the above
71+
// \match will not count for this new
72+
// matcher(-group)
73+
// \match{int a = 42} <- only applies to the previous matcher (not to the
74+
// previous case)
75+
//
76+
//
77+
// The above block can be repeated inside a doxygen command for multiple code
78+
// examples for a single matcher. The test generation script will only look for
79+
// these annotations and ignore anything else like `\c` or the sentences where
80+
// these annotations are embedded into: `The matcher \matcher{expr()} matches
81+
// the number \match{42}.`.
82+
//
83+
// Language Grammar:
84+
//
85+
// [] denotes an optional, and <> denotes user-input
86+
//
87+
// compile_args j:= \compile_args{[<compile_arg>;]<compile_arg>}
88+
// matcher_tag_key ::= type
89+
// match_tag_key ::= type || std || count || sub
90+
// matcher_tags ::= [matcher_tag_key=<value>;]matcher_tag_key=<value>
91+
// match_tags ::= [match_tag_key=<value>;]match_tag_key=<value>
92+
// matcher ::= \matcher{[matcher_tags$]<matcher>}
93+
// matchers ::= [matcher] matcher
94+
// match ::= \match{[match_tags$]<match>}
95+
// matches ::= [match] match
96+
// case ::= matchers matches
97+
// cases ::= [case] case
98+
// header-block ::= \header{<name>} <code> \endheader
99+
// code-block ::= \code <code> \endcode
100+
// testcase ::= code-block [compile_args] cases
101+
//
102+
// Language Standard Versions:
103+
//
104+
// The 'std' tag and '\compile_args' support specifying a specific language
105+
// version, a whole language and all of its versions, and thresholds (implies
106+
// ranges). Multiple arguments are passed with a ',' separator. For a language
107+
// and version to execute a tested matcher, it has to match the specified
108+
// '\compile_args' for the code, and the 'std' tag for the matcher. Predicates
109+
// for the 'std' compiler flag are used with disjunction between languages
110+
// (e.g. 'c || c++') and conjunction for all predicates specific to each
111+
// language (e.g. 'c++11-or-later && c++23-or-earlier').
112+
//
113+
// Examples:
114+
// - `c` all available versions of C
115+
// - `c++11` only C++11
116+
// - `c++11-or-later` C++11 or later
117+
// - `c++11-or-earlier` C++11 or earlier
118+
// - `c++11-or-later,c++23-or-earlier,c` all of C and C++ between 11 and
119+
// 23 (inclusive)
120+
// - `c++11-23,c` same as above
121+
//
122+
// Tags
123+
//
124+
// `type`:
125+
// **Match types** are used to select where the string that is used to check if
126+
// a node matches comes from. Available: `code`, `name`, `typestr`,
127+
// `typeofstr`. The default is `code`.
128+
//
129+
// - `code`: Forwards to `tooling::fixit::getText(...)` and should be the
130+
// preferred way to show what matches.
131+
// - `name`: Casts the match to a `NamedDecl` and returns the result of
132+
// `getNameAsString`. Useful when the matched AST node is not easy to spell
133+
// out (`code` type), e.g., namespaces or classes with many members.
134+
// - `typestr`: Returns the result of `QualType::getAsString` for the type
135+
// derived from `Type` (otherwise, if it is derived from `Decl`, recurses with
136+
// `Node->getTypeForDecl()`)
137+
//
138+
// **Matcher types** are used to mark matchers as sub-matcher with 'sub' or as
139+
// deactivated using 'none'. Testing sub-matcher is not implemented.
140+
//
141+
// `count`:
142+
// Specifying a 'count=n' on a match will result in a test that requires that
143+
// the specified match will be matched n times. Default is 1.
144+
//
145+
// `std`:
146+
// A match allows specifying if it matches only in specific language versions.
147+
// This may be needed when the AST differs between language versions.
148+
//
149+
// `sub`:
150+
// The `sub` tag on a `\match` will indicate that the match is for a node of a
151+
// bound sub-matcher. E.g., `\matcher{expr(expr().bind("inner"))}` has a
152+
// sub-matcher that binds to `inner`, which is the value for the `sub` tag of
153+
// the expected match for the sub-matcher `\match{sub=inner$...}`. Currently,
154+
// sub-matchers are not tested in any way.
155+
//
156+
//
157+
// What if ...?
158+
//
159+
// ... I want to add a matcher?
160+
//
161+
// Add a doxygen comment to the matcher with a code example, corresponding
162+
// matchers and matches, that shows what the matcher is supposed to do. Specify
163+
// the compile arguments/supported languages if required, and run `ninja
164+
// check-clang-unit` to test the documentation.
165+
//
166+
// ... the example I wrote is wrong?
167+
//
168+
// The test-generation script will try to compile your example code before it
169+
// continues. This makes finding issues with your example code easier because
170+
// the test-failures are much more verbose.
171+
//
172+
// The test-failure output of the generated test file will provide information
173+
// about
174+
// - where the generated test file is located
175+
// - which line in `ASTMatcher.h` the example is from
176+
// - which matches were: found, not-(yet)-found, expected
177+
// - in case of an unexpected match: what the node looks like using the
178+
// different `type`s
179+
// - the language version and if the test ran with a windows `-target` flag
180+
// (also in failure summary)
181+
//
182+
// ... I don't adhere to the required order of the syntax?
183+
//
184+
// The script will diagnose any found issues, such as `matcher is missing an
185+
// example` with a `file:line:` prefix, which should provide enough information
186+
// about the issue.
187+
//
188+
// ... the script diagnoses a false-positive issue with a doxygen comment?
189+
//
190+
// It hopefully shouldn't, but if you, e.g., added some non-matcher code and
191+
// documented it with doxygen, then the script will consider that as a matcher
192+
// documentation. As a result, the script will print that it detected a
193+
// mismatch between the actual and the expected number of failures. If the
194+
// diagnostic truly is a false-positive, change the
195+
// `expected_failure_statistics` at the top of the
196+
// `generate_ast_matcher_doc_tests.py` file.
197+
//
42198
//===----------------------------------------------------------------------===//
43199

44200
#ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHERS_H

0 commit comments

Comments
 (0)