Adds the AST Matcher library, which provides a in-C++ DSL to express
matches on interesting parts of the AST, and callback mechanisms to act on them. llvm-svn: 159805
This commit is contained in:
parent
5e6e6264f4
commit
04616e4776
|
@ -0,0 +1,141 @@
|
|||
//===--- ASTMatchFinder.h - Structural query framework ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Provides a way to construct an ASTConsumer that runs given matchers
|
||||
// over the AST and invokes a given callback on every match.
|
||||
//
|
||||
// The general idea is to construct a matcher expression that describes a
|
||||
// subtree match on the AST. Next, a callback that is executed every time the
|
||||
// expression matches is registered, and the matcher is run over the AST of
|
||||
// some code. Matched subexpressions can be bound to string IDs and easily
|
||||
// be accessed from the registered callback. The callback can than use the
|
||||
// AST nodes that the subexpressions matched on to output information about
|
||||
// the match or construct changes that can be applied to the code.
|
||||
//
|
||||
// Example:
|
||||
// class HandleMatch : public MatchFinder::MatchCallback {
|
||||
// public:
|
||||
// virtual void Run(const MatchFinder::MatchResult &Result) {
|
||||
// const CXXRecordDecl *Class =
|
||||
// Result.Nodes.GetDeclAs<CXXRecordDecl>("id");
|
||||
// ...
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// int main(int argc, char **argv) {
|
||||
// ClangTool Tool(argc, argv);
|
||||
// MatchFinder finder;
|
||||
// finder.AddMatcher(Id("id", record(hasName("::a_namespace::AClass"))),
|
||||
// new HandleMatch);
|
||||
// return Tool.Run(newFrontendActionFactory(&finder));
|
||||
// }
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCH_FINDER_H
|
||||
#define LLVM_CLANG_AST_MATCHERS_AST_MATCH_FINDER_H
|
||||
|
||||
#include "clang/ASTMatchers/ASTMatchers.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
namespace ast_matchers {
|
||||
|
||||
/// \brief A class to allow finding matches over the Clang AST.
|
||||
///
|
||||
/// After creation, you can add multiple matchers to the MatchFinder via
|
||||
/// calls to addMatcher(...).
|
||||
///
|
||||
/// Once all matchers are added, newASTConsumer() returns an ASTConsumer
|
||||
/// that will trigger the callbacks specified via addMatcher(...) when a match
|
||||
/// is found.
|
||||
///
|
||||
/// See ASTMatchers.h for more information about how to create matchers.
|
||||
///
|
||||
/// Not intended to be subclassed.
|
||||
class MatchFinder {
|
||||
public:
|
||||
/// \brief Contains all information for a given match.
|
||||
///
|
||||
/// Every time a match is found, the MatchFinder will invoke the registered
|
||||
/// MatchCallback with a MatchResult containing information about the match.
|
||||
struct MatchResult {
|
||||
MatchResult(const BoundNodes &Nodes, clang::ASTContext *Context);
|
||||
|
||||
/// \brief Contains the nodes bound on the current match.
|
||||
///
|
||||
/// This allows user code to easily extract matched AST nodes.
|
||||
const BoundNodes Nodes;
|
||||
|
||||
/// \brief Utilities for interpreting the matched AST structures.
|
||||
/// @{
|
||||
clang::ASTContext * const Context;
|
||||
clang::SourceManager * const SourceManager;
|
||||
/// @}
|
||||
};
|
||||
|
||||
/// \brief Called when the Match registered for it was successfully found
|
||||
/// in the AST.
|
||||
class MatchCallback {
|
||||
public:
|
||||
virtual ~MatchCallback();
|
||||
virtual void run(const MatchResult &Result) = 0;
|
||||
};
|
||||
|
||||
/// \brief Called when parsing is finished. Intended for testing only.
|
||||
class ParsingDoneTestCallback {
|
||||
public:
|
||||
virtual ~ParsingDoneTestCallback();
|
||||
virtual void run() = 0;
|
||||
};
|
||||
|
||||
MatchFinder();
|
||||
~MatchFinder();
|
||||
|
||||
/// \brief Adds a matcher to execute when running over the AST.
|
||||
///
|
||||
/// Calls 'Action' with the BoundNodes on every match.
|
||||
/// Adding more than one 'NodeMatch' allows finding different matches in a
|
||||
/// single pass over the AST.
|
||||
///
|
||||
/// Does not take ownership of 'Action'.
|
||||
/// @{
|
||||
void addMatcher(const DeclarationMatcher &NodeMatch,
|
||||
MatchCallback *Action);
|
||||
void addMatcher(const TypeMatcher &NodeMatch,
|
||||
MatchCallback *Action);
|
||||
void addMatcher(const StatementMatcher &NodeMatch,
|
||||
MatchCallback *Action);
|
||||
/// @}
|
||||
|
||||
/// \brief Creates a clang ASTConsumer that finds all matches.
|
||||
clang::ASTConsumer *newASTConsumer();
|
||||
|
||||
/// \brief Registers a callback to notify the end of parsing.
|
||||
///
|
||||
/// The provided closure is called after parsing is done, before the AST is
|
||||
/// traversed. Useful for benchmarking.
|
||||
/// Each call to FindAll(...) will call the closure once.
|
||||
void registerTestCallbackAfterParsing(ParsingDoneTestCallback *ParsingDone);
|
||||
|
||||
private:
|
||||
/// \brief The MatchCallback*'s will be called every time the
|
||||
/// UntypedBaseMatcher matches on the AST.
|
||||
std::vector< std::pair<
|
||||
const internal::UntypedBaseMatcher*,
|
||||
MatchCallback*> > Triggers;
|
||||
|
||||
/// \brief Called when parsing is done.
|
||||
ParsingDoneTestCallback *ParsingDone;
|
||||
};
|
||||
|
||||
} // end namespace ast_matchers
|
||||
} // end namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCH_FINDER_H
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,888 @@
|
|||
//===--- ASTMatchersInternal.h - Structural query framework -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Implements the base layer of the matcher framework.
|
||||
//
|
||||
// Matchers are methods that return a Matcher<T> which provides a method
|
||||
// Matches(...) which is a predicate on an AST node. The Matches method's
|
||||
// parameters define the context of the match, which allows matchers to recurse
|
||||
// or store the current node as bound to a specific string, so that it can be
|
||||
// retrieved later.
|
||||
//
|
||||
// In general, matchers have two parts:
|
||||
// 1. A function Matcher<T> MatcherName(<arguments>) which returns a Matcher<T>
|
||||
// based on the arguments and optionally on template type deduction based
|
||||
// on the arguments. Matcher<T>s form an implicit reverse hierarchy
|
||||
// to clang's AST class hierarchy, meaning that you can use a Matcher<Base>
|
||||
// everywhere a Matcher<Derived> is required.
|
||||
// 2. An implementation of a class derived from MatcherInterface<T>.
|
||||
//
|
||||
// The matcher functions are defined in ASTMatchers.h. To make it possible
|
||||
// to implement both the matcher function and the implementation of the matcher
|
||||
// interface in one place, ASTMatcherMacros.h defines macros that allow
|
||||
// implementing a matcher in a single place.
|
||||
//
|
||||
// This file contains the base classes needed to construct the actual matchers.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H
|
||||
#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "llvm/ADT/VariadicFunction.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/// FIXME: Move into the llvm support library.
|
||||
template <bool> struct CompileAssert {};
|
||||
#define TOOLING_COMPILE_ASSERT(Expr, Msg) \
|
||||
typedef CompileAssert<(bool(Expr))> Msg[bool(Expr) ? 1 : -1]
|
||||
|
||||
namespace clang {
|
||||
namespace ast_matchers {
|
||||
|
||||
class BoundNodes;
|
||||
|
||||
namespace internal {
|
||||
|
||||
class BoundNodesTreeBuilder;
|
||||
|
||||
/// \brief A tree of bound nodes in match results.
|
||||
///
|
||||
/// If a match can contain multiple matches on the same node with different
|
||||
/// matching subexpressions, BoundNodesTree contains a branch for each of
|
||||
/// those matching subexpressions.
|
||||
///
|
||||
/// BoundNodesTree's are created during the matching process; when a match
|
||||
/// is found, we iterate over the tree and create a BoundNodes object containing
|
||||
/// the union of all bound nodes on the path from the root to a each leaf.
|
||||
class BoundNodesTree {
|
||||
public:
|
||||
/// \brief A visitor interface to visit all BoundNodes results for a
|
||||
/// BoundNodesTree.
|
||||
class Visitor {
|
||||
public:
|
||||
virtual ~Visitor() {}
|
||||
|
||||
/// \brief Called multiple times during a single call to VisitMatches(...).
|
||||
///
|
||||
/// 'BoundNodesView' contains the bound nodes for a single match.
|
||||
virtual void visitMatch(const BoundNodes& BoundNodesView) = 0;
|
||||
};
|
||||
|
||||
BoundNodesTree();
|
||||
|
||||
/// \brief Create a BoundNodesTree from pre-filled maps of bindings.
|
||||
BoundNodesTree(const std::map<std::string, const clang::Decl*>& DeclBindings,
|
||||
const std::map<std::string, const clang::Stmt*>& StmtBindings,
|
||||
const std::vector<BoundNodesTree> RecursiveBindings);
|
||||
|
||||
/// \brief Adds all bound nodes to bound_nodes_builder.
|
||||
void copyTo(BoundNodesTreeBuilder* Builder) const;
|
||||
|
||||
/// \brief Visits all matches that this BoundNodesTree represents.
|
||||
///
|
||||
/// The ownership of 'ResultVisitor' remains at the caller.
|
||||
void visitMatches(Visitor* ResultVisitor);
|
||||
|
||||
private:
|
||||
void visitMatchesRecursively(
|
||||
Visitor* ResultVistior,
|
||||
std::map<std::string, const clang::Decl*> DeclBindings,
|
||||
std::map<std::string, const clang::Stmt*> StmtBindings);
|
||||
|
||||
template <typename T>
|
||||
void copyBindingsTo(const T& bindings, BoundNodesTreeBuilder* Builder) const;
|
||||
|
||||
// FIXME: Find out whether we want to use different data structures here -
|
||||
// first benchmarks indicate that it doesn't matter though.
|
||||
|
||||
std::map<std::string, const clang::Decl*> DeclBindings;
|
||||
std::map<std::string, const clang::Stmt*> StmtBindings;
|
||||
|
||||
std::vector<BoundNodesTree> RecursiveBindings;
|
||||
};
|
||||
|
||||
/// \brief Creates BoundNodesTree objects.
|
||||
///
|
||||
/// The tree builder is used during the matching process to insert the bound
|
||||
/// nodes from the Id matcher.
|
||||
class BoundNodesTreeBuilder {
|
||||
public:
|
||||
BoundNodesTreeBuilder();
|
||||
|
||||
/// \brief Add a binding from an id to a node.
|
||||
///
|
||||
/// FIXME: Add overloads for all AST base types.
|
||||
/// @{
|
||||
void setBinding(const std::pair<const std::string,
|
||||
const clang::Decl*>& binding);
|
||||
void setBinding(const std::pair<const std::string,
|
||||
const clang::Stmt*>& binding);
|
||||
/// @}
|
||||
|
||||
/// \brief Adds a branch in the tree.
|
||||
void addMatch(const BoundNodesTree& Bindings);
|
||||
|
||||
/// \brief Returns a BoundNodes object containing all current bindings.
|
||||
BoundNodesTree build() const;
|
||||
|
||||
private:
|
||||
BoundNodesTreeBuilder(const BoundNodesTreeBuilder&); // DO NOT IMPLEMENT
|
||||
void operator=(const BoundNodesTreeBuilder&); // DO NOT IMPLEMENT
|
||||
|
||||
std::map<std::string, const clang::Decl*> DeclBindings;
|
||||
std::map<std::string, const clang::Stmt*> StmtBindings;
|
||||
|
||||
std::vector<BoundNodesTree> RecursiveBindings;
|
||||
};
|
||||
|
||||
class ASTMatchFinder;
|
||||
|
||||
/// \brief Generic interface for matchers on an AST node of type T.
|
||||
///
|
||||
/// Implement this if your matcher may need to inspect the children or
|
||||
/// descendants of the node or bind matched nodes to names. If you are
|
||||
/// writing a simple matcher that only inspects properties of the
|
||||
/// current node and doesn't care about its children or descendants,
|
||||
/// implement SingleNodeMatcherInterface instead.
|
||||
template <typename T>
|
||||
class MatcherInterface : public llvm::RefCountedBaseVPTR {
|
||||
public:
|
||||
virtual ~MatcherInterface() {}
|
||||
|
||||
/// \brief Returns true if 'Node' can be matched.
|
||||
///
|
||||
/// May bind 'Node' to an ID via 'Builder', or recurse into
|
||||
/// the AST via 'Finder'.
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const = 0;
|
||||
};
|
||||
|
||||
/// \brief Interface for matchers that only evaluate properties on a single node.
|
||||
template <typename T>
|
||||
class SingleNodeMatcherInterface : public MatcherInterface<T> {
|
||||
public:
|
||||
/// \brief Returns true if the matcher matches the provided node.
|
||||
///
|
||||
/// A subclass must implement this instead of Matches().
|
||||
virtual bool matchesNode(const T &Node) const = 0;
|
||||
|
||||
private:
|
||||
/// Implements MatcherInterface::Matches.
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder * /* Finder */,
|
||||
BoundNodesTreeBuilder * /* Builder */) const {
|
||||
return matchesNode(Node);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Wrapper of a MatcherInterface<T> *that allows copying.
|
||||
///
|
||||
/// A Matcher<Base> can be used anywhere a Matcher<Derived> is
|
||||
/// required. This establishes an is-a relationship which is reverse
|
||||
/// to the AST hierarchy. In other words, Matcher<T> is contravariant
|
||||
/// with respect to T. The relationship is built via a type conversion
|
||||
/// operator rather than a type hierarchy to be able to templatize the
|
||||
/// type hierarchy instead of spelling it out.
|
||||
template <typename T>
|
||||
class Matcher {
|
||||
public:
|
||||
/// \brief Takes ownership of the provided implementation pointer.
|
||||
explicit Matcher(MatcherInterface<T> *Implementation)
|
||||
: Implementation(Implementation) {}
|
||||
|
||||
/// \brief Forwards the call to the underlying MatcherInterface<T> pointer.
|
||||
bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return Implementation->matches(Node, Finder, Builder);
|
||||
}
|
||||
|
||||
/// \brief Implicitly converts this object to a Matcher<Derived>.
|
||||
///
|
||||
/// Requires Derived to be derived from T.
|
||||
template <typename Derived>
|
||||
operator Matcher<Derived>() const {
|
||||
return Matcher<Derived>(new ImplicitCastMatcher<Derived>(*this));
|
||||
}
|
||||
|
||||
/// \brief Returns an ID that uniquely identifies the matcher.
|
||||
uint64_t getID() const {
|
||||
/// FIXME: Document the requirements this imposes on matcher
|
||||
/// implementations (no new() implementation_ during a Matches()).
|
||||
return reinterpret_cast<uint64_t>(Implementation.getPtr());
|
||||
}
|
||||
|
||||
private:
|
||||
/// \brief Allows conversion from Matcher<T> to Matcher<Derived> if Derived
|
||||
/// is derived from T.
|
||||
template <typename Derived>
|
||||
class ImplicitCastMatcher : public MatcherInterface<Derived> {
|
||||
public:
|
||||
explicit ImplicitCastMatcher(const Matcher<T> &From)
|
||||
: From(From) {}
|
||||
|
||||
virtual bool matches(const Derived &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return From.matches(Node, Finder, Builder);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<T> From;
|
||||
};
|
||||
|
||||
llvm::IntrusiveRefCntPtr< MatcherInterface<T> > Implementation;
|
||||
}; // class Matcher
|
||||
|
||||
/// \brief A convenient helper for creating a Matcher<T> without specifying
|
||||
/// the template type argument.
|
||||
template <typename T>
|
||||
inline Matcher<T> makeMatcher(MatcherInterface<T> *Implementation) {
|
||||
return Matcher<T>(Implementation);
|
||||
}
|
||||
|
||||
/// \brief Matches declarations for QualType and CallExpr.
|
||||
///
|
||||
/// Type argument DeclMatcherT is required by PolymorphicMatcherWithParam1 but
|
||||
/// not actually used.
|
||||
template <typename T, typename DeclMatcherT>
|
||||
class HasDeclarationMatcher : public MatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT((llvm::is_same< DeclMatcherT,
|
||||
Matcher<clang::Decl> >::value),
|
||||
instantiated_with_wrong_types);
|
||||
public:
|
||||
explicit HasDeclarationMatcher(const Matcher<clang::Decl> &InnerMatcher)
|
||||
: InnerMatcher(InnerMatcher) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return matchesSpecialized(Node, Finder, Builder);
|
||||
}
|
||||
|
||||
private:
|
||||
/// \brief Extracts the CXXRecordDecl of a QualType and returns whether the
|
||||
/// inner matcher matches on it.
|
||||
bool matchesSpecialized(const clang::QualType &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
/// FIXME: Add other ways to convert...
|
||||
clang::CXXRecordDecl *NodeAsRecordDecl = Node->getAsCXXRecordDecl();
|
||||
return NodeAsRecordDecl != NULL &&
|
||||
InnerMatcher.matches(*NodeAsRecordDecl, Finder, Builder);
|
||||
}
|
||||
|
||||
/// \brief Extracts the Decl of the callee of a CallExpr and returns whether
|
||||
/// the inner matcher matches on it.
|
||||
bool matchesSpecialized(const clang::CallExpr &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
const clang::Decl *NodeAsDecl = Node.getCalleeDecl();
|
||||
return NodeAsDecl != NULL &&
|
||||
InnerMatcher.matches(*NodeAsDecl, Finder, Builder);
|
||||
}
|
||||
|
||||
/// \brief Extracts the Decl of the constructor call and returns whether the
|
||||
/// inner matcher matches on it.
|
||||
bool matchesSpecialized(const clang::CXXConstructExpr &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
const clang::Decl *NodeAsDecl = Node.getConstructor();
|
||||
return NodeAsDecl != NULL &&
|
||||
InnerMatcher.matches(*NodeAsDecl, Finder, Builder);
|
||||
}
|
||||
|
||||
const Matcher<clang::Decl> InnerMatcher;
|
||||
};
|
||||
|
||||
/// \brief IsBaseType<T>::value is true if T is a "base" type in the AST
|
||||
/// node class hierarchies (i.e. if T is Decl, Stmt, or QualType).
|
||||
template <typename T>
|
||||
struct IsBaseType {
|
||||
static const bool value =
|
||||
(llvm::is_same<T, clang::Decl>::value ||
|
||||
llvm::is_same<T, clang::Stmt>::value ||
|
||||
llvm::is_same<T, clang::QualType>::value ||
|
||||
llvm::is_same<T, clang::CXXCtorInitializer>::value);
|
||||
};
|
||||
template <typename T>
|
||||
const bool IsBaseType<T>::value;
|
||||
|
||||
/// \brief Interface that can match any AST base node type and contains default
|
||||
/// implementations returning false.
|
||||
class UntypedBaseMatcher : public llvm::RefCountedBaseVPTR {
|
||||
public:
|
||||
virtual ~UntypedBaseMatcher() {}
|
||||
|
||||
virtual bool matches(const clang::Decl &DeclNode, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return false;
|
||||
}
|
||||
virtual bool matches(const clang::QualType &TypeNode, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return false;
|
||||
}
|
||||
virtual bool matches(const clang::Stmt &StmtNode, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return false;
|
||||
}
|
||||
virtual bool matches(const clang::CXXCtorInitializer &CtorInitNode,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Returns a unique ID for the matcher.
|
||||
virtual uint64_t getID() const = 0;
|
||||
};
|
||||
|
||||
/// \brief An UntypedBaseMatcher that overwrites the Matches(...) method for
|
||||
/// node type T. T must be an AST base type.
|
||||
template <typename T>
|
||||
class TypedBaseMatcher : public UntypedBaseMatcher {
|
||||
TOOLING_COMPILE_ASSERT(IsBaseType<T>::value,
|
||||
typed_base_matcher_can_only_be_used_with_base_type);
|
||||
public:
|
||||
explicit TypedBaseMatcher(const Matcher<T> &InnerMatcher)
|
||||
: InnerMatcher(InnerMatcher) {}
|
||||
|
||||
using UntypedBaseMatcher::matches;
|
||||
/// \brief Implements UntypedBaseMatcher::Matches.
|
||||
///
|
||||
/// Since T is guaranteed to be a "base" AST node type, this method is
|
||||
/// guaranteed to override one of the matches() methods from
|
||||
/// UntypedBaseMatcher.
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return InnerMatcher.matches(Node, Finder, Builder);
|
||||
}
|
||||
|
||||
/// \brief Implements UntypedBaseMatcher::getID.
|
||||
virtual uint64_t getID() const {
|
||||
return InnerMatcher.getID();
|
||||
}
|
||||
|
||||
private:
|
||||
Matcher<T> InnerMatcher;
|
||||
};
|
||||
|
||||
/// \brief Interface that allows matchers to traverse the AST.
|
||||
/// FIXME: Find a better name.
|
||||
///
|
||||
/// This provides two entry methods for each base node type in the AST:
|
||||
/// - matchesChildOf:
|
||||
/// Matches a matcher on every child node of the given node. Returns true
|
||||
/// if at least one child node could be matched.
|
||||
/// - matchesDescendantOf:
|
||||
/// Matches a matcher on all descendant nodes of the given node. Returns true
|
||||
/// if at least one descendant matched.
|
||||
class ASTMatchFinder {
|
||||
public:
|
||||
/// \brief Defines how we descend a level in the AST when we pass
|
||||
/// through expressions.
|
||||
enum TraversalKind {
|
||||
/// Will traverse any child nodes.
|
||||
TK_AsIs,
|
||||
/// Will not traverse implicit casts and parentheses.
|
||||
TK_IgnoreImplicitCastsAndParentheses
|
||||
};
|
||||
|
||||
/// \brief Defines how bindings are processed on recursive matches.
|
||||
enum BindKind {
|
||||
/// Stop at the first match and only bind the first match.
|
||||
BK_First,
|
||||
/// Create results for all combinations of bindings that match.
|
||||
BK_All
|
||||
};
|
||||
|
||||
virtual ~ASTMatchFinder() {}
|
||||
|
||||
/// \brief Returns true if the given class is directly or indirectly derived
|
||||
/// from a base type with the given name.
|
||||
///
|
||||
/// A class is considered to be also derived from itself.
|
||||
virtual bool classIsDerivedFrom(const clang::CXXRecordDecl *Declaration,
|
||||
StringRef BaseName) const = 0;
|
||||
|
||||
// FIXME: Implement for other base nodes.
|
||||
virtual bool matchesChildOf(const clang::Decl &DeclNode,
|
||||
const UntypedBaseMatcher &BaseMatcher,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
TraversalKind Traverse,
|
||||
BindKind Bind) = 0;
|
||||
virtual bool matchesChildOf(const clang::Stmt &StmtNode,
|
||||
const UntypedBaseMatcher &BaseMatcher,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
TraversalKind Traverse,
|
||||
BindKind Bind) = 0;
|
||||
|
||||
virtual bool matchesDescendantOf(const clang::Decl &DeclNode,
|
||||
const UntypedBaseMatcher &BaseMatcher,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
BindKind Bind) = 0;
|
||||
virtual bool matchesDescendantOf(const clang::Stmt &StmtNode,
|
||||
const UntypedBaseMatcher &BaseMatcher,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
BindKind Bind) = 0;
|
||||
};
|
||||
|
||||
/// \brief Converts a Matcher<T> to a matcher of desired type To by "adapting"
|
||||
/// a To into a T.
|
||||
///
|
||||
/// The ArgumentAdapterT argument specifies how the adaptation is done.
|
||||
///
|
||||
/// For example:
|
||||
/// ArgumentAdaptingMatcher<DynCastMatcher, T>(InnerMatcher);
|
||||
/// returns a matcher that can be used where a Matcher<To> is required, if
|
||||
/// To and T are in the same type hierarchy, and thus dyn_cast can be
|
||||
/// called to convert a To to a T.
|
||||
///
|
||||
/// FIXME: Make sure all our applications of this class actually require
|
||||
/// knowledge about the inner type. DynCastMatcher obviously does, but the
|
||||
/// Has *matchers require the inner type solely for COMPILE_ASSERT purposes.
|
||||
template <template <typename ToArg, typename FromArg> class ArgumentAdapterT,
|
||||
typename T>
|
||||
class ArgumentAdaptingMatcher {
|
||||
public:
|
||||
explicit ArgumentAdaptingMatcher(const Matcher<T> &InnerMatcher)
|
||||
: InnerMatcher(InnerMatcher) {}
|
||||
|
||||
template <typename To>
|
||||
operator Matcher<To>() const {
|
||||
return Matcher<To>(new ArgumentAdapterT<To, T>(InnerMatcher));
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<T> InnerMatcher;
|
||||
};
|
||||
|
||||
/// \brief A PolymorphicMatcherWithParamN<MatcherT, P1, ..., PN> object can be
|
||||
/// created from N parameters p1, ..., pN (of type P1, ..., PN) and
|
||||
/// used as a Matcher<T> where a MatcherT<T, P1, ..., PN>(p1, ..., pN)
|
||||
/// can be constructed.
|
||||
///
|
||||
/// For example:
|
||||
/// - PolymorphicMatcherWithParam0<IsDefinitionMatcher>()
|
||||
/// creates an object that can be used as a Matcher<T> for any type T
|
||||
/// where an IsDefinitionMatcher<T>() can be constructed.
|
||||
/// - PolymorphicMatcherWithParam1<ValueEqualsMatcher, int>(42)
|
||||
/// creates an object that can be used as a Matcher<T> for any type T
|
||||
/// where a ValueEqualsMatcher<T, int>(42) can be constructed.
|
||||
template <template <typename T> class MatcherT>
|
||||
class PolymorphicMatcherWithParam0 {
|
||||
public:
|
||||
template <typename T>
|
||||
operator Matcher<T>() const {
|
||||
return Matcher<T>(new MatcherT<T>());
|
||||
}
|
||||
};
|
||||
|
||||
template <template <typename T, typename P1> class MatcherT,
|
||||
typename P1>
|
||||
class PolymorphicMatcherWithParam1 {
|
||||
public:
|
||||
explicit PolymorphicMatcherWithParam1(const P1 &Param1)
|
||||
: Param1(Param1) {}
|
||||
|
||||
template <typename T>
|
||||
operator Matcher<T>() const {
|
||||
return Matcher<T>(new MatcherT<T, P1>(Param1));
|
||||
}
|
||||
|
||||
private:
|
||||
const P1 Param1;
|
||||
};
|
||||
|
||||
template <template <typename T, typename P1, typename P2> class MatcherT,
|
||||
typename P1, typename P2>
|
||||
class PolymorphicMatcherWithParam2 {
|
||||
public:
|
||||
PolymorphicMatcherWithParam2(const P1 &Param1, const P2 &Param2)
|
||||
: Param1(Param1), Param2(Param2) {}
|
||||
|
||||
template <typename T>
|
||||
operator Matcher<T>() const {
|
||||
return Matcher<T>(new MatcherT<T, P1, P2>(Param1, Param2));
|
||||
}
|
||||
|
||||
private:
|
||||
const P1 Param1;
|
||||
const P2 Param2;
|
||||
};
|
||||
|
||||
/// \brief Matches any instance of the given NodeType.
|
||||
///
|
||||
/// This is useful when a matcher syntactically requires a child matcher,
|
||||
/// but the context doesn't care. See for example: anything().
|
||||
///
|
||||
/// FIXME: Alternatively we could also create a IsAMatcher or something
|
||||
/// that checks that a dyn_cast is possible. This is purely needed for the
|
||||
/// difference between calling for example:
|
||||
/// record()
|
||||
/// and
|
||||
/// record(SomeMatcher)
|
||||
/// In the second case we need the correct type we were dyn_cast'ed to in order
|
||||
/// to get the right type for the inner matcher. In the first case we don't need
|
||||
/// that, but we use the type conversion anyway and insert a TrueMatcher.
|
||||
template <typename T>
|
||||
class TrueMatcher : public SingleNodeMatcherInterface<T> {
|
||||
public:
|
||||
virtual bool matchesNode(const T &Node) const {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Provides a MatcherInterface<T> for a Matcher<To> that matches if T is
|
||||
/// dyn_cast'able into To and the given Matcher<To> matches on the dyn_cast'ed
|
||||
/// node.
|
||||
template <typename T, typename To>
|
||||
class DynCastMatcher : public MatcherInterface<T> {
|
||||
public:
|
||||
explicit DynCastMatcher(const Matcher<To> &InnerMatcher)
|
||||
: InnerMatcher(InnerMatcher) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
const To *InnerMatchValue = llvm::dyn_cast<To>(&Node);
|
||||
return InnerMatchValue != NULL &&
|
||||
InnerMatcher.matches(*InnerMatchValue, Finder, Builder);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<To> InnerMatcher;
|
||||
};
|
||||
|
||||
/// \brief Enables the user to pass a Matcher<clang::CXXMemberCallExpr> to
|
||||
/// Call().
|
||||
///
|
||||
/// FIXME: Alternatives are using more specific methods than Call, like
|
||||
/// MemberCall, or not using VariadicFunction for Call and overloading it.
|
||||
template <>
|
||||
template <>
|
||||
inline Matcher<clang::CXXMemberCallExpr>::
|
||||
operator Matcher<clang::CallExpr>() const {
|
||||
return makeMatcher(
|
||||
new DynCastMatcher<clang::CallExpr, clang::CXXMemberCallExpr>(*this));
|
||||
}
|
||||
|
||||
/// \brief Matcher<T> that wraps an inner Matcher<T> and binds the matched node
|
||||
/// to an ID if the inner matcher matches on the node.
|
||||
template <typename T>
|
||||
class IdMatcher : public MatcherInterface<T> {
|
||||
public:
|
||||
/// \brief Creates an IdMatcher that binds to 'ID' if 'InnerMatcher' matches
|
||||
/// the node.
|
||||
IdMatcher(StringRef ID, const Matcher<T> &InnerMatcher)
|
||||
: ID(ID), InnerMatcher(InnerMatcher) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
bool Result = InnerMatcher.matches(Node, Finder, Builder);
|
||||
if (Result) {
|
||||
Builder->setBinding(std::pair<const std::string, const T*>(ID, &Node));
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
private:
|
||||
const std::string ID;
|
||||
const Matcher<T> InnerMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type T that have child nodes of type ChildT for
|
||||
/// which a specified child matcher matches.
|
||||
///
|
||||
/// ChildT must be an AST base type.
|
||||
template <typename T, typename ChildT>
|
||||
class HasMatcher : public MatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT(IsBaseType<ChildT>::value,
|
||||
has_only_accepts_base_type_matcher);
|
||||
public:
|
||||
explicit HasMatcher(const Matcher<ChildT> &ChildMatcher)
|
||||
: ChildMatcher(ChildMatcher) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return Finder->matchesChildOf(
|
||||
Node, ChildMatcher, Builder,
|
||||
ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses,
|
||||
ASTMatchFinder::BK_First);
|
||||
}
|
||||
|
||||
private:
|
||||
const TypedBaseMatcher<ChildT> ChildMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type T that have child nodes of type ChildT for
|
||||
/// which a specified child matcher matches. ChildT must be an AST base
|
||||
/// type.
|
||||
/// As opposed to the HasMatcher, the ForEachMatcher will produce a match
|
||||
/// for each child that matches.
|
||||
template <typename T, typename ChildT>
|
||||
class ForEachMatcher : public MatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT(IsBaseType<ChildT>::value,
|
||||
for_each_only_accepts_base_type_matcher);
|
||||
public:
|
||||
explicit ForEachMatcher(const Matcher<ChildT> &ChildMatcher)
|
||||
: ChildMatcher(ChildMatcher) {}
|
||||
|
||||
virtual bool matches(const T& Node,
|
||||
ASTMatchFinder* Finder,
|
||||
BoundNodesTreeBuilder* Builder) const {
|
||||
return Finder->matchesChildOf(
|
||||
Node, ChildMatcher, Builder,
|
||||
ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses,
|
||||
ASTMatchFinder::BK_All);
|
||||
}
|
||||
|
||||
private:
|
||||
const TypedBaseMatcher<ChildT> ChildMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type T if the given Matcher<T> does not match.
|
||||
///
|
||||
/// Type argument MatcherT is required by PolymorphicMatcherWithParam1
|
||||
/// but not actually used. It will always be instantiated with a type
|
||||
/// convertible to Matcher<T>.
|
||||
template <typename T, typename MatcherT>
|
||||
class NotMatcher : public MatcherInterface<T> {
|
||||
public:
|
||||
explicit NotMatcher(const Matcher<T> &InnerMatcher)
|
||||
: InnerMatcher(InnerMatcher) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return !InnerMatcher.matches(Node, Finder, Builder);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<T> InnerMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type T for which both provided matchers match.
|
||||
///
|
||||
/// Type arguments MatcherT1 and MatcherT2 are required by
|
||||
/// PolymorphicMatcherWithParam2 but not actually used. They will
|
||||
/// always be instantiated with types convertible to Matcher<T>.
|
||||
template <typename T, typename MatcherT1, typename MatcherT2>
|
||||
class AllOfMatcher : public MatcherInterface<T> {
|
||||
public:
|
||||
AllOfMatcher(const Matcher<T> &InnerMatcher1, const Matcher<T> &InnerMatcher2)
|
||||
: InnerMatcher1(InnerMatcher1), InnerMatcher2(InnerMatcher2) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return InnerMatcher1.matches(Node, Finder, Builder) &&
|
||||
InnerMatcher2.matches(Node, Finder, Builder);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<T> InnerMatcher1;
|
||||
const Matcher<T> InnerMatcher2;
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type T for which at least one of the two provided
|
||||
/// matchers matches.
|
||||
///
|
||||
/// Type arguments MatcherT1 and MatcherT2 are
|
||||
/// required by PolymorphicMatcherWithParam2 but not actually
|
||||
/// used. They will always be instantiated with types convertible to
|
||||
/// Matcher<T>.
|
||||
template <typename T, typename MatcherT1, typename MatcherT2>
|
||||
class AnyOfMatcher : public MatcherInterface<T> {
|
||||
public:
|
||||
AnyOfMatcher(const Matcher<T> &InnerMatcher1, const Matcher<T> &InnerMatcher2)
|
||||
: InnerMatcher1(InnerMatcher1), InnertMatcher2(InnerMatcher2) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return InnerMatcher1.matches(Node, Finder, Builder) ||
|
||||
InnertMatcher2.matches(Node, Finder, Builder);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<T> InnerMatcher1;
|
||||
const Matcher<T> InnertMatcher2;
|
||||
};
|
||||
|
||||
/// \brief Creates a Matcher<T> that matches if
|
||||
/// T is dyn_cast'able into InnerT and all inner matchers match.
|
||||
template<typename T, typename InnerT>
|
||||
Matcher<T> makeDynCastAllOfComposite(
|
||||
ArrayRef<const Matcher<InnerT> *> InnerMatchers) {
|
||||
if (InnerMatchers.empty()) {
|
||||
return ArgumentAdaptingMatcher<DynCastMatcher, InnerT>(
|
||||
makeMatcher(new TrueMatcher<InnerT>));
|
||||
}
|
||||
Matcher<InnerT> InnerMatcher = *InnerMatchers.back();
|
||||
for (int i = InnerMatchers.size() - 2; i >= 0; --i) {
|
||||
InnerMatcher = makeMatcher(
|
||||
new AllOfMatcher<InnerT, Matcher<InnerT>, Matcher<InnerT> >(
|
||||
*InnerMatchers[i], InnerMatcher));
|
||||
}
|
||||
return ArgumentAdaptingMatcher<DynCastMatcher, InnerT>(InnerMatcher);
|
||||
}
|
||||
|
||||
/// \brief Matches nodes of type T that have at least one descendant node of
|
||||
/// type DescendantT for which the given inner matcher matches.
|
||||
///
|
||||
/// DescendantT must be an AST base type.
|
||||
template <typename T, typename DescendantT>
|
||||
class HasDescendantMatcher : public MatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT(IsBaseType<DescendantT>::value,
|
||||
has_descendant_only_accepts_base_type_matcher);
|
||||
public:
|
||||
explicit HasDescendantMatcher(const Matcher<DescendantT> &DescendantMatcher)
|
||||
: DescendantMatcher(DescendantMatcher) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return Finder->matchesDescendantOf(
|
||||
Node, DescendantMatcher, Builder, ASTMatchFinder::BK_First);
|
||||
}
|
||||
|
||||
private:
|
||||
const TypedBaseMatcher<DescendantT> DescendantMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type T that have at least one descendant node of
|
||||
/// type DescendantT for which the given inner matcher matches.
|
||||
///
|
||||
/// DescendantT must be an AST base type.
|
||||
/// As opposed to HasDescendantMatcher, ForEachDescendantMatcher will match
|
||||
/// for each descendant node that matches instead of only for the first.
|
||||
template <typename T, typename DescendantT>
|
||||
class ForEachDescendantMatcher : public MatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT(IsBaseType<DescendantT>::value,
|
||||
for_each_descendant_only_accepts_base_type_matcher);
|
||||
public:
|
||||
explicit ForEachDescendantMatcher(
|
||||
const Matcher<DescendantT>& DescendantMatcher)
|
||||
: DescendantMatcher(DescendantMatcher) {}
|
||||
|
||||
virtual bool matches(const T& Node,
|
||||
ASTMatchFinder* Finder,
|
||||
BoundNodesTreeBuilder* Builder) const {
|
||||
return Finder->matchesDescendantOf(Node, DescendantMatcher, Builder,
|
||||
ASTMatchFinder::BK_All);
|
||||
}
|
||||
|
||||
private:
|
||||
const TypedBaseMatcher<DescendantT> DescendantMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches on nodes that have a getValue() method if getValue() equals
|
||||
/// the value the ValueEqualsMatcher was constructed with.
|
||||
template <typename T, typename ValueT>
|
||||
class ValueEqualsMatcher : public SingleNodeMatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT((llvm::is_base_of<clang::CharacterLiteral, T>::value ||
|
||||
llvm::is_base_of<clang::CXXBoolLiteralExpr,
|
||||
T>::value ||
|
||||
llvm::is_base_of<clang::FloatingLiteral, T>::value ||
|
||||
llvm::is_base_of<clang::IntegerLiteral, T>::value),
|
||||
the_node_must_have_a_getValue_method);
|
||||
public:
|
||||
explicit ValueEqualsMatcher(const ValueT &ExpectedValue)
|
||||
: ExpectedValue(ExpectedValue) {}
|
||||
|
||||
virtual bool matchesNode(const T &Node) const {
|
||||
return Node.getValue() == ExpectedValue;
|
||||
}
|
||||
|
||||
private:
|
||||
const ValueT ExpectedValue;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class IsDefinitionMatcher : public SingleNodeMatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT(
|
||||
(llvm::is_base_of<clang::TagDecl, T>::value) ||
|
||||
(llvm::is_base_of<clang::VarDecl, T>::value) ||
|
||||
(llvm::is_base_of<clang::FunctionDecl, T>::value),
|
||||
is_definition_requires_isThisDeclarationADefinition_method);
|
||||
public:
|
||||
virtual bool matchesNode(const T &Node) const {
|
||||
return Node.isThisDeclarationADefinition();
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Matches on template instantiations for FunctionDecl, VarDecl or
|
||||
/// CXXRecordDecl nodes.
|
||||
template <typename T>
|
||||
class IsTemplateInstantiationMatcher : public MatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT((llvm::is_base_of<clang::FunctionDecl, T>::value) ||
|
||||
(llvm::is_base_of<clang::VarDecl, T>::value) ||
|
||||
(llvm::is_base_of<clang::CXXRecordDecl, T>::value),
|
||||
requires_getTemplateSpecializationKind_method);
|
||||
public:
|
||||
virtual bool matches(const T& Node,
|
||||
ASTMatchFinder* Finder,
|
||||
BoundNodesTreeBuilder* Builder) const {
|
||||
return (Node.getTemplateSpecializationKind() ==
|
||||
clang::TSK_ImplicitInstantiation ||
|
||||
Node.getTemplateSpecializationKind() ==
|
||||
clang::TSK_ExplicitInstantiationDefinition);
|
||||
}
|
||||
};
|
||||
|
||||
class IsArrowMatcher : public SingleNodeMatcherInterface<clang::MemberExpr> {
|
||||
public:
|
||||
virtual bool matchesNode(const clang::MemberExpr &Node) const {
|
||||
return Node.isArrow();
|
||||
}
|
||||
};
|
||||
|
||||
class IsConstQualifiedMatcher
|
||||
: public SingleNodeMatcherInterface<clang::QualType> {
|
||||
public:
|
||||
virtual bool matchesNode(const clang::QualType& Node) const {
|
||||
return Node.isConstQualified();
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief A VariadicDynCastAllOfMatcher<SourceT, TargetT> object is a
|
||||
/// variadic functor that takes a number of Matcher<TargetT> and returns a
|
||||
/// Matcher<SourceT> that matches TargetT nodes that are matched by all of the
|
||||
/// given matchers, if SourceT can be dynamically casted into TargetT.
|
||||
///
|
||||
/// For example:
|
||||
/// const VariadicDynCastAllOfMatcher<
|
||||
/// clang::Decl, clang::CXXRecordDecl> record;
|
||||
/// Creates a functor record(...) that creates a Matcher<clang::Decl> given
|
||||
/// a variable number of arguments of type Matcher<clang::CXXRecordDecl>.
|
||||
/// The returned matcher matches if the given clang::Decl can by dynamically
|
||||
/// casted to clang::CXXRecordDecl and all given matchers match.
|
||||
template <typename SourceT, typename TargetT>
|
||||
class VariadicDynCastAllOfMatcher
|
||||
: public llvm::VariadicFunction<
|
||||
Matcher<SourceT>, Matcher<TargetT>,
|
||||
makeDynCastAllOfComposite<SourceT, TargetT> > {
|
||||
public:
|
||||
VariadicDynCastAllOfMatcher() {}
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace ast_matchers
|
||||
} // end namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H
|
|
@ -0,0 +1,224 @@
|
|||
//===--- ASTMatchersMacros.h - Structural query framework -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Defines macros that enable us to define new matchers in a single place.
|
||||
// Since a matcher is a function which returns a Matcher<T> object, where
|
||||
// T is the type of the actual implementation of the matcher, the macros allow
|
||||
// us to write matchers like functions and take care of the definition of the
|
||||
// class boilerplate.
|
||||
//
|
||||
// Note that when you define a matcher with an AST_MATCHER* macro, only the
|
||||
// function which creates the matcher goes into the current namespace - the
|
||||
// class that implements the actual matcher, which gets returned by the
|
||||
// generator function, is put into the 'internal' namespace. This allows us
|
||||
// to only have the functions (which is all the user cares about) in the
|
||||
// 'ast_matchers' namespace and hide the boilerplate.
|
||||
//
|
||||
// To define a matcher in user code, always put it into the clang::ast_matchers
|
||||
// namespace and refer to the internal types via the 'internal::':
|
||||
//
|
||||
// namespace clang {
|
||||
// namespace ast_matchers {
|
||||
// AST_MATCHER_P(MemberExpr, Member,
|
||||
// internal::Matcher<ValueDecl>, InnerMatcher) {
|
||||
// return InnerMatcher.matches(*Node.getMemberDecl(), Finder, Builder);
|
||||
// }
|
||||
// } // end namespace ast_matchers
|
||||
// } // end namespace clang
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H
|
||||
#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H
|
||||
|
||||
/// \brief AST_MATCHER(Type, DefineMatcher) { ... }
|
||||
/// defines a zero parameter function named DefineMatcher() that returns a
|
||||
/// Matcher<Type> object.
|
||||
///
|
||||
/// The code between the curly braces has access to the following variables:
|
||||
///
|
||||
/// Node: the AST node being matched; its type is Type.
|
||||
/// Finder: an ASTMatchFinder*.
|
||||
/// Builder: a BoundNodesTreeBuilder*.
|
||||
///
|
||||
/// The code should return true if 'Node' matches.
|
||||
#define AST_MATCHER(Type, DefineMatcher) \
|
||||
namespace internal { \
|
||||
class matcher_##DefineMatcher##Matcher \
|
||||
: public MatcherInterface<Type> { \
|
||||
public: \
|
||||
explicit matcher_##DefineMatcher##Matcher() {} \
|
||||
virtual bool matches( \
|
||||
const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const; \
|
||||
}; \
|
||||
} \
|
||||
inline internal::Matcher<Type> DefineMatcher() { \
|
||||
return internal::makeMatcher( \
|
||||
new internal::matcher_##DefineMatcher##Matcher()); \
|
||||
} \
|
||||
inline bool internal::matcher_##DefineMatcher##Matcher::matches( \
|
||||
const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const
|
||||
|
||||
/// \brief AST_MATCHER_P(Type, DefineMatcher, ParamType, Param) { ... }
|
||||
/// defines a single-parameter function named DefineMatcher() that returns a
|
||||
/// Matcher<Type> object.
|
||||
///
|
||||
/// The code between the curly braces has access to the following variables:
|
||||
///
|
||||
/// Node: the AST node being matched; its type is Type.
|
||||
/// Param: the parameter passed to the function; its type
|
||||
/// is ParamType.
|
||||
/// Finder: an ASTMatchFinder*.
|
||||
/// Builder: a BoundNodesTreeBuilder*.
|
||||
///
|
||||
/// The code should return true if 'Node' matches.
|
||||
#define AST_MATCHER_P(Type, DefineMatcher, ParamType, Param) \
|
||||
namespace internal { \
|
||||
class matcher_##DefineMatcher##Matcher \
|
||||
: public MatcherInterface<Type> { \
|
||||
public: \
|
||||
explicit matcher_##DefineMatcher##Matcher( \
|
||||
const ParamType &A##Param) : Param(A##Param) {} \
|
||||
virtual bool matches( \
|
||||
const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const; \
|
||||
private: \
|
||||
const ParamType Param; \
|
||||
}; \
|
||||
} \
|
||||
inline internal::Matcher<Type> DefineMatcher(const ParamType &Param) { \
|
||||
return internal::makeMatcher( \
|
||||
new internal::matcher_##DefineMatcher##Matcher(Param)); \
|
||||
} \
|
||||
inline bool internal::matcher_##DefineMatcher##Matcher::matches( \
|
||||
const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const
|
||||
|
||||
/// \brief AST_MATCHER_P2(
|
||||
/// Type, DefineMatcher, ParamType1, Param1, ParamType2, Param2) { ... }
|
||||
/// defines a two-parameter function named DefineMatcher() that returns a
|
||||
/// Matcher<Type> object.
|
||||
///
|
||||
/// The code between the curly braces has access to the following variables:
|
||||
///
|
||||
/// Node: the AST node being matched; its type is Type.
|
||||
/// Param1, Param2: the parameters passed to the function; their types
|
||||
/// are ParamType1 and ParamType2.
|
||||
/// Finder: an ASTMatchFinder*.
|
||||
/// Builder: a BoundNodesTreeBuilder*.
|
||||
///
|
||||
/// The code should return true if 'Node' matches.
|
||||
#define AST_MATCHER_P2( \
|
||||
Type, DefineMatcher, ParamType1, Param1, ParamType2, Param2) \
|
||||
namespace internal { \
|
||||
class matcher_##DefineMatcher##Matcher \
|
||||
: public MatcherInterface<Type> { \
|
||||
public: \
|
||||
matcher_##DefineMatcher##Matcher( \
|
||||
const ParamType1 &A##Param1, const ParamType2 &A##Param2) \
|
||||
: Param1(A##Param1), Param2(A##Param2) {} \
|
||||
virtual bool matches( \
|
||||
const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const; \
|
||||
private: \
|
||||
const ParamType1 Param1; \
|
||||
const ParamType2 Param2; \
|
||||
}; \
|
||||
} \
|
||||
inline internal::Matcher<Type> DefineMatcher( \
|
||||
const ParamType1 &Param1, const ParamType2 &Param2) { \
|
||||
return internal::makeMatcher( \
|
||||
new internal::matcher_##DefineMatcher##Matcher( \
|
||||
Param1, Param2)); \
|
||||
} \
|
||||
inline bool internal::matcher_##DefineMatcher##Matcher::matches( \
|
||||
const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const
|
||||
|
||||
/// \brief AST_POLYMORPHIC_MATCHER_P(DefineMatcher, ParamType, Param) { ... }
|
||||
/// defines a single-parameter function named DefineMatcher() that is
|
||||
/// polymorphic in the return type.
|
||||
///
|
||||
/// The variables are the same as for
|
||||
/// AST_MATCHER_P, with the addition of NodeType, which specifies the node type
|
||||
/// of the matcher Matcher<NodeType> returned by the function matcher().
|
||||
///
|
||||
/// FIXME: Pull out common code with above macro?
|
||||
#define AST_POLYMORPHIC_MATCHER_P(DefineMatcher, ParamType, Param) \
|
||||
namespace internal { \
|
||||
template <typename NodeType, typename ParamT> \
|
||||
class matcher_##DefineMatcher##Matcher \
|
||||
: public MatcherInterface<NodeType> { \
|
||||
public: \
|
||||
explicit matcher_##DefineMatcher##Matcher( \
|
||||
const ParamType &A##Param) : Param(A##Param) {} \
|
||||
virtual bool matches( \
|
||||
const NodeType &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const; \
|
||||
private: \
|
||||
const ParamType Param; \
|
||||
}; \
|
||||
} \
|
||||
inline internal::PolymorphicMatcherWithParam1< \
|
||||
internal::matcher_##DefineMatcher##Matcher, \
|
||||
ParamType > \
|
||||
DefineMatcher(const ParamType &Param) { \
|
||||
return internal::PolymorphicMatcherWithParam1< \
|
||||
internal::matcher_##DefineMatcher##Matcher, \
|
||||
ParamType >(Param); \
|
||||
} \
|
||||
template <typename NodeType, typename ParamT> \
|
||||
bool internal::matcher_##DefineMatcher##Matcher<NodeType, ParamT>::matches( \
|
||||
const NodeType &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const
|
||||
|
||||
/// \brief AST_POLYMORPHIC_MATCHER_P2(
|
||||
/// DefineMatcher, ParamType1, Param1, ParamType2, Param2) { ... }
|
||||
/// defines a two-parameter function named matcher() that is polymorphic in
|
||||
/// the return type.
|
||||
///
|
||||
/// The variables are the same as for AST_MATCHER_P2, with the
|
||||
/// addition of NodeType, which specifies the node type of the matcher
|
||||
/// Matcher<NodeType> returned by the function DefineMatcher().
|
||||
#define AST_POLYMORPHIC_MATCHER_P2( \
|
||||
DefineMatcher, ParamType1, Param1, ParamType2, Param2) \
|
||||
namespace internal { \
|
||||
template <typename NodeType, typename ParamT1, typename ParamT2> \
|
||||
class matcher_##DefineMatcher##Matcher \
|
||||
: public MatcherInterface<NodeType> { \
|
||||
public: \
|
||||
matcher_##DefineMatcher##Matcher( \
|
||||
const ParamType1 &A##Param1, const ParamType2 &A##Param2) \
|
||||
: Param1(A##Param1), Param2(A##Param2) {} \
|
||||
virtual bool matches( \
|
||||
const NodeType &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const; \
|
||||
private: \
|
||||
const ParamType1 Param1; \
|
||||
const ParamType2 Param2; \
|
||||
}; \
|
||||
} \
|
||||
inline internal::PolymorphicMatcherWithParam2< \
|
||||
internal::matcher_##DefineMatcher##Matcher, \
|
||||
ParamType1, ParamType2 > \
|
||||
DefineMatcher(const ParamType1 &Param1, const ParamType2 &Param2) { \
|
||||
return internal::PolymorphicMatcherWithParam2< \
|
||||
internal::matcher_##DefineMatcher##Matcher, \
|
||||
ParamType1, ParamType2 >( \
|
||||
Param1, Param2); \
|
||||
} \
|
||||
template <typename NodeType, typename ParamT1, typename ParamT2> \
|
||||
bool internal::matcher_##DefineMatcher##Matcher< \
|
||||
NodeType, ParamT1, ParamT2>::matches( \
|
||||
const NodeType &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const
|
||||
|
||||
#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H
|
|
@ -0,0 +1,556 @@
|
|||
//===--- ASTMatchFinder.cpp - Structural query framework ------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Implements an algorithm to efficiently search for matches on AST nodes.
|
||||
// Uses memoization to support recursive matches like HasDescendant.
|
||||
//
|
||||
// The general idea is to visit all AST nodes with a RecursiveASTVisitor,
|
||||
// calling the Matches(...) method of each matcher we are running on each
|
||||
// AST node. The matcher can recurse via the ASTMatchFinder interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/RecursiveASTVisitor.h"
|
||||
#include <set>
|
||||
|
||||
namespace clang {
|
||||
namespace ast_matchers {
|
||||
namespace internal {
|
||||
namespace {
|
||||
|
||||
// Returns the value that 'AMap' maps 'Key' to, or NULL if 'Key' is
|
||||
// not in 'AMap'.
|
||||
template <typename Map>
|
||||
static const typename Map::mapped_type *
|
||||
find(const Map &AMap, const typename Map::key_type &Key) {
|
||||
typename Map::const_iterator It = AMap.find(Key);
|
||||
return It == AMap.end() ? NULL : &It->second;
|
||||
}
|
||||
|
||||
// We use memoization to avoid running the same matcher on the same
|
||||
// AST node twice. This pair is the key for looking up match
|
||||
// result. It consists of an ID of the MatcherInterface (for
|
||||
// identifying the matcher) and a pointer to the AST node.
|
||||
typedef std::pair<uint64_t, const void*> UntypedMatchInput;
|
||||
|
||||
// Used to store the result of a match and possibly bound nodes.
|
||||
struct MemoizedMatchResult {
|
||||
bool ResultOfMatch;
|
||||
BoundNodesTree Nodes;
|
||||
};
|
||||
|
||||
// A RecursiveASTVisitor that traverses all children or all descendants of
|
||||
// a node.
|
||||
class MatchChildASTVisitor
|
||||
: public clang::RecursiveASTVisitor<MatchChildASTVisitor> {
|
||||
public:
|
||||
typedef clang::RecursiveASTVisitor<MatchChildASTVisitor> VisitorBase;
|
||||
|
||||
// Creates an AST visitor that matches 'matcher' on all children or
|
||||
// descendants of a traversed node. max_depth is the maximum depth
|
||||
// to traverse: use 1 for matching the children and INT_MAX for
|
||||
// matching the descendants.
|
||||
MatchChildASTVisitor(const UntypedBaseMatcher *BaseMatcher,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
int MaxDepth,
|
||||
ASTMatchFinder::TraversalKind Traversal,
|
||||
ASTMatchFinder::BindKind Bind)
|
||||
: BaseMatcher(BaseMatcher),
|
||||
Finder(Finder),
|
||||
Builder(Builder),
|
||||
CurrentDepth(-1),
|
||||
MaxDepth(MaxDepth),
|
||||
Traversal(Traversal),
|
||||
Bind(Bind),
|
||||
Matches(false) {}
|
||||
|
||||
// Returns true if a match is found in the subtree rooted at the
|
||||
// given AST node. This is done via a set of mutually recursive
|
||||
// functions. Here's how the recursion is done (the *wildcard can
|
||||
// actually be Decl, Stmt, or Type):
|
||||
//
|
||||
// - Traverse(node) calls BaseTraverse(node) when it needs
|
||||
// to visit the descendants of node.
|
||||
// - BaseTraverse(node) then calls (via VisitorBase::Traverse*(node))
|
||||
// Traverse*(c) for each child c of 'node'.
|
||||
// - Traverse*(c) in turn calls Traverse(c), completing the
|
||||
// recursion.
|
||||
template <typename T>
|
||||
bool findMatch(const T &Node) {
|
||||
reset();
|
||||
traverse(Node);
|
||||
return Matches;
|
||||
}
|
||||
|
||||
// The following are overriding methods from the base visitor class.
|
||||
// They are public only to allow CRTP to work. They are *not *part
|
||||
// of the public API of this class.
|
||||
bool TraverseDecl(clang::Decl *DeclNode) {
|
||||
return (DeclNode == NULL) || traverse(*DeclNode);
|
||||
}
|
||||
bool TraverseStmt(clang::Stmt *StmtNode) {
|
||||
const clang::Stmt *StmtToTraverse = StmtNode;
|
||||
if (Traversal ==
|
||||
ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses) {
|
||||
const clang::Expr *ExprNode = dyn_cast_or_null<clang::Expr>(StmtNode);
|
||||
if (ExprNode != NULL) {
|
||||
StmtToTraverse = ExprNode->IgnoreParenImpCasts();
|
||||
}
|
||||
}
|
||||
return (StmtToTraverse == NULL) || traverse(*StmtToTraverse);
|
||||
}
|
||||
bool TraverseType(clang::QualType TypeNode) {
|
||||
return traverse(TypeNode);
|
||||
}
|
||||
|
||||
bool shouldVisitTemplateInstantiations() const { return true; }
|
||||
bool shouldVisitImplicitCode() const { return true; }
|
||||
|
||||
private:
|
||||
// Used for updating the depth during traversal.
|
||||
struct ScopedIncrement {
|
||||
explicit ScopedIncrement(int *Depth) : Depth(Depth) { ++(*Depth); }
|
||||
~ScopedIncrement() { --(*Depth); }
|
||||
|
||||
private:
|
||||
int *Depth;
|
||||
};
|
||||
|
||||
// Resets the state of this object.
|
||||
void reset() {
|
||||
Matches = false;
|
||||
CurrentDepth = -1;
|
||||
}
|
||||
|
||||
// Forwards the call to the corresponding Traverse*() method in the
|
||||
// base visitor class.
|
||||
bool baseTraverse(const clang::Decl &DeclNode) {
|
||||
return VisitorBase::TraverseDecl(const_cast<clang::Decl*>(&DeclNode));
|
||||
}
|
||||
bool baseTraverse(const clang::Stmt &StmtNode) {
|
||||
return VisitorBase::TraverseStmt(const_cast<clang::Stmt*>(&StmtNode));
|
||||
}
|
||||
bool baseTraverse(clang::QualType TypeNode) {
|
||||
return VisitorBase::TraverseType(TypeNode);
|
||||
}
|
||||
|
||||
// Traverses the subtree rooted at 'node'; returns true if the
|
||||
// traversal should continue after this function returns; also sets
|
||||
// matched_ to true if a match is found during the traversal.
|
||||
template <typename T>
|
||||
bool traverse(const T &Node) {
|
||||
TOOLING_COMPILE_ASSERT(IsBaseType<T>::value,
|
||||
traverse_can_only_be_instantiated_with_base_type);
|
||||
ScopedIncrement ScopedDepth(&CurrentDepth);
|
||||
if (CurrentDepth == 0) {
|
||||
// We don't want to match the root node, so just recurse.
|
||||
return baseTraverse(Node);
|
||||
}
|
||||
if (Bind != ASTMatchFinder::BK_All) {
|
||||
if (BaseMatcher->matches(Node, Finder, Builder)) {
|
||||
Matches = true;
|
||||
return false; // Abort as soon as a match is found.
|
||||
}
|
||||
if (CurrentDepth < MaxDepth) {
|
||||
// The current node doesn't match, and we haven't reached the
|
||||
// maximum depth yet, so recurse.
|
||||
return baseTraverse(Node);
|
||||
}
|
||||
// The current node doesn't match, and we have reached the
|
||||
// maximum depth, so don't recurse (but continue the traversal
|
||||
// such that other nodes at the current level can be visited).
|
||||
return true;
|
||||
} else {
|
||||
BoundNodesTreeBuilder RecursiveBuilder;
|
||||
if (BaseMatcher->matches(Node, Finder, &RecursiveBuilder)) {
|
||||
// After the first match the matcher succeeds.
|
||||
Matches = true;
|
||||
Builder->addMatch(RecursiveBuilder.build());
|
||||
}
|
||||
if (CurrentDepth < MaxDepth) {
|
||||
baseTraverse(Node);
|
||||
}
|
||||
// In kBindAll mode we always search for more matches.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const UntypedBaseMatcher *const BaseMatcher;
|
||||
ASTMatchFinder *const Finder;
|
||||
BoundNodesTreeBuilder *const Builder;
|
||||
int CurrentDepth;
|
||||
const int MaxDepth;
|
||||
const ASTMatchFinder::TraversalKind Traversal;
|
||||
const ASTMatchFinder::BindKind Bind;
|
||||
bool Matches;
|
||||
};
|
||||
|
||||
// Controls the outermost traversal of the AST and allows to match multiple
|
||||
// matchers.
|
||||
class MatchASTVisitor : public clang::RecursiveASTVisitor<MatchASTVisitor>,
|
||||
public ASTMatchFinder {
|
||||
public:
|
||||
MatchASTVisitor(std::vector< std::pair<const UntypedBaseMatcher*,
|
||||
MatchFinder::MatchCallback*> > *Triggers)
|
||||
: Triggers(Triggers),
|
||||
ActiveASTContext(NULL) {
|
||||
}
|
||||
|
||||
void set_active_ast_context(clang::ASTContext *NewActiveASTContext) {
|
||||
ActiveASTContext = NewActiveASTContext;
|
||||
}
|
||||
|
||||
// The following Visit*() and Traverse*() functions "override"
|
||||
// methods in RecursiveASTVisitor.
|
||||
|
||||
bool VisitTypedefDecl(clang::TypedefDecl *DeclNode) {
|
||||
// When we see 'typedef A B', we add name 'B' to the set of names
|
||||
// A's canonical type maps to. This is necessary for implementing
|
||||
// IsDerivedFrom(x) properly, where x can be the name of the base
|
||||
// class or any of its aliases.
|
||||
//
|
||||
// In general, the is-alias-of (as defined by typedefs) relation
|
||||
// is tree-shaped, as you can typedef a type more than once. For
|
||||
// example,
|
||||
//
|
||||
// typedef A B;
|
||||
// typedef A C;
|
||||
// typedef C D;
|
||||
// typedef C E;
|
||||
//
|
||||
// gives you
|
||||
//
|
||||
// A
|
||||
// |- B
|
||||
// `- C
|
||||
// |- D
|
||||
// `- E
|
||||
//
|
||||
// It is wrong to assume that the relation is a chain. A correct
|
||||
// implementation of IsDerivedFrom() needs to recognize that B and
|
||||
// E are aliases, even though neither is a typedef of the other.
|
||||
// Therefore, we cannot simply walk through one typedef chain to
|
||||
// find out whether the type name matches.
|
||||
const clang::Type *TypeNode = DeclNode->getUnderlyingType().getTypePtr();
|
||||
const clang::Type *CanonicalType = // root of the typedef tree
|
||||
ActiveASTContext->getCanonicalType(TypeNode);
|
||||
TypeToUnqualifiedAliases[CanonicalType].insert(
|
||||
DeclNode->getName().str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TraverseDecl(clang::Decl *DeclNode);
|
||||
bool TraverseStmt(clang::Stmt *StmtNode);
|
||||
bool TraverseType(clang::QualType TypeNode);
|
||||
bool TraverseTypeLoc(clang::TypeLoc TypeNode);
|
||||
|
||||
// Matches children or descendants of 'Node' with 'BaseMatcher'.
|
||||
template <typename T>
|
||||
bool memoizedMatchesRecursively(const T &Node,
|
||||
const UntypedBaseMatcher &BaseMatcher,
|
||||
BoundNodesTreeBuilder *Builder, int MaxDepth,
|
||||
TraversalKind Traversal, BindKind Bind) {
|
||||
TOOLING_COMPILE_ASSERT((llvm::is_same<T, clang::Decl>::value) ||
|
||||
(llvm::is_same<T, clang::Stmt>::value),
|
||||
type_does_not_support_memoization);
|
||||
const UntypedMatchInput input(BaseMatcher.getID(), &Node);
|
||||
std::pair<MemoizationMap::iterator, bool> InsertResult
|
||||
= ResultCache.insert(std::make_pair(input, MemoizedMatchResult()));
|
||||
if (InsertResult.second) {
|
||||
BoundNodesTreeBuilder DescendantBoundNodesBuilder;
|
||||
InsertResult.first->second.ResultOfMatch =
|
||||
matchesRecursively(Node, BaseMatcher, &DescendantBoundNodesBuilder,
|
||||
MaxDepth, Traversal, Bind);
|
||||
InsertResult.first->second.Nodes =
|
||||
DescendantBoundNodesBuilder.build();
|
||||
}
|
||||
InsertResult.first->second.Nodes.copyTo(Builder);
|
||||
return InsertResult.first->second.ResultOfMatch;
|
||||
}
|
||||
|
||||
// Matches children or descendants of 'Node' with 'BaseMatcher'.
|
||||
template <typename T>
|
||||
bool matchesRecursively(const T &Node, const UntypedBaseMatcher &BaseMatcher,
|
||||
BoundNodesTreeBuilder *Builder, int MaxDepth,
|
||||
TraversalKind Traversal, BindKind Bind) {
|
||||
MatchChildASTVisitor Visitor(
|
||||
&BaseMatcher, this, Builder, MaxDepth, Traversal, Bind);
|
||||
return Visitor.findMatch(Node);
|
||||
}
|
||||
|
||||
virtual bool classIsDerivedFrom(const clang::CXXRecordDecl *Declaration,
|
||||
StringRef BaseName) const;
|
||||
|
||||
// Implements ASTMatchFinder::MatchesChildOf.
|
||||
virtual bool matchesChildOf(const clang::Decl &DeclNode,
|
||||
const UntypedBaseMatcher &BaseMatcher,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
TraversalKind Traversal,
|
||||
BindKind Bind) {
|
||||
return matchesRecursively(DeclNode, BaseMatcher, Builder, 1, Traversal,
|
||||
Bind);
|
||||
}
|
||||
virtual bool matchesChildOf(const clang::Stmt &StmtNode,
|
||||
const UntypedBaseMatcher &BaseMatcher,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
TraversalKind Traversal,
|
||||
BindKind Bind) {
|
||||
return matchesRecursively(StmtNode, BaseMatcher, Builder, 1, Traversal,
|
||||
Bind);
|
||||
}
|
||||
|
||||
// Implements ASTMatchFinder::MatchesDescendantOf.
|
||||
virtual bool matchesDescendantOf(const clang::Decl &DeclNode,
|
||||
const UntypedBaseMatcher &BaseMatcher,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
BindKind Bind) {
|
||||
return memoizedMatchesRecursively(DeclNode, BaseMatcher, Builder, INT_MAX,
|
||||
TK_AsIs, Bind);
|
||||
}
|
||||
virtual bool matchesDescendantOf(const clang::Stmt &StmtNode,
|
||||
const UntypedBaseMatcher &BaseMatcher,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
BindKind Bind) {
|
||||
return memoizedMatchesRecursively(StmtNode, BaseMatcher, Builder, INT_MAX,
|
||||
TK_AsIs, Bind);
|
||||
}
|
||||
|
||||
bool shouldVisitTemplateInstantiations() const { return true; }
|
||||
bool shouldVisitImplicitCode() const { return true; }
|
||||
|
||||
private:
|
||||
// Implements a BoundNodesTree::Visitor that calls a MatchCallback with
|
||||
// the aggregated bound nodes for each match.
|
||||
class MatchVisitor : public BoundNodesTree::Visitor {
|
||||
public:
|
||||
MatchVisitor(clang::ASTContext* Context,
|
||||
MatchFinder::MatchCallback* Callback)
|
||||
: Context(Context),
|
||||
Callback(Callback) {}
|
||||
|
||||
virtual void visitMatch(const BoundNodes& BoundNodesView) {
|
||||
Callback->run(MatchFinder::MatchResult(BoundNodesView, Context));
|
||||
}
|
||||
|
||||
private:
|
||||
clang::ASTContext* Context;
|
||||
MatchFinder::MatchCallback* Callback;
|
||||
};
|
||||
|
||||
// Returns true if 'TypeNode' is also known by the name 'Name'. In other
|
||||
// words, there is a type (including typedef) with the name 'Name'
|
||||
// that is equal to 'TypeNode'.
|
||||
bool typeHasAlias(const clang::Type *TypeNode,
|
||||
StringRef Name) const {
|
||||
const clang::Type *const CanonicalType =
|
||||
ActiveASTContext->getCanonicalType(TypeNode);
|
||||
const std::set<std::string> *UnqualifiedAlias =
|
||||
find(TypeToUnqualifiedAliases, CanonicalType);
|
||||
return UnqualifiedAlias != NULL && UnqualifiedAlias->count(Name) > 0;
|
||||
}
|
||||
|
||||
// Matches all registered matchers on the given node and calls the
|
||||
// result callback for every node that matches.
|
||||
template <typename T>
|
||||
void match(const T &node) {
|
||||
for (std::vector< std::pair<const UntypedBaseMatcher*,
|
||||
MatchFinder::MatchCallback*> >::const_iterator
|
||||
It = Triggers->begin(), End = Triggers->end();
|
||||
It != End; ++It) {
|
||||
BoundNodesTreeBuilder Builder;
|
||||
if (It->first->matches(node, this, &Builder)) {
|
||||
BoundNodesTree BoundNodes = Builder.build();
|
||||
MatchVisitor Visitor(ActiveASTContext, It->second);
|
||||
BoundNodes.visitMatches(&Visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector< std::pair<const UntypedBaseMatcher*,
|
||||
MatchFinder::MatchCallback*> > *const Triggers;
|
||||
clang::ASTContext *ActiveASTContext;
|
||||
|
||||
// Maps a canonical type to the names of its typedefs.
|
||||
llvm::DenseMap<const clang::Type*, std::set<std::string> >
|
||||
TypeToUnqualifiedAliases;
|
||||
|
||||
// Maps (matcher, node) -> the match result for memoization.
|
||||
typedef llvm::DenseMap<UntypedMatchInput, MemoizedMatchResult> MemoizationMap;
|
||||
MemoizationMap ResultCache;
|
||||
};
|
||||
|
||||
// Returns true if the given class is directly or indirectly derived
|
||||
// from a base type with the given name. A class is considered to be
|
||||
// also derived from itself.
|
||||
bool
|
||||
MatchASTVisitor::classIsDerivedFrom(const clang::CXXRecordDecl *Declaration,
|
||||
StringRef BaseName) const {
|
||||
if (Declaration->getName() == BaseName) {
|
||||
return true;
|
||||
}
|
||||
if (!Declaration->hasDefinition()) {
|
||||
return false;
|
||||
}
|
||||
typedef clang::CXXRecordDecl::base_class_const_iterator BaseIterator;
|
||||
for (BaseIterator It = Declaration->bases_begin(),
|
||||
End = Declaration->bases_end(); It != End; ++It) {
|
||||
const clang::Type *TypeNode = It->getType().getTypePtr();
|
||||
|
||||
if (typeHasAlias(TypeNode, BaseName))
|
||||
return true;
|
||||
|
||||
// clang::Type::getAs<...>() drills through typedefs.
|
||||
if (TypeNode->getAs<clang::DependentNameType>() != NULL ||
|
||||
TypeNode->getAs<clang::TemplateTypeParmType>() != NULL) {
|
||||
// Dependent names and template TypeNode parameters will be matched when
|
||||
// the template is instantiated.
|
||||
continue;
|
||||
}
|
||||
clang::CXXRecordDecl *ClassDecl = NULL;
|
||||
clang::TemplateSpecializationType const *TemplateType =
|
||||
TypeNode->getAs<clang::TemplateSpecializationType>();
|
||||
if (TemplateType != NULL) {
|
||||
if (TemplateType->getTemplateName().isDependent()) {
|
||||
// Dependent template specializations will be matched when the
|
||||
// template is instantiated.
|
||||
continue;
|
||||
}
|
||||
// For template specialization types which are specializing a template
|
||||
// declaration which is an explicit or partial specialization of another
|
||||
// template declaration, getAsCXXRecordDecl() returns the corresponding
|
||||
// ClassTemplateSpecializationDecl.
|
||||
//
|
||||
// For template specialization types which are specializing a template
|
||||
// declaration which is neither an explicit nor partial specialization of
|
||||
// another template declaration, getAsCXXRecordDecl() returns NULL and
|
||||
// we get the CXXRecordDecl of the templated declaration.
|
||||
clang::CXXRecordDecl *SpecializationDecl =
|
||||
TemplateType->getAsCXXRecordDecl();
|
||||
if (SpecializationDecl != NULL) {
|
||||
ClassDecl = SpecializationDecl;
|
||||
} else {
|
||||
ClassDecl = llvm::dyn_cast<clang::CXXRecordDecl>(
|
||||
TemplateType->getTemplateName()
|
||||
.getAsTemplateDecl()->getTemplatedDecl());
|
||||
}
|
||||
} else {
|
||||
ClassDecl = TypeNode->getAsCXXRecordDecl();
|
||||
}
|
||||
assert(ClassDecl != NULL);
|
||||
assert(ClassDecl != Declaration);
|
||||
if (classIsDerivedFrom(ClassDecl, BaseName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MatchASTVisitor::TraverseDecl(clang::Decl *DeclNode) {
|
||||
if (DeclNode == NULL) {
|
||||
return true;
|
||||
}
|
||||
match(*DeclNode);
|
||||
return clang::RecursiveASTVisitor<MatchASTVisitor>::TraverseDecl(DeclNode);
|
||||
}
|
||||
|
||||
bool MatchASTVisitor::TraverseStmt(clang::Stmt *StmtNode) {
|
||||
if (StmtNode == NULL) {
|
||||
return true;
|
||||
}
|
||||
match(*StmtNode);
|
||||
return clang::RecursiveASTVisitor<MatchASTVisitor>::TraverseStmt(StmtNode);
|
||||
}
|
||||
|
||||
bool MatchASTVisitor::TraverseType(clang::QualType TypeNode) {
|
||||
match(TypeNode);
|
||||
return clang::RecursiveASTVisitor<MatchASTVisitor>::TraverseType(TypeNode);
|
||||
}
|
||||
|
||||
bool MatchASTVisitor::TraverseTypeLoc(clang::TypeLoc TypeLoc) {
|
||||
return clang::RecursiveASTVisitor<MatchASTVisitor>::
|
||||
TraverseType(TypeLoc.getType());
|
||||
}
|
||||
|
||||
class MatchASTConsumer : public clang::ASTConsumer {
|
||||
public:
|
||||
MatchASTConsumer(std::vector< std::pair<const UntypedBaseMatcher*,
|
||||
MatchFinder::MatchCallback*> > *Triggers,
|
||||
MatchFinder::ParsingDoneTestCallback *ParsingDone)
|
||||
: Visitor(Triggers),
|
||||
ParsingDone(ParsingDone) {}
|
||||
|
||||
private:
|
||||
virtual void HandleTranslationUnit(clang::ASTContext &Context) {
|
||||
if (ParsingDone != NULL) {
|
||||
ParsingDone->run();
|
||||
}
|
||||
Visitor.set_active_ast_context(&Context);
|
||||
Visitor.TraverseDecl(Context.getTranslationUnitDecl());
|
||||
Visitor.set_active_ast_context(NULL);
|
||||
}
|
||||
|
||||
MatchASTVisitor Visitor;
|
||||
MatchFinder::ParsingDoneTestCallback *ParsingDone;
|
||||
};
|
||||
|
||||
} // end namespace
|
||||
} // end namespace internal
|
||||
|
||||
MatchFinder::MatchResult::MatchResult(const BoundNodes &Nodes,
|
||||
clang::ASTContext *Context)
|
||||
: Nodes(Nodes), Context(Context),
|
||||
SourceManager(&Context->getSourceManager()) {}
|
||||
|
||||
MatchFinder::MatchCallback::~MatchCallback() {}
|
||||
MatchFinder::ParsingDoneTestCallback::~ParsingDoneTestCallback() {}
|
||||
|
||||
MatchFinder::MatchFinder() : ParsingDone(NULL) {}
|
||||
|
||||
MatchFinder::~MatchFinder() {
|
||||
for (std::vector< std::pair<const internal::UntypedBaseMatcher*,
|
||||
MatchFinder::MatchCallback*> >::const_iterator
|
||||
It = Triggers.begin(), End = Triggers.end();
|
||||
It != End; ++It) {
|
||||
delete It->first;
|
||||
}
|
||||
}
|
||||
|
||||
void MatchFinder::addMatcher(const DeclarationMatcher &NodeMatch,
|
||||
MatchCallback *Action) {
|
||||
Triggers.push_back(std::make_pair(
|
||||
new internal::TypedBaseMatcher<clang::Decl>(NodeMatch), Action));
|
||||
}
|
||||
|
||||
void MatchFinder::addMatcher(const TypeMatcher &NodeMatch,
|
||||
MatchCallback *Action) {
|
||||
Triggers.push_back(std::make_pair(
|
||||
new internal::TypedBaseMatcher<clang::QualType>(NodeMatch), Action));
|
||||
}
|
||||
|
||||
void MatchFinder::addMatcher(const StatementMatcher &NodeMatch,
|
||||
MatchCallback *Action) {
|
||||
Triggers.push_back(std::make_pair(
|
||||
new internal::TypedBaseMatcher<clang::Stmt>(NodeMatch), Action));
|
||||
}
|
||||
|
||||
clang::ASTConsumer *MatchFinder::newASTConsumer() {
|
||||
return new internal::MatchASTConsumer(&Triggers, ParsingDone);
|
||||
}
|
||||
|
||||
void MatchFinder::registerTestCallbackAfterParsing(
|
||||
MatchFinder::ParsingDoneTestCallback *NewParsingDone) {
|
||||
ParsingDone = NewParsingDone;
|
||||
}
|
||||
|
||||
} // end namespace ast_matchers
|
||||
} // end namespace clang
|
|
@ -0,0 +1,102 @@
|
|||
//===--- ASTMatchersInternal.cpp - Structural query framework -------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Implements the base layer of the matcher framework.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/ASTMatchers/ASTMatchers.h"
|
||||
#include "clang/ASTMatchers/ASTMatchersInternal.h"
|
||||
|
||||
namespace clang {
|
||||
namespace ast_matchers {
|
||||
namespace internal {
|
||||
|
||||
BoundNodesTree::BoundNodesTree() {}
|
||||
|
||||
BoundNodesTree::BoundNodesTree(
|
||||
const std::map<std::string, const clang::Decl*>& DeclBindings,
|
||||
const std::map<std::string, const clang::Stmt*>& StmtBindings,
|
||||
const std::vector<BoundNodesTree> RecursiveBindings)
|
||||
: DeclBindings(DeclBindings), StmtBindings(StmtBindings),
|
||||
RecursiveBindings(RecursiveBindings) {}
|
||||
|
||||
void BoundNodesTree::copyTo(BoundNodesTreeBuilder* Builder) const {
|
||||
copyBindingsTo(DeclBindings, Builder);
|
||||
copyBindingsTo(StmtBindings, Builder);
|
||||
for (std::vector<BoundNodesTree>::const_iterator
|
||||
I = RecursiveBindings.begin(),
|
||||
E = RecursiveBindings.end();
|
||||
I != E; ++I) {
|
||||
Builder->addMatch(*I);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void BoundNodesTree::copyBindingsTo(
|
||||
const T& Bindings, BoundNodesTreeBuilder* Builder) const {
|
||||
for (typename T::const_iterator I = Bindings.begin(),
|
||||
E = Bindings.end();
|
||||
I != E; ++I) {
|
||||
Builder->setBinding(*I);
|
||||
}
|
||||
}
|
||||
|
||||
void BoundNodesTree::visitMatches(Visitor* ResultVisitor) {
|
||||
std::map<std::string, const clang::Decl*> AggregatedDeclBindings;
|
||||
std::map<std::string, const clang::Stmt*> AggregatedStmtBindings;
|
||||
visitMatchesRecursively(ResultVisitor, AggregatedDeclBindings,
|
||||
AggregatedStmtBindings);
|
||||
}
|
||||
|
||||
void BoundNodesTree::
|
||||
visitMatchesRecursively(Visitor* ResultVisitor,
|
||||
std::map<std::string, const clang::Decl*>
|
||||
AggregatedDeclBindings,
|
||||
std::map<std::string, const clang::Stmt*>
|
||||
AggregatedStmtBindings) {
|
||||
copy(DeclBindings.begin(), DeclBindings.end(),
|
||||
inserter(AggregatedDeclBindings, AggregatedDeclBindings.begin()));
|
||||
copy(StmtBindings.begin(), StmtBindings.end(),
|
||||
inserter(AggregatedStmtBindings, AggregatedStmtBindings.begin()));
|
||||
if (RecursiveBindings.empty()) {
|
||||
ResultVisitor->visitMatch(BoundNodes(AggregatedDeclBindings,
|
||||
AggregatedStmtBindings));
|
||||
} else {
|
||||
for (unsigned I = 0; I < RecursiveBindings.size(); ++I) {
|
||||
RecursiveBindings[I].visitMatchesRecursively(ResultVisitor,
|
||||
AggregatedDeclBindings,
|
||||
AggregatedStmtBindings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BoundNodesTreeBuilder::BoundNodesTreeBuilder() {}
|
||||
|
||||
void BoundNodesTreeBuilder::
|
||||
setBinding(const std::pair<const std::string, const clang::Decl*>& Binding) {
|
||||
DeclBindings.insert(Binding);
|
||||
}
|
||||
|
||||
void BoundNodesTreeBuilder::
|
||||
setBinding(const std::pair<const std::string, const clang::Stmt*>& Binding) {
|
||||
StmtBindings.insert(Binding);
|
||||
}
|
||||
|
||||
void BoundNodesTreeBuilder::addMatch(const BoundNodesTree& Bindings) {
|
||||
RecursiveBindings.push_back(Bindings);
|
||||
}
|
||||
|
||||
BoundNodesTree BoundNodesTreeBuilder::build() const {
|
||||
return BoundNodesTree(DeclBindings, StmtBindings, RecursiveBindings);
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace ast_matchers
|
||||
} // end namespace clang
|
|
@ -0,0 +1,7 @@
|
|||
set(LLVM_LINK_COMPONENTS support)
|
||||
set(LLVM_USED_LIBS clangBasic clangAST)
|
||||
|
||||
add_clang_library(clangASTMatchers
|
||||
ASTMatchFinder.cpp
|
||||
ASTMatchersInternal.cpp
|
||||
)
|
|
@ -0,0 +1,15 @@
|
|||
##===- clang/lib/ASTMatchers/Makefile ----------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
CLANG_LEVEL := ../..
|
||||
LIBRARYNAME := clangASTMatchers
|
||||
|
||||
PARALLEL_DIRS = Dynamic
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
|
@ -3,6 +3,7 @@ add_subdirectory(Basic)
|
|||
add_subdirectory(Lex)
|
||||
add_subdirectory(Parse)
|
||||
add_subdirectory(AST)
|
||||
add_subdirectory(ASTMatchers)
|
||||
add_subdirectory(Sema)
|
||||
add_subdirectory(CodeGen)
|
||||
add_subdirectory(Analysis)
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
##===----------------------------------------------------------------------===##
|
||||
CLANG_LEVEL := ..
|
||||
|
||||
PARALLEL_DIRS = Headers Basic Lex Parse AST Sema CodeGen Analysis \
|
||||
PARALLEL_DIRS = Headers Basic Lex Parse AST ASTMatchers Sema CodeGen Analysis \
|
||||
StaticAnalyzer Edit Rewrite ARCMigrate Serialization Frontend \
|
||||
FrontendTool Tooling Driver
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,128 @@
|
|||
//===- unittest/Tooling/ASTMatchersTest.h - Matcher tests helpers ------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_UNITTESTS_AST_MATCHERS_AST_MATCHERS_TEST_H
|
||||
#define LLVM_CLANG_UNITTESTS_AST_MATCHERS_AST_MATCHERS_TEST_H
|
||||
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace clang {
|
||||
namespace ast_matchers {
|
||||
|
||||
using clang::tooling::newFrontendActionFactory;
|
||||
using clang::tooling::runToolOnCode;
|
||||
using clang::tooling::FrontendActionFactory;
|
||||
|
||||
class BoundNodesCallback {
|
||||
public:
|
||||
virtual ~BoundNodesCallback() {}
|
||||
virtual bool run(const BoundNodes *BoundNodes) = 0;
|
||||
};
|
||||
|
||||
// If 'FindResultVerifier' is not NULL, sets *Verified to the result of
|
||||
// running 'FindResultVerifier' with the bound nodes as argument.
|
||||
// If 'FindResultVerifier' is NULL, sets *Verified to true when Run is called.
|
||||
class VerifyMatch : public MatchFinder::MatchCallback {
|
||||
public:
|
||||
VerifyMatch(BoundNodesCallback *FindResultVerifier, bool *Verified)
|
||||
: Verified(Verified), FindResultReviewer(FindResultVerifier) {}
|
||||
|
||||
virtual void run(const MatchFinder::MatchResult &Result) {
|
||||
if (FindResultReviewer != NULL) {
|
||||
*Verified = FindResultReviewer->run(&Result.Nodes);
|
||||
} else {
|
||||
*Verified = true;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool *const Verified;
|
||||
BoundNodesCallback *const FindResultReviewer;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
testing::AssertionResult matchesConditionally(const std::string &Code,
|
||||
const T &AMatcher,
|
||||
bool ExpectMatch) {
|
||||
bool Found = false;
|
||||
MatchFinder Finder;
|
||||
Finder.addMatcher(AMatcher, new VerifyMatch(0, &Found));
|
||||
OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
|
||||
if (!runToolOnCode(Factory->create(), Code)) {
|
||||
return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
|
||||
}
|
||||
if (!Found && ExpectMatch) {
|
||||
return testing::AssertionFailure()
|
||||
<< "Could not find match in \"" << Code << "\"";
|
||||
} else if (Found && !ExpectMatch) {
|
||||
return testing::AssertionFailure()
|
||||
<< "Found unexpected match in \"" << Code << "\"";
|
||||
}
|
||||
return testing::AssertionSuccess();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
testing::AssertionResult matches(const std::string &Code, const T &AMatcher) {
|
||||
return matchesConditionally(Code, AMatcher, true);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
testing::AssertionResult notMatches(const std::string &Code,
|
||||
const T &AMatcher) {
|
||||
return matchesConditionally(Code, AMatcher, false);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
testing::AssertionResult
|
||||
matchAndVerifyResultConditionally(const std::string &Code, const T &AMatcher,
|
||||
BoundNodesCallback *FindResultVerifier,
|
||||
bool ExpectResult) {
|
||||
llvm::OwningPtr<BoundNodesCallback> ScopedVerifier(FindResultVerifier);
|
||||
bool VerifiedResult = false;
|
||||
MatchFinder Finder;
|
||||
Finder.addMatcher(
|
||||
AMatcher, new VerifyMatch(FindResultVerifier, &VerifiedResult));
|
||||
OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
|
||||
if (!runToolOnCode(Factory->create(), Code)) {
|
||||
return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
|
||||
}
|
||||
if (!VerifiedResult && ExpectResult) {
|
||||
return testing::AssertionFailure()
|
||||
<< "Could not verify result in \"" << Code << "\"";
|
||||
} else if (VerifiedResult && !ExpectResult) {
|
||||
return testing::AssertionFailure()
|
||||
<< "Verified unexpected result in \"" << Code << "\"";
|
||||
}
|
||||
return testing::AssertionSuccess();
|
||||
}
|
||||
|
||||
// FIXME: Find better names for these functions (or document what they
|
||||
// do more precisely).
|
||||
template <typename T>
|
||||
testing::AssertionResult
|
||||
matchAndVerifyResultTrue(const std::string &Code, const T &AMatcher,
|
||||
BoundNodesCallback *FindResultVerifier) {
|
||||
return matchAndVerifyResultConditionally(
|
||||
Code, AMatcher, FindResultVerifier, true);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
testing::AssertionResult
|
||||
matchAndVerifyResultFalse(const std::string &Code, const T &AMatcher,
|
||||
BoundNodesCallback *FindResultVerifier) {
|
||||
return matchAndVerifyResultConditionally(
|
||||
Code, AMatcher, FindResultVerifier, false);
|
||||
}
|
||||
|
||||
} // end namespace ast_matchers
|
||||
} // end namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_UNITTESTS_AST_MATCHERS_AST_MATCHERS_TEST_H
|
|
@ -0,0 +1,5 @@
|
|||
add_clang_unittest(ASTMatchersTests
|
||||
ASTMatchersTest.cpp)
|
||||
|
||||
target_link_libraries(ASTMatchersTests
|
||||
gtest gtest_main clangASTMatchers clangTooling)
|
|
@ -0,0 +1,19 @@
|
|||
##===- unittests/ASTMatchers/Makefile ----------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
CLANG_LEVEL = ../..
|
||||
PARALLEL_DIRS = Dynamic
|
||||
|
||||
TESTNAME = ASTMatchers
|
||||
LINK_COMPONENTS := support mc
|
||||
USEDLIBS = clangEdit.a clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
|
||||
clangRewrite.a clangParse.a clangSema.a clangAnalysis.a \
|
||||
clangAST.a clangASTMatchers.a clangLex.a clangBasic.a
|
||||
|
||||
include $(CLANG_LEVEL)/unittests/Makefile
|
|
@ -9,6 +9,7 @@ function(add_clang_unittest test_dirname)
|
|||
add_unittest(ClangUnitTests ${test_dirname} ${ARGN})
|
||||
endfunction()
|
||||
|
||||
add_subdirectory(ASTMatchers)
|
||||
add_subdirectory(Basic)
|
||||
add_subdirectory(Lex)
|
||||
add_subdirectory(Frontend)
|
||||
|
|
|
@ -14,7 +14,7 @@ ifndef CLANG_LEVEL
|
|||
|
||||
IS_UNITTEST_LEVEL := 1
|
||||
CLANG_LEVEL := ..
|
||||
PARALLEL_DIRS = Basic AST Frontend Lex Tooling
|
||||
PARALLEL_DIRS = ASTMatchers Basic AST Frontend Lex Tooling
|
||||
|
||||
endif # CLANG_LEVEL
|
||||
|
||||
|
|
Loading…
Reference in New Issue