Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

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