Coverage Report

Created: 2021-08-24 07:12

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/include/clang/ASTMatchers/ASTMatchFinder.h
Line
Count
Source
1
//===--- ASTMatchFinder.h - Structural query framework ----------*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
//  Provides a way to construct an ASTConsumer that runs given matchers
10
//  over the AST and invokes a given callback on every match.
11
//
12
//  The general idea is to construct a matcher expression that describes a
13
//  subtree match on the AST. Next, a callback that is executed every time the
14
//  expression matches is registered, and the matcher is run over the AST of
15
//  some code. Matched subexpressions can be bound to string IDs and easily
16
//  be accessed from the registered callback. The callback can than use the
17
//  AST nodes that the subexpressions matched on to output information about
18
//  the match or construct changes that can be applied to the code.
19
//
20
//  Example:
21
//  class HandleMatch : public MatchFinder::MatchCallback {
22
//  public:
23
//    virtual void Run(const MatchFinder::MatchResult &Result) {
24
//      const CXXRecordDecl *Class =
25
//          Result.Nodes.GetDeclAs<CXXRecordDecl>("id");
26
//      ...
27
//    }
28
//  };
29
//
30
//  int main(int argc, char **argv) {
31
//    ClangTool Tool(argc, argv);
32
//    MatchFinder finder;
33
//    finder.AddMatcher(Id("id", record(hasName("::a_namespace::AClass"))),
34
//                      new HandleMatch);
35
//    return Tool.Run(newFrontendActionFactory(&finder));
36
//  }
37
//
38
//===----------------------------------------------------------------------===//
39
40
#ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHFINDER_H
41
#define LLVM_CLANG_ASTMATCHERS_ASTMATCHFINDER_H
42
43
#include "clang/ASTMatchers/ASTMatchers.h"
44
#include "llvm/ADT/SmallPtrSet.h"
45
#include "llvm/ADT/StringMap.h"
46
#include "llvm/Support/Timer.h"
47
48
namespace clang {
49
50
namespace ast_matchers {
51
52
/// A class to allow finding matches over the Clang AST.
53
///
54
/// After creation, you can add multiple matchers to the MatchFinder via
55
/// calls to addMatcher(...).
56
///
57
/// Once all matchers are added, newASTConsumer() returns an ASTConsumer
58
/// that will trigger the callbacks specified via addMatcher(...) when a match
59
/// is found.
60
///
61
/// The order of matches is guaranteed to be equivalent to doing a pre-order
62
/// traversal on the AST, and applying the matchers in the order in which they
63
/// were added to the MatchFinder.
64
///
65
/// See ASTMatchers.h for more information about how to create matchers.
66
///
67
/// Not intended to be subclassed.
68
class MatchFinder {
69
public:
70
  /// Contains all information for a given match.
71
  ///
72
  /// Every time a match is found, the MatchFinder will invoke the registered
73
  /// MatchCallback with a MatchResult containing information about the match.
74
  struct MatchResult {
75
    MatchResult(const BoundNodes &Nodes, clang::ASTContext *Context);
76
77
    /// Contains the nodes bound on the current match.
78
    ///
79
    /// This allows user code to easily extract matched AST nodes.
80
    const BoundNodes Nodes;
81
82
    /// Utilities for interpreting the matched AST structures.
83
    /// @{
84
    clang::ASTContext * const Context;
85
    clang::SourceManager * const SourceManager;
86
    /// @}
87
  };
88
89
  /// Called when the Match registered for it was successfully found
90
  /// in the AST.
91
  class MatchCallback {
92
  public:
93
    virtual ~MatchCallback();
94
95
    /// Called on every match by the \c MatchFinder.
96
    virtual void run(const MatchResult &Result) = 0;
97
98
    /// Called at the start of each translation unit.
99
    ///
100
    /// Optionally override to do per translation unit tasks.
101
37.0k
    virtual void onStartOfTranslationUnit() {}
102
103
    /// Called at the end of each translation unit.
104
    ///
105
    /// Optionally override to do per translation unit tasks.
106
7.01k
    virtual void onEndOfTranslationUnit() {}
107
108
    /// An id used to group the matchers.
109
    ///
110
    /// This id is used, for example, for the profiling output.
111
    /// It defaults to "<unknown>".
112
    virtual StringRef getID() const;
113
114
    /// TraversalKind to use while matching and processing
115
    /// the result nodes. This API is temporary to facilitate
116
    /// third parties porting existing code to the default
117
    /// behavior of clang-tidy.
118
    virtual llvm::Optional<TraversalKind> getCheckTraversalKind() const;
119
  };
120
121
  /// Called when parsing is finished. Intended for testing only.
122
  class ParsingDoneTestCallback {
123
  public:
124
    virtual ~ParsingDoneTestCallback();
125
    virtual void run() = 0;
126
  };
127
128
  struct MatchFinderOptions {
129
    struct Profiling {
130
      Profiling(llvm::StringMap<llvm::TimeRecord> &Records)
131
          : Records(Records) {}
132
133
      /// Per bucket timing information.
134
      llvm::StringMap<llvm::TimeRecord> &Records;
135
    };
136
137
    /// Enables per-check timers.
138
    ///
139
    /// It prints a report after match.
140
    llvm::Optional<Profiling> CheckProfiling;
141
  };
142
143
  MatchFinder(MatchFinderOptions Options = MatchFinderOptions());
144
  ~MatchFinder();
145
146
  /// Adds a matcher to execute when running over the AST.
147
  ///
148
  /// Calls 'Action' with the BoundNodes on every match.
149
  /// Adding more than one 'NodeMatch' allows finding different matches in a
150
  /// single pass over the AST.
151
  ///
152
  /// Does not take ownership of 'Action'.
153
  /// @{
154
  void addMatcher(const DeclarationMatcher &NodeMatch,
155
                  MatchCallback *Action);
156
  void addMatcher(const TypeMatcher &NodeMatch,
157
                  MatchCallback *Action);
158
  void addMatcher(const StatementMatcher &NodeMatch,
159
                  MatchCallback *Action);
160
  void addMatcher(const NestedNameSpecifierMatcher &NodeMatch,
161
                  MatchCallback *Action);
162
  void addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch,
163
                  MatchCallback *Action);
164
  void addMatcher(const TypeLocMatcher &NodeMatch,
165
                  MatchCallback *Action);
166
  void addMatcher(const CXXCtorInitializerMatcher &NodeMatch,
167
                  MatchCallback *Action);
168
  void addMatcher(const TemplateArgumentLocMatcher &NodeMatch,
169
                  MatchCallback *Action);
170
  void addMatcher(const AttrMatcher &NodeMatch, MatchCallback *Action);
171
  /// @}
172
173
  /// Adds a matcher to execute when running over the AST.
174
  ///
175
  /// This is similar to \c addMatcher(), but it uses the dynamic interface. It
176
  /// is more flexible, but the lost type information enables a caller to pass
177
  /// a matcher that cannot match anything.
178
  ///
179
  /// \returns \c true if the matcher is a valid top-level matcher, \c false
180
  ///   otherwise.
181
  bool addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
182
                         MatchCallback *Action);
183
184
  /// Creates a clang ASTConsumer that finds all matches.
185
  std::unique_ptr<clang::ASTConsumer> newASTConsumer();
186
187
  /// Calls the registered callbacks on all matches on the given \p Node.
188
  ///
189
  /// Note that there can be multiple matches on a single node, for
190
  /// example when using decl(forEachDescendant(stmt())).
191
  ///
192
  /// @{
193
947
  template <typename T> void match(const T &Node, ASTContext &Context) {
194
947
    match(clang::DynTypedNode::create(Node), Context);
195
947
  }
void clang::ast_matchers::MatchFinder::match<clang::Stmt>(clang::Stmt const&, clang::ASTContext&)
Line
Count
Source
193
265
  template <typename T> void match(const T &Node, ASTContext &Context) {
194
265
    match(clang::DynTypedNode::create(Node), Context);
195
265
  }
void clang::ast_matchers::MatchFinder::match<clang::Decl>(clang::Decl const&, clang::ASTContext&)
Line
Count
Source
193
680
  template <typename T> void match(const T &Node, ASTContext &Context) {
194
680
    match(clang::DynTypedNode::create(Node), Context);
195
680
  }
void clang::ast_matchers::MatchFinder::match<clang::TypeLoc>(clang::TypeLoc const&, clang::ASTContext&)
Line
Count
Source
193
2
  template <typename T> void match(const T &Node, ASTContext &Context) {
194
2
    match(clang::DynTypedNode::create(Node), Context);
195
2
  }
196
  void match(const clang::DynTypedNode &Node, ASTContext &Context);
197
  /// @}
198
199
  /// Finds all matches in the given AST.
200
  void matchAST(ASTContext &Context);
201
202
  /// Registers a callback to notify the end of parsing.
203
  ///
204
  /// The provided closure is called after parsing is done, before the AST is
205
  /// traversed. Useful for benchmarking.
206
  /// Each call to FindAll(...) will call the closure once.
207
  void registerTestCallbackAfterParsing(ParsingDoneTestCallback *ParsingDone);
208
209
  /// For each \c Matcher<> a \c MatchCallback that will be called
210
  /// when it matches.
211
  struct MatchersByType {
212
    std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *>>
213
        DeclOrStmt;
214
    std::vector<std::pair<TypeMatcher, MatchCallback *>> Type;
215
    std::vector<std::pair<NestedNameSpecifierMatcher, MatchCallback *>>
216
        NestedNameSpecifier;
217
    std::vector<std::pair<NestedNameSpecifierLocMatcher, MatchCallback *>>
218
        NestedNameSpecifierLoc;
219
    std::vector<std::pair<TypeLocMatcher, MatchCallback *>> TypeLoc;
220
    std::vector<std::pair<CXXCtorInitializerMatcher, MatchCallback *>> CtorInit;
221
    std::vector<std::pair<TemplateArgumentLocMatcher, MatchCallback *>>
222
        TemplateArgumentLoc;
223
    std::vector<std::pair<AttrMatcher, MatchCallback *>> Attr;
224
    /// All the callbacks in one container to simplify iteration.
225
    llvm::SmallPtrSet<MatchCallback *, 16> AllCallbacks;
226
  };
227
228
private:
229
  MatchersByType Matchers;
230
231
  MatchFinderOptions Options;
232
233
  /// Called when parsing is done.
234
  ParsingDoneTestCallback *ParsingDone;
235
};
236
237
/// Returns the results of matching \p Matcher on \p Node.
238
///
239
/// Collects the \c BoundNodes of all callback invocations when matching
240
/// \p Matcher on \p Node and returns the collected results.
241
///
242
/// Multiple results occur when using matchers like \c forEachDescendant,
243
/// which generate a result for each sub-match.
244
///
245
/// If you want to find all matches on the sub-tree rooted at \c Node (rather
246
/// than only the matches on \c Node itself), surround the \c Matcher with a
247
/// \c findAll().
248
///
249
/// \see selectFirst
250
/// @{
251
template <typename MatcherT, typename NodeT>
252
SmallVector<BoundNodes, 1>
253
match(MatcherT Matcher, const NodeT &Node, ASTContext &Context);
254
255
template <typename MatcherT>
256
SmallVector<BoundNodes, 1> match(MatcherT Matcher, const DynTypedNode &Node,
257
                                 ASTContext &Context);
258
/// @}
259
260
/// Returns the results of matching \p Matcher on the translation unit of
261
/// \p Context and collects the \c BoundNodes of all callback invocations.
262
template <typename MatcherT>
263
SmallVector<BoundNodes, 1> match(MatcherT Matcher, ASTContext &Context);
264
265
/// Returns the first result of type \c NodeT bound to \p BoundTo.
266
///
267
/// Returns \c NULL if there is no match, or if the matching node cannot be
268
/// casted to \c NodeT.
269
///
270
/// This is useful in combanation with \c match():
271
/// \code
272
///   const Decl *D = selectFirst<Decl>("id", match(Matcher.bind("id"),
273
///                                                 Node, Context));
274
/// \endcode
275
template <typename NodeT>
276
const NodeT *
277
1.65k
selectFirst(StringRef BoundTo, const SmallVectorImpl<BoundNodes> &Results) {
278
1.65k
  for (const BoundNodes &N : Results) {
279
722
    if (const NodeT *Node = N.getNodeAs<NodeT>(BoundTo))
280
722
      return Node;
281
722
  }
282
936
  return nullptr;
283
1.65k
}
clang::Expr const* clang::ast_matchers::selectFirst<clang::Expr>(llvm::StringRef, llvm::SmallVectorImpl<clang::ast_matchers::BoundNodes> const&)
Line
Count
Source
277
610
selectFirst(StringRef BoundTo, const SmallVectorImpl<BoundNodes> &Results) {
278
610
  for (const BoundNodes &N : Results) {
279
277
    if (const NodeT *Node = N.getNodeAs<NodeT>(BoundTo))
280
277
      return Node;
281
277
  }
282
333
  return nullptr;
283
610
}
clang::Stmt const* clang::ast_matchers::selectFirst<clang::Stmt>(llvm::StringRef, llvm::SmallVectorImpl<clang::ast_matchers::BoundNodes> const&)
Line
Count
Source
277
1.04k
selectFirst(StringRef BoundTo, const SmallVectorImpl<BoundNodes> &Results) {
278
1.04k
  for (const BoundNodes &N : Results) {
279
445
    if (const NodeT *Node = N.getNodeAs<NodeT>(BoundTo))
280
445
      return Node;
281
445
  }
282
603
  return nullptr;
283
1.04k
}
284
285
namespace internal {
286
class CollectMatchesCallback : public MatchFinder::MatchCallback {
287
public:
288
1.74k
  void run(const MatchFinder::MatchResult &Result) override {
289
1.74k
    Nodes.push_back(Result.Nodes);
290
1.74k
  }
291
292
23.2k
  llvm::Optional<TraversalKind> getCheckTraversalKind() const override {
293
23.2k
    return llvm::None;
294
23.2k
  }
295
296
  SmallVector<BoundNodes, 1> Nodes;
297
};
298
}
299
300
template <typename MatcherT>
301
SmallVector<BoundNodes, 1> match(MatcherT Matcher, const DynTypedNode &Node,
302
20.7k
                                 ASTContext &Context) {
303
20.7k
  internal::CollectMatchesCallback Callback;
304
20.7k
  MatchFinder Finder;
305
20.7k
  Finder.addMatcher(Matcher, &Callback);
306
20.7k
  Finder.match(Node, Context);
307
20.7k
  return std::move(Callback.Nodes);
308
20.7k
}
llvm::SmallVector<clang::ast_matchers::BoundNodes, 1u> clang::ast_matchers::match<clang::ast_matchers::internal::BindableMatcher<clang::Decl> >(clang::ast_matchers::internal::BindableMatcher<clang::Decl>, clang::DynTypedNode const&, clang::ASTContext&)
Line
Count
Source
302
310
                                 ASTContext &Context) {
303
310
  internal::CollectMatchesCallback Callback;
304
310
  MatchFinder Finder;
305
310
  Finder.addMatcher(Matcher, &Callback);
306
310
  Finder.match(Node, Context);
307
310
  return std::move(Callback.Nodes);
308
310
}
llvm::SmallVector<clang::ast_matchers::BoundNodes, 1u> clang::ast_matchers::match<clang::ast_matchers::internal::Matcher<clang::Decl> >(clang::ast_matchers::internal::Matcher<clang::Decl>, clang::DynTypedNode const&, clang::ASTContext&)
Line
Count
Source
302
1.57k
                                 ASTContext &Context) {
303
1.57k
  internal::CollectMatchesCallback Callback;
304
1.57k
  MatchFinder Finder;
305
1.57k
  Finder.addMatcher(Matcher, &Callback);
306
1.57k
  Finder.match(Node, Context);
307
1.57k
  return std::move(Callback.Nodes);
308
1.57k
}
llvm::SmallVector<clang::ast_matchers::BoundNodes, 1u> clang::ast_matchers::match<clang::ast_matchers::internal::BindableMatcher<clang::Stmt> >(clang::ast_matchers::internal::BindableMatcher<clang::Stmt>, clang::DynTypedNode const&, clang::ASTContext&)
Line
Count
Source
302
16.4k
                                 ASTContext &Context) {
303
16.4k
  internal::CollectMatchesCallback Callback;
304
16.4k
  MatchFinder Finder;
305
16.4k
  Finder.addMatcher(Matcher, &Callback);
306
16.4k
  Finder.match(Node, Context);
307
16.4k
  return std::move(Callback.Nodes);
308
16.4k
}
llvm::SmallVector<clang::ast_matchers::BoundNodes, 1u> clang::ast_matchers::match<clang::ast_matchers::internal::Matcher<clang::Stmt> >(clang::ast_matchers::internal::Matcher<clang::Stmt>, clang::DynTypedNode const&, clang::ASTContext&)
Line
Count
Source
302
2.44k
                                 ASTContext &Context) {
303
2.44k
  internal::CollectMatchesCallback Callback;
304
2.44k
  MatchFinder Finder;
305
2.44k
  Finder.addMatcher(Matcher, &Callback);
306
2.44k
  Finder.match(Node, Context);
307
2.44k
  return std::move(Callback.Nodes);
308
2.44k
}
llvm::SmallVector<clang::ast_matchers::BoundNodes, 1u> clang::ast_matchers::match<clang::ast_matchers::internal::BindableMatcher<clang::QualType> >(clang::ast_matchers::internal::BindableMatcher<clang::QualType>, clang::DynTypedNode const&, clang::ASTContext&)
Line
Count
Source
302
11
                                 ASTContext &Context) {
303
11
  internal::CollectMatchesCallback Callback;
304
11
  MatchFinder Finder;
305
11
  Finder.addMatcher(Matcher, &Callback);
306
11
  Finder.match(Node, Context);
307
11
  return std::move(Callback.Nodes);
308
11
}
309
310
template <typename MatcherT, typename NodeT>
311
SmallVector<BoundNodes, 1>
312
20.7k
match(MatcherT Matcher, const NodeT &Node, ASTContext &Context) {
313
20.7k
  return match(Matcher, DynTypedNode::create(Node), Context);
314
20.7k
}
llvm::SmallVector<clang::ast_matchers::BoundNodes, 1u> clang::ast_matchers::match<clang::ast_matchers::internal::BindableMatcher<clang::Decl>, clang::Decl>(clang::ast_matchers::internal::BindableMatcher<clang::Decl>, clang::Decl const&, clang::ASTContext&)
Line
Count
Source
312
290
match(MatcherT Matcher, const NodeT &Node, ASTContext &Context) {
313
290
  return match(Matcher, DynTypedNode::create(Node), Context);
314
290
}
llvm::SmallVector<clang::ast_matchers::BoundNodes, 1u> clang::ast_matchers::match<clang::ast_matchers::internal::Matcher<clang::Decl>, clang::Decl>(clang::ast_matchers::internal::Matcher<clang::Decl>, clang::Decl const&, clang::ASTContext&)
Line
Count
Source
312
1.57k
match(MatcherT Matcher, const NodeT &Node, ASTContext &Context) {
313
1.57k
  return match(Matcher, DynTypedNode::create(Node), Context);
314
1.57k
}
llvm::SmallVector<clang::ast_matchers::BoundNodes, 1u> clang::ast_matchers::match<clang::ast_matchers::internal::BindableMatcher<clang::Stmt>, clang::Stmt>(clang::ast_matchers::internal::BindableMatcher<clang::Stmt>, clang::Stmt const&, clang::ASTContext&)
Line
Count
Source
312
16.4k
match(MatcherT Matcher, const NodeT &Node, ASTContext &Context) {
313
16.4k
  return match(Matcher, DynTypedNode::create(Node), Context);
314
16.4k
}
llvm::SmallVector<clang::ast_matchers::BoundNodes, 1u> clang::ast_matchers::match<clang::ast_matchers::internal::Matcher<clang::Stmt>, clang::Stmt>(clang::ast_matchers::internal::Matcher<clang::Stmt>, clang::Stmt const&, clang::ASTContext&)
Line
Count
Source
312
2.44k
match(MatcherT Matcher, const NodeT &Node, ASTContext &Context) {
313
2.44k
  return match(Matcher, DynTypedNode::create(Node), Context);
314
2.44k
}
Unexecuted instantiation: llvm::SmallVector<clang::ast_matchers::BoundNodes, 1u> clang::ast_matchers::match<clang::ast_matchers::internal::Matcher<clang::Decl>, clang::CXXRecordDecl>(clang::ast_matchers::internal::Matcher<clang::Decl>, clang::CXXRecordDecl const&, clang::ASTContext&)
llvm::SmallVector<clang::ast_matchers::BoundNodes, 1u> clang::ast_matchers::match<clang::ast_matchers::internal::BindableMatcher<clang::QualType>, clang::QualType>(clang::ast_matchers::internal::BindableMatcher<clang::QualType>, clang::QualType const&, clang::ASTContext&)
Line
Count
Source
312
11
match(MatcherT Matcher, const NodeT &Node, ASTContext &Context) {
313
11
  return match(Matcher, DynTypedNode::create(Node), Context);
314
11
}
llvm::SmallVector<clang::ast_matchers::BoundNodes, 1u> clang::ast_matchers::match<clang::ast_matchers::internal::BindableMatcher<clang::Stmt>, clang::Expr>(clang::ast_matchers::internal::BindableMatcher<clang::Stmt>, clang::Expr const&, clang::ASTContext&)
Line
Count
Source
312
4
match(MatcherT Matcher, const NodeT &Node, ASTContext &Context) {
313
4
  return match(Matcher, DynTypedNode::create(Node), Context);
314
4
}
315
316
template <typename MatcherT>
317
SmallVector<BoundNodes, 1>
318
match(MatcherT Matcher, ASTContext &Context) {
319
  internal::CollectMatchesCallback Callback;
320
  MatchFinder Finder;
321
  Finder.addMatcher(Matcher, &Callback);
322
  Finder.matchAST(Context);
323
  return std::move(Callback.Nodes);
324
}
325
326
inline SmallVector<BoundNodes, 1>
327
matchDynamic(internal::DynTypedMatcher Matcher, const DynTypedNode &Node,
328
             ASTContext &Context) {
329
  internal::CollectMatchesCallback Callback;
330
  MatchFinder Finder;
331
  Finder.addDynamicMatcher(Matcher, &Callback);
332
  Finder.match(Node, Context);
333
  return std::move(Callback.Nodes);
334
}
335
336
template <typename NodeT>
337
SmallVector<BoundNodes, 1> matchDynamic(internal::DynTypedMatcher Matcher,
338
                                        const NodeT &Node,
339
                                        ASTContext &Context) {
340
  return matchDynamic(Matcher, DynTypedNode::create(Node), Context);
341
}
342
343
inline SmallVector<BoundNodes, 1>
344
matchDynamic(internal::DynTypedMatcher Matcher, ASTContext &Context) {
345
  internal::CollectMatchesCallback Callback;
346
  MatchFinder Finder;
347
  Finder.addDynamicMatcher(Matcher, &Callback);
348
  Finder.matchAST(Context);
349
  return std::move(Callback.Nodes);
350
}
351
352
} // end namespace ast_matchers
353
} // end namespace clang
354
355
#endif