mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-23 20:01:24 +00:00
Add more matchers and do cleanups.
Reviewers: klimek Differential Revision: http://ec2-50-18-127-156.us-west-1.compute.amazonaws.com/D2 llvm-svn: 160013
This commit is contained in:
parent
8b95df290e
commit
1dad183b38
File diff suppressed because it is too large
Load Diff
@ -84,8 +84,8 @@ public:
|
||||
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,
|
||||
BoundNodesTree(const std::map<std::string, const Decl*>& DeclBindings,
|
||||
const std::map<std::string, const Stmt*>& StmtBindings,
|
||||
const std::vector<BoundNodesTree> RecursiveBindings);
|
||||
|
||||
/// \brief Adds all bound nodes to bound_nodes_builder.
|
||||
@ -99,8 +99,8 @@ public:
|
||||
private:
|
||||
void visitMatchesRecursively(
|
||||
Visitor* ResultVistior,
|
||||
std::map<std::string, const clang::Decl*> DeclBindings,
|
||||
std::map<std::string, const clang::Stmt*> StmtBindings);
|
||||
std::map<std::string, const Decl*> DeclBindings,
|
||||
std::map<std::string, const Stmt*> StmtBindings);
|
||||
|
||||
template <typename T>
|
||||
void copyBindingsTo(const T& bindings, BoundNodesTreeBuilder* Builder) const;
|
||||
@ -108,8 +108,8 @@ private:
|
||||
// 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::map<std::string, const Decl*> DeclBindings;
|
||||
std::map<std::string, const Stmt*> StmtBindings;
|
||||
|
||||
std::vector<BoundNodesTree> RecursiveBindings;
|
||||
};
|
||||
@ -126,10 +126,8 @@ public:
|
||||
///
|
||||
/// 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);
|
||||
void setBinding(const std::string &Id, const Decl *Node);
|
||||
void setBinding(const std::string &Id, const Stmt *Node);
|
||||
/// @}
|
||||
|
||||
/// \brief Adds a branch in the tree.
|
||||
@ -142,8 +140,8 @@ 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::map<std::string, const Decl*> DeclBindings;
|
||||
std::map<std::string, const Stmt*> StmtBindings;
|
||||
|
||||
std::vector<BoundNodesTree> RecursiveBindings;
|
||||
};
|
||||
@ -262,10 +260,10 @@ inline Matcher<T> makeMatcher(MatcherInterface<T> *Implementation) {
|
||||
template <typename T, typename DeclMatcherT>
|
||||
class HasDeclarationMatcher : public MatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT((llvm::is_same< DeclMatcherT,
|
||||
Matcher<clang::Decl> >::value),
|
||||
Matcher<Decl> >::value),
|
||||
instantiated_with_wrong_types);
|
||||
public:
|
||||
explicit HasDeclarationMatcher(const Matcher<clang::Decl> &InnerMatcher)
|
||||
explicit HasDeclarationMatcher(const Matcher<Decl> &InnerMatcher)
|
||||
: InnerMatcher(InnerMatcher) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
@ -277,34 +275,36 @@ public:
|
||||
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,
|
||||
bool matchesSpecialized(const QualType &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
/// FIXME: Add other ways to convert...
|
||||
clang::CXXRecordDecl *NodeAsRecordDecl = Node->getAsCXXRecordDecl();
|
||||
if (Node.isNull())
|
||||
return false;
|
||||
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,
|
||||
bool matchesSpecialized(const CallExpr &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
const clang::Decl *NodeAsDecl = Node.getCalleeDecl();
|
||||
const 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,
|
||||
bool matchesSpecialized(const CXXConstructExpr &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
const clang::Decl *NodeAsDecl = Node.getConstructor();
|
||||
const Decl *NodeAsDecl = Node.getConstructor();
|
||||
return NodeAsDecl != NULL &&
|
||||
InnerMatcher.matches(*NodeAsDecl, Finder, Builder);
|
||||
}
|
||||
|
||||
const Matcher<clang::Decl> InnerMatcher;
|
||||
const Matcher<Decl> InnerMatcher;
|
||||
};
|
||||
|
||||
/// \brief IsBaseType<T>::value is true if T is a "base" type in the AST
|
||||
@ -312,10 +312,10 @@ private:
|
||||
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);
|
||||
(llvm::is_same<T, Decl>::value ||
|
||||
llvm::is_same<T, Stmt>::value ||
|
||||
llvm::is_same<T, QualType>::value ||
|
||||
llvm::is_same<T, CXXCtorInitializer>::value);
|
||||
};
|
||||
template <typename T>
|
||||
const bool IsBaseType<T>::value;
|
||||
@ -326,19 +326,19 @@ class UntypedBaseMatcher : public llvm::RefCountedBaseVPTR {
|
||||
public:
|
||||
virtual ~UntypedBaseMatcher() {}
|
||||
|
||||
virtual bool matches(const clang::Decl &DeclNode, ASTMatchFinder *Finder,
|
||||
virtual bool matches(const Decl &DeclNode, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return false;
|
||||
}
|
||||
virtual bool matches(const clang::QualType &TypeNode, ASTMatchFinder *Finder,
|
||||
virtual bool matches(const QualType &TypeNode, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return false;
|
||||
}
|
||||
virtual bool matches(const clang::Stmt &StmtNode, ASTMatchFinder *Finder,
|
||||
virtual bool matches(const Stmt &StmtNode, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return false;
|
||||
}
|
||||
virtual bool matches(const clang::CXXCtorInitializer &CtorInitNode,
|
||||
virtual bool matches(const CXXCtorInitializer &CtorInitNode,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return false;
|
||||
@ -414,26 +414,26 @@ public:
|
||||
/// 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,
|
||||
virtual bool classIsDerivedFrom(const CXXRecordDecl *Declaration,
|
||||
StringRef BaseName) const = 0;
|
||||
|
||||
// FIXME: Implement for other base nodes.
|
||||
virtual bool matchesChildOf(const clang::Decl &DeclNode,
|
||||
virtual bool matchesChildOf(const Decl &DeclNode,
|
||||
const UntypedBaseMatcher &BaseMatcher,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
TraversalKind Traverse,
|
||||
BindKind Bind) = 0;
|
||||
virtual bool matchesChildOf(const clang::Stmt &StmtNode,
|
||||
virtual bool matchesChildOf(const Stmt &StmtNode,
|
||||
const UntypedBaseMatcher &BaseMatcher,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
TraversalKind Traverse,
|
||||
BindKind Bind) = 0;
|
||||
|
||||
virtual bool matchesDescendantOf(const clang::Decl &DeclNode,
|
||||
virtual bool matchesDescendantOf(const Decl &DeclNode,
|
||||
const UntypedBaseMatcher &BaseMatcher,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
BindKind Bind) = 0;
|
||||
virtual bool matchesDescendantOf(const clang::Stmt &StmtNode,
|
||||
virtual bool matchesDescendantOf(const Stmt &StmtNode,
|
||||
const UntypedBaseMatcher &BaseMatcher,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
BindKind Bind) = 0;
|
||||
@ -566,17 +566,17 @@ private:
|
||||
const Matcher<To> InnerMatcher;
|
||||
};
|
||||
|
||||
/// \brief Enables the user to pass a Matcher<clang::CXXMemberCallExpr> to
|
||||
/// \brief Enables the user to pass a Matcher<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 {
|
||||
inline Matcher<CXXMemberCallExpr>::
|
||||
operator Matcher<CallExpr>() const {
|
||||
return makeMatcher(
|
||||
new DynCastMatcher<clang::CallExpr, clang::CXXMemberCallExpr>(*this));
|
||||
new DynCastMatcher<CallExpr, CXXMemberCallExpr>(*this));
|
||||
}
|
||||
|
||||
/// \brief Matcher<T> that wraps an inner Matcher<T> and binds the matched node
|
||||
@ -594,7 +594,7 @@ public:
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
bool Result = InnerMatcher.matches(Node, Finder, Builder);
|
||||
if (Result) {
|
||||
Builder->setBinding(std::pair<const std::string, const T*>(ID, &Node));
|
||||
Builder->setBinding(ID, &Node);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
@ -795,11 +795,11 @@ private:
|
||||
/// 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,
|
||||
TOOLING_COMPILE_ASSERT((llvm::is_base_of<CharacterLiteral, T>::value ||
|
||||
llvm::is_base_of<CXXBoolLiteralExpr,
|
||||
T>::value ||
|
||||
llvm::is_base_of<clang::FloatingLiteral, T>::value ||
|
||||
llvm::is_base_of<clang::IntegerLiteral, T>::value),
|
||||
llvm::is_base_of<FloatingLiteral, T>::value ||
|
||||
llvm::is_base_of<IntegerLiteral, T>::value),
|
||||
the_node_must_have_a_getValue_method);
|
||||
public:
|
||||
explicit ValueEqualsMatcher(const ValueT &ExpectedValue)
|
||||
@ -816,9 +816,9 @@ private:
|
||||
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),
|
||||
(llvm::is_base_of<TagDecl, T>::value) ||
|
||||
(llvm::is_base_of<VarDecl, T>::value) ||
|
||||
(llvm::is_base_of<FunctionDecl, T>::value),
|
||||
is_definition_requires_isThisDeclarationADefinition_method);
|
||||
public:
|
||||
virtual bool matchesNode(const T &Node) const {
|
||||
@ -830,32 +830,32 @@ public:
|
||||
/// 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),
|
||||
TOOLING_COMPILE_ASSERT((llvm::is_base_of<FunctionDecl, T>::value) ||
|
||||
(llvm::is_base_of<VarDecl, T>::value) ||
|
||||
(llvm::is_base_of<CXXRecordDecl, T>::value),
|
||||
requires_getTemplateSpecializationKind_method);
|
||||
public:
|
||||
virtual bool matches(const T& Node,
|
||||
ASTMatchFinder* Finder,
|
||||
BoundNodesTreeBuilder* Builder) const {
|
||||
return (Node.getTemplateSpecializationKind() ==
|
||||
clang::TSK_ImplicitInstantiation ||
|
||||
TSK_ImplicitInstantiation ||
|
||||
Node.getTemplateSpecializationKind() ==
|
||||
clang::TSK_ExplicitInstantiationDefinition);
|
||||
TSK_ExplicitInstantiationDefinition);
|
||||
}
|
||||
};
|
||||
|
||||
class IsArrowMatcher : public SingleNodeMatcherInterface<clang::MemberExpr> {
|
||||
class IsArrowMatcher : public SingleNodeMatcherInterface<MemberExpr> {
|
||||
public:
|
||||
virtual bool matchesNode(const clang::MemberExpr &Node) const {
|
||||
virtual bool matchesNode(const MemberExpr &Node) const {
|
||||
return Node.isArrow();
|
||||
}
|
||||
};
|
||||
|
||||
class IsConstQualifiedMatcher
|
||||
: public SingleNodeMatcherInterface<clang::QualType> {
|
||||
: public SingleNodeMatcherInterface<QualType> {
|
||||
public:
|
||||
virtual bool matchesNode(const clang::QualType& Node) const {
|
||||
virtual bool matchesNode(const QualType& Node) const {
|
||||
return Node.isConstQualified();
|
||||
}
|
||||
};
|
||||
@ -867,11 +867,11 @@ class IsConstQualifiedMatcher
|
||||
///
|
||||
/// 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.
|
||||
/// Decl, CXXRecordDecl> record;
|
||||
/// Creates a functor record(...) that creates a Matcher<Decl> given
|
||||
/// a variable number of arguments of type Matcher<CXXRecordDecl>.
|
||||
/// The returned matcher matches if the given Decl can by dynamically
|
||||
/// casted to CXXRecordDecl and all given matchers match.
|
||||
template <typename SourceT, typename TargetT>
|
||||
class VariadicDynCastAllOfMatcher
|
||||
: public llvm::VariadicFunction<
|
||||
|
@ -51,9 +51,9 @@ struct MemoizedMatchResult {
|
||||
// A RecursiveASTVisitor that traverses all children or all descendants of
|
||||
// a node.
|
||||
class MatchChildASTVisitor
|
||||
: public clang::RecursiveASTVisitor<MatchChildASTVisitor> {
|
||||
: public RecursiveASTVisitor<MatchChildASTVisitor> {
|
||||
public:
|
||||
typedef clang::RecursiveASTVisitor<MatchChildASTVisitor> VisitorBase;
|
||||
typedef 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
|
||||
@ -95,21 +95,21 @@ public:
|
||||
// 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) {
|
||||
bool TraverseDecl(Decl *DeclNode) {
|
||||
return (DeclNode == NULL) || traverse(*DeclNode);
|
||||
}
|
||||
bool TraverseStmt(clang::Stmt *StmtNode) {
|
||||
const clang::Stmt *StmtToTraverse = StmtNode;
|
||||
bool TraverseStmt(Stmt *StmtNode) {
|
||||
const Stmt *StmtToTraverse = StmtNode;
|
||||
if (Traversal ==
|
||||
ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses) {
|
||||
const clang::Expr *ExprNode = dyn_cast_or_null<clang::Expr>(StmtNode);
|
||||
const Expr *ExprNode = dyn_cast_or_null<Expr>(StmtNode);
|
||||
if (ExprNode != NULL) {
|
||||
StmtToTraverse = ExprNode->IgnoreParenImpCasts();
|
||||
}
|
||||
}
|
||||
return (StmtToTraverse == NULL) || traverse(*StmtToTraverse);
|
||||
}
|
||||
bool TraverseType(clang::QualType TypeNode) {
|
||||
bool TraverseType(QualType TypeNode) {
|
||||
return traverse(TypeNode);
|
||||
}
|
||||
|
||||
@ -134,13 +134,13 @@ private:
|
||||
|
||||
// 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 Decl &DeclNode) {
|
||||
return VisitorBase::TraverseDecl(const_cast<Decl*>(&DeclNode));
|
||||
}
|
||||
bool baseTraverse(const clang::Stmt &StmtNode) {
|
||||
return VisitorBase::TraverseStmt(const_cast<clang::Stmt*>(&StmtNode));
|
||||
bool baseTraverse(const Stmt &StmtNode) {
|
||||
return VisitorBase::TraverseStmt(const_cast<Stmt*>(&StmtNode));
|
||||
}
|
||||
bool baseTraverse(clang::QualType TypeNode) {
|
||||
bool baseTraverse(QualType TypeNode) {
|
||||
return VisitorBase::TraverseType(TypeNode);
|
||||
}
|
||||
|
||||
@ -197,7 +197,7 @@ private:
|
||||
|
||||
// Controls the outermost traversal of the AST and allows to match multiple
|
||||
// matchers.
|
||||
class MatchASTVisitor : public clang::RecursiveASTVisitor<MatchASTVisitor>,
|
||||
class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>,
|
||||
public ASTMatchFinder {
|
||||
public:
|
||||
MatchASTVisitor(std::vector< std::pair<const UntypedBaseMatcher*,
|
||||
@ -206,14 +206,14 @@ public:
|
||||
ActiveASTContext(NULL) {
|
||||
}
|
||||
|
||||
void set_active_ast_context(clang::ASTContext *NewActiveASTContext) {
|
||||
void set_active_ast_context(ASTContext *NewActiveASTContext) {
|
||||
ActiveASTContext = NewActiveASTContext;
|
||||
}
|
||||
|
||||
// The following Visit*() and Traverse*() functions "override"
|
||||
// methods in RecursiveASTVisitor.
|
||||
|
||||
bool VisitTypedefDecl(clang::TypedefDecl *DeclNode) {
|
||||
bool VisitTypedefDecl(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
|
||||
@ -241,18 +241,18 @@ public:
|
||||
// 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
|
||||
const Type *TypeNode = DeclNode->getUnderlyingType().getTypePtr();
|
||||
const 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);
|
||||
bool TraverseDecl(Decl *DeclNode);
|
||||
bool TraverseStmt(Stmt *StmtNode);
|
||||
bool TraverseType(QualType TypeNode);
|
||||
bool TraverseTypeLoc(TypeLoc TypeNode);
|
||||
|
||||
// Matches children or descendants of 'Node' with 'BaseMatcher'.
|
||||
template <typename T>
|
||||
@ -260,8 +260,8 @@ public:
|
||||
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),
|
||||
TOOLING_COMPILE_ASSERT((llvm::is_same<T, Decl>::value) ||
|
||||
(llvm::is_same<T, Stmt>::value),
|
||||
type_does_not_support_memoization);
|
||||
const UntypedMatchInput input(BaseMatcher.getID(), &Node);
|
||||
std::pair<MemoizationMap::iterator, bool> InsertResult
|
||||
@ -288,11 +288,11 @@ public:
|
||||
return Visitor.findMatch(Node);
|
||||
}
|
||||
|
||||
virtual bool classIsDerivedFrom(const clang::CXXRecordDecl *Declaration,
|
||||
virtual bool classIsDerivedFrom(const CXXRecordDecl *Declaration,
|
||||
StringRef BaseName) const;
|
||||
|
||||
// Implements ASTMatchFinder::MatchesChildOf.
|
||||
virtual bool matchesChildOf(const clang::Decl &DeclNode,
|
||||
virtual bool matchesChildOf(const Decl &DeclNode,
|
||||
const UntypedBaseMatcher &BaseMatcher,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
TraversalKind Traversal,
|
||||
@ -300,7 +300,7 @@ public:
|
||||
return matchesRecursively(DeclNode, BaseMatcher, Builder, 1, Traversal,
|
||||
Bind);
|
||||
}
|
||||
virtual bool matchesChildOf(const clang::Stmt &StmtNode,
|
||||
virtual bool matchesChildOf(const Stmt &StmtNode,
|
||||
const UntypedBaseMatcher &BaseMatcher,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
TraversalKind Traversal,
|
||||
@ -310,14 +310,14 @@ public:
|
||||
}
|
||||
|
||||
// Implements ASTMatchFinder::MatchesDescendantOf.
|
||||
virtual bool matchesDescendantOf(const clang::Decl &DeclNode,
|
||||
virtual bool matchesDescendantOf(const 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,
|
||||
virtual bool matchesDescendantOf(const Stmt &StmtNode,
|
||||
const UntypedBaseMatcher &BaseMatcher,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
BindKind Bind) {
|
||||
@ -333,7 +333,7 @@ private:
|
||||
// the aggregated bound nodes for each match.
|
||||
class MatchVisitor : public BoundNodesTree::Visitor {
|
||||
public:
|
||||
MatchVisitor(clang::ASTContext* Context,
|
||||
MatchVisitor(ASTContext* Context,
|
||||
MatchFinder::MatchCallback* Callback)
|
||||
: Context(Context),
|
||||
Callback(Callback) {}
|
||||
@ -343,16 +343,16 @@ private:
|
||||
}
|
||||
|
||||
private:
|
||||
clang::ASTContext* Context;
|
||||
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,
|
||||
bool typeHasAlias(const Type *TypeNode,
|
||||
StringRef Name) const {
|
||||
const clang::Type *const CanonicalType =
|
||||
const Type *const CanonicalType =
|
||||
ActiveASTContext->getCanonicalType(TypeNode);
|
||||
const std::set<std::string> *UnqualifiedAlias =
|
||||
find(TypeToUnqualifiedAliases, CanonicalType);
|
||||
@ -378,10 +378,10 @@ private:
|
||||
|
||||
std::vector< std::pair<const UntypedBaseMatcher*,
|
||||
MatchFinder::MatchCallback*> > *const Triggers;
|
||||
clang::ASTContext *ActiveASTContext;
|
||||
ASTContext *ActiveASTContext;
|
||||
|
||||
// Maps a canonical type to the names of its typedefs.
|
||||
llvm::DenseMap<const clang::Type*, std::set<std::string> >
|
||||
llvm::DenseMap<const Type*, std::set<std::string> >
|
||||
TypeToUnqualifiedAliases;
|
||||
|
||||
// Maps (matcher, node) -> the match result for memoization.
|
||||
@ -393,7 +393,7 @@ private:
|
||||
// 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,
|
||||
MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
|
||||
StringRef BaseName) const {
|
||||
if (Declaration->getName() == BaseName) {
|
||||
return true;
|
||||
@ -401,24 +401,24 @@ MatchASTVisitor::classIsDerivedFrom(const clang::CXXRecordDecl *Declaration,
|
||||
if (!Declaration->hasDefinition()) {
|
||||
return false;
|
||||
}
|
||||
typedef clang::CXXRecordDecl::base_class_const_iterator BaseIterator;
|
||||
typedef 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();
|
||||
const 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) {
|
||||
// Type::getAs<...>() drills through typedefs.
|
||||
if (TypeNode->getAs<DependentNameType>() != NULL ||
|
||||
TypeNode->getAs<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>();
|
||||
CXXRecordDecl *ClassDecl = NULL;
|
||||
TemplateSpecializationType const *TemplateType =
|
||||
TypeNode->getAs<TemplateSpecializationType>();
|
||||
if (TemplateType != NULL) {
|
||||
if (TemplateType->getTemplateName().isDependent()) {
|
||||
// Dependent template specializations will be matched when the
|
||||
@ -434,12 +434,12 @@ MatchASTVisitor::classIsDerivedFrom(const clang::CXXRecordDecl *Declaration,
|
||||
// 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 =
|
||||
CXXRecordDecl *SpecializationDecl =
|
||||
TemplateType->getAsCXXRecordDecl();
|
||||
if (SpecializationDecl != NULL) {
|
||||
ClassDecl = SpecializationDecl;
|
||||
} else {
|
||||
ClassDecl = llvm::dyn_cast<clang::CXXRecordDecl>(
|
||||
ClassDecl = llvm::dyn_cast<CXXRecordDecl>(
|
||||
TemplateType->getTemplateName()
|
||||
.getAsTemplateDecl()->getTemplatedDecl());
|
||||
}
|
||||
@ -455,33 +455,33 @@ MatchASTVisitor::classIsDerivedFrom(const clang::CXXRecordDecl *Declaration,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MatchASTVisitor::TraverseDecl(clang::Decl *DeclNode) {
|
||||
bool MatchASTVisitor::TraverseDecl(Decl *DeclNode) {
|
||||
if (DeclNode == NULL) {
|
||||
return true;
|
||||
}
|
||||
match(*DeclNode);
|
||||
return clang::RecursiveASTVisitor<MatchASTVisitor>::TraverseDecl(DeclNode);
|
||||
return RecursiveASTVisitor<MatchASTVisitor>::TraverseDecl(DeclNode);
|
||||
}
|
||||
|
||||
bool MatchASTVisitor::TraverseStmt(clang::Stmt *StmtNode) {
|
||||
bool MatchASTVisitor::TraverseStmt(Stmt *StmtNode) {
|
||||
if (StmtNode == NULL) {
|
||||
return true;
|
||||
}
|
||||
match(*StmtNode);
|
||||
return clang::RecursiveASTVisitor<MatchASTVisitor>::TraverseStmt(StmtNode);
|
||||
return RecursiveASTVisitor<MatchASTVisitor>::TraverseStmt(StmtNode);
|
||||
}
|
||||
|
||||
bool MatchASTVisitor::TraverseType(clang::QualType TypeNode) {
|
||||
bool MatchASTVisitor::TraverseType(QualType TypeNode) {
|
||||
match(TypeNode);
|
||||
return clang::RecursiveASTVisitor<MatchASTVisitor>::TraverseType(TypeNode);
|
||||
return RecursiveASTVisitor<MatchASTVisitor>::TraverseType(TypeNode);
|
||||
}
|
||||
|
||||
bool MatchASTVisitor::TraverseTypeLoc(clang::TypeLoc TypeLoc) {
|
||||
return clang::RecursiveASTVisitor<MatchASTVisitor>::
|
||||
bool MatchASTVisitor::TraverseTypeLoc(TypeLoc TypeLoc) {
|
||||
return RecursiveASTVisitor<MatchASTVisitor>::
|
||||
TraverseType(TypeLoc.getType());
|
||||
}
|
||||
|
||||
class MatchASTConsumer : public clang::ASTConsumer {
|
||||
class MatchASTConsumer : public ASTConsumer {
|
||||
public:
|
||||
MatchASTConsumer(std::vector< std::pair<const UntypedBaseMatcher*,
|
||||
MatchFinder::MatchCallback*> > *Triggers,
|
||||
@ -490,7 +490,7 @@ public:
|
||||
ParsingDone(ParsingDone) {}
|
||||
|
||||
private:
|
||||
virtual void HandleTranslationUnit(clang::ASTContext &Context) {
|
||||
virtual void HandleTranslationUnit(ASTContext &Context) {
|
||||
if (ParsingDone != NULL) {
|
||||
ParsingDone->run();
|
||||
}
|
||||
@ -507,7 +507,7 @@ private:
|
||||
} // end namespace internal
|
||||
|
||||
MatchFinder::MatchResult::MatchResult(const BoundNodes &Nodes,
|
||||
clang::ASTContext *Context)
|
||||
ASTContext *Context)
|
||||
: Nodes(Nodes), Context(Context),
|
||||
SourceManager(&Context->getSourceManager()) {}
|
||||
|
||||
@ -528,22 +528,22 @@ MatchFinder::~MatchFinder() {
|
||||
void MatchFinder::addMatcher(const DeclarationMatcher &NodeMatch,
|
||||
MatchCallback *Action) {
|
||||
Triggers.push_back(std::make_pair(
|
||||
new internal::TypedBaseMatcher<clang::Decl>(NodeMatch), Action));
|
||||
new internal::TypedBaseMatcher<Decl>(NodeMatch), Action));
|
||||
}
|
||||
|
||||
void MatchFinder::addMatcher(const TypeMatcher &NodeMatch,
|
||||
MatchCallback *Action) {
|
||||
Triggers.push_back(std::make_pair(
|
||||
new internal::TypedBaseMatcher<clang::QualType>(NodeMatch), Action));
|
||||
new internal::TypedBaseMatcher<QualType>(NodeMatch), Action));
|
||||
}
|
||||
|
||||
void MatchFinder::addMatcher(const StatementMatcher &NodeMatch,
|
||||
MatchCallback *Action) {
|
||||
Triggers.push_back(std::make_pair(
|
||||
new internal::TypedBaseMatcher<clang::Stmt>(NodeMatch), Action));
|
||||
new internal::TypedBaseMatcher<Stmt>(NodeMatch), Action));
|
||||
}
|
||||
|
||||
clang::ASTConsumer *MatchFinder::newASTConsumer() {
|
||||
ASTConsumer *MatchFinder::newASTConsumer() {
|
||||
return new internal::MatchASTConsumer(&Triggers, ParsingDone);
|
||||
}
|
||||
|
||||
|
@ -21,8 +21,8 @@ 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::map<std::string, const Decl*>& DeclBindings,
|
||||
const std::map<std::string, const Stmt*>& StmtBindings,
|
||||
const std::vector<BoundNodesTree> RecursiveBindings)
|
||||
: DeclBindings(DeclBindings), StmtBindings(StmtBindings),
|
||||
RecursiveBindings(RecursiveBindings) {}
|
||||
@ -44,22 +44,22 @@ void BoundNodesTree::copyBindingsTo(
|
||||
for (typename T::const_iterator I = Bindings.begin(),
|
||||
E = Bindings.end();
|
||||
I != E; ++I) {
|
||||
Builder->setBinding(*I);
|
||||
Builder->setBinding(I->first, I->second);
|
||||
}
|
||||
}
|
||||
|
||||
void BoundNodesTree::visitMatches(Visitor* ResultVisitor) {
|
||||
std::map<std::string, const clang::Decl*> AggregatedDeclBindings;
|
||||
std::map<std::string, const clang::Stmt*> AggregatedStmtBindings;
|
||||
std::map<std::string, const Decl*> AggregatedDeclBindings;
|
||||
std::map<std::string, const Stmt*> AggregatedStmtBindings;
|
||||
visitMatchesRecursively(ResultVisitor, AggregatedDeclBindings,
|
||||
AggregatedStmtBindings);
|
||||
}
|
||||
|
||||
void BoundNodesTree::
|
||||
visitMatchesRecursively(Visitor* ResultVisitor,
|
||||
std::map<std::string, const clang::Decl*>
|
||||
std::map<std::string, const Decl*>
|
||||
AggregatedDeclBindings,
|
||||
std::map<std::string, const clang::Stmt*>
|
||||
std::map<std::string, const Stmt*>
|
||||
AggregatedStmtBindings) {
|
||||
copy(DeclBindings.begin(), DeclBindings.end(),
|
||||
inserter(AggregatedDeclBindings, AggregatedDeclBindings.begin()));
|
||||
@ -79,14 +79,14 @@ visitMatchesRecursively(Visitor* ResultVisitor,
|
||||
|
||||
BoundNodesTreeBuilder::BoundNodesTreeBuilder() {}
|
||||
|
||||
void BoundNodesTreeBuilder::
|
||||
setBinding(const std::pair<const std::string, const clang::Decl*>& Binding) {
|
||||
DeclBindings.insert(Binding);
|
||||
void BoundNodesTreeBuilder::setBinding(const std::string &Id,
|
||||
const Decl *Node) {
|
||||
DeclBindings[Id] = Node;
|
||||
}
|
||||
|
||||
void BoundNodesTreeBuilder::
|
||||
setBinding(const std::pair<const std::string, const clang::Stmt*>& Binding) {
|
||||
StmtBindings.insert(Binding);
|
||||
void BoundNodesTreeBuilder::setBinding(const std::string &Id,
|
||||
const Stmt *Node) {
|
||||
StmtBindings[Id] = Node;
|
||||
}
|
||||
|
||||
void BoundNodesTreeBuilder::addMatch(const BoundNodesTree& Bindings) {
|
||||
|
@ -24,6 +24,13 @@ TEST(HasNameDeathTest, DiesOnEmptyName) {
|
||||
}, "");
|
||||
}
|
||||
|
||||
TEST(HasNameDeathTest, DiesOnEmptyPattern) {
|
||||
ASSERT_DEBUG_DEATH({
|
||||
DeclarationMatcher HasEmptyName = record(matchesName(""));
|
||||
EXPECT_TRUE(notMatches("class X {};", HasEmptyName));
|
||||
}, "");
|
||||
}
|
||||
|
||||
TEST(IsDerivedFromDeathTest, DiesOnEmptyBaseName) {
|
||||
ASSERT_DEBUG_DEATH({
|
||||
DeclarationMatcher IsDerivedFromEmpty = record(isDerivedFrom(""));
|
||||
@ -40,10 +47,34 @@ TEST(NameableDeclaration, MatchesVariousDecls) {
|
||||
EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", NamedX));
|
||||
EXPECT_TRUE(matches("void foo() { int X; }", NamedX));
|
||||
EXPECT_TRUE(matches("namespace X { }", NamedX));
|
||||
EXPECT_TRUE(matches("enum X { A, B, C };", NamedX));
|
||||
|
||||
EXPECT_TRUE(notMatches("#define X 1", NamedX));
|
||||
}
|
||||
|
||||
TEST(NameableDeclaration, REMatchesVariousDecls) {
|
||||
DeclarationMatcher NamedX = nameableDeclaration(matchesName("::X"));
|
||||
EXPECT_TRUE(matches("typedef int Xa;", NamedX));
|
||||
EXPECT_TRUE(matches("int Xb;", NamedX));
|
||||
EXPECT_TRUE(matches("class foo { virtual void Xc(); };", NamedX));
|
||||
EXPECT_TRUE(matches("void foo() try { } catch(int Xdef) { }", NamedX));
|
||||
EXPECT_TRUE(matches("void foo() { int Xgh; }", NamedX));
|
||||
EXPECT_TRUE(matches("namespace Xij { }", NamedX));
|
||||
EXPECT_TRUE(matches("enum X { A, B, C };", NamedX));
|
||||
|
||||
EXPECT_TRUE(notMatches("#define Xkl 1", NamedX));
|
||||
|
||||
DeclarationMatcher StartsWithNo = nameableDeclaration(matchesName("::no"));
|
||||
EXPECT_TRUE(matches("int no_foo;", StartsWithNo));
|
||||
EXPECT_TRUE(matches("class foo { virtual void nobody(); };", StartsWithNo));
|
||||
|
||||
DeclarationMatcher Abc = nameableDeclaration(matchesName("a.*b.*c"));
|
||||
EXPECT_TRUE(matches("int abc;", Abc));
|
||||
EXPECT_TRUE(matches("int aFOObBARc;", Abc));
|
||||
EXPECT_TRUE(notMatches("int cab;", Abc));
|
||||
EXPECT_TRUE(matches("int cabc;", Abc));
|
||||
}
|
||||
|
||||
TEST(DeclarationMatcher, MatchClass) {
|
||||
DeclarationMatcher ClassMatcher(record());
|
||||
#if !defined(_MSC_VER)
|
||||
@ -456,6 +487,21 @@ TEST(DeclarationMatcher, HasDescendant) {
|
||||
"};", ZDescendantClassXDescendantClassY));
|
||||
}
|
||||
|
||||
TEST(Enum, DoesNotMatchClasses) {
|
||||
EXPECT_TRUE(notMatches("class X {};", enumDecl(hasName("X"))));
|
||||
}
|
||||
|
||||
TEST(Enum, MatchesEnums) {
|
||||
EXPECT_TRUE(matches("enum X {};", enumDecl(hasName("X"))));
|
||||
}
|
||||
|
||||
TEST(EnumConstant, Matches) {
|
||||
DeclarationMatcher Matcher = enumConstant(hasName("A"));
|
||||
EXPECT_TRUE(matches("enum X{ A };", Matcher));
|
||||
EXPECT_TRUE(notMatches("enum X{ B };", Matcher));
|
||||
EXPECT_TRUE(notMatches("enum X {};", Matcher));
|
||||
}
|
||||
|
||||
TEST(StatementMatcher, Has) {
|
||||
StatementMatcher HasVariableI =
|
||||
expression(
|
||||
@ -552,23 +598,40 @@ TEST(Matcher, BindMatchedNodes) {
|
||||
DeclarationMatcher ClassX = has(id("x", record(hasName("X"))));
|
||||
|
||||
EXPECT_TRUE(matchAndVerifyResultTrue("class X {};",
|
||||
ClassX, new VerifyIdIsBoundToDecl<clang::CXXRecordDecl>("x")));
|
||||
ClassX, new VerifyIdIsBoundToDecl<CXXRecordDecl>("x")));
|
||||
|
||||
EXPECT_TRUE(matchAndVerifyResultFalse("class X {};",
|
||||
ClassX, new VerifyIdIsBoundToDecl<clang::CXXRecordDecl>("other-id")));
|
||||
ClassX, new VerifyIdIsBoundToDecl<CXXRecordDecl>("other-id")));
|
||||
|
||||
TypeMatcher TypeAHasClassB = hasDeclaration(
|
||||
record(hasName("A"), has(id("b", record(hasName("B"))))));
|
||||
|
||||
EXPECT_TRUE(matchAndVerifyResultTrue("class A { public: A *a; class B {}; };",
|
||||
TypeAHasClassB,
|
||||
new VerifyIdIsBoundToDecl<clang::Decl>("b")));
|
||||
new VerifyIdIsBoundToDecl<Decl>("b")));
|
||||
|
||||
StatementMatcher MethodX = id("x", call(callee(method(hasName("x")))));
|
||||
|
||||
EXPECT_TRUE(matchAndVerifyResultTrue("class A { void x() { x(); } };",
|
||||
MethodX,
|
||||
new VerifyIdIsBoundToStmt<clang::CXXMemberCallExpr>("x")));
|
||||
new VerifyIdIsBoundToStmt<CXXMemberCallExpr>("x")));
|
||||
}
|
||||
|
||||
TEST(Matcher, BindTheSameNameInAlternatives) {
|
||||
StatementMatcher matcher = anyOf(
|
||||
binaryOperator(hasOperatorName("+"),
|
||||
hasLHS(id("x", expression())),
|
||||
hasRHS(integerLiteral(equals(0)))),
|
||||
binaryOperator(hasOperatorName("+"),
|
||||
hasLHS(integerLiteral(equals(0))),
|
||||
hasRHS(id("x", expression()))));
|
||||
|
||||
EXPECT_TRUE(matchAndVerifyResultTrue(
|
||||
// The first branch of the matcher binds x to 0 but then fails.
|
||||
// The second branch binds x to f() and succeeds.
|
||||
"int f() { return 0 + f(); }",
|
||||
matcher,
|
||||
new VerifyIdIsBoundToStmt<CallExpr>("x")));
|
||||
}
|
||||
|
||||
TEST(HasType, TakesQualTypeMatcherAndMatchesExpr) {
|
||||
@ -613,7 +676,7 @@ TEST(HasType, TakesDeclMatcherAndMatchesValueDecl) {
|
||||
|
||||
TEST(Matcher, Call) {
|
||||
// FIXME: Do we want to overload Call() to directly take
|
||||
// Matcher<clang::Decl>, too?
|
||||
// Matcher<Decl>, too?
|
||||
StatementMatcher MethodX = call(hasDeclaration(method(hasName("x"))));
|
||||
|
||||
EXPECT_TRUE(matches("class Y { void x() { x(); } };", MethodX));
|
||||
@ -657,6 +720,18 @@ TEST(Matcher, Call) {
|
||||
MethodOnYPointer));
|
||||
}
|
||||
|
||||
TEST(HasType, MatchesAsString) {
|
||||
EXPECT_TRUE(
|
||||
matches("class Y { public: void x(); }; void z() {Y* y; y->x(); }",
|
||||
call(on(hasType(asString("class Y *"))))));
|
||||
EXPECT_TRUE(matches("class X { void x(int x) {} };",
|
||||
method(hasParameter(0, hasType(asString("int"))))));
|
||||
EXPECT_TRUE(matches("namespace ns { struct A {}; } struct B { ns::A a; };",
|
||||
field(hasType(asString("ns::A")))));
|
||||
EXPECT_TRUE(matches("namespace { struct A {}; } struct B { A a; };",
|
||||
field(hasType(asString("struct <anonymous>::A")))));
|
||||
}
|
||||
|
||||
TEST(Matcher, OverloadedOperatorCall) {
|
||||
StatementMatcher OpCall = overloadedOperatorCall();
|
||||
// Unary operator
|
||||
@ -772,6 +847,30 @@ TEST(Matcher, CalledVariable) {
|
||||
CallOnVariableY));
|
||||
}
|
||||
|
||||
TEST(UnaryExprOrTypeTraitExpr, MatchesSizeOfAndAlignOf) {
|
||||
EXPECT_TRUE(matches("void x() { int a = sizeof(a); }",
|
||||
unaryExprOrTypeTraitExpr()));
|
||||
EXPECT_TRUE(notMatches("void x() { int a = sizeof(a); }",
|
||||
alignOfExpr(anything())));
|
||||
// FIXME: Uncomment once alignof is enabled.
|
||||
// EXPECT_TRUE(matches("void x() { int a = alignof(a); }",
|
||||
// unaryExprOrTypeTraitExpr()));
|
||||
// EXPECT_TRUE(notMatches("void x() { int a = alignof(a); }",
|
||||
// sizeOfExpr()));
|
||||
}
|
||||
|
||||
TEST(UnaryExpressionOrTypeTraitExpression, MatchesCorrectType) {
|
||||
EXPECT_TRUE(matches("void x() { int a = sizeof(a); }", sizeOfExpr(
|
||||
hasArgumentOfType(asString("int")))));
|
||||
EXPECT_TRUE(notMatches("void x() { int a = sizeof(a); }", sizeOfExpr(
|
||||
hasArgumentOfType(asString("float")))));
|
||||
EXPECT_TRUE(matches(
|
||||
"struct A {}; void x() { A a; int b = sizeof(a); }",
|
||||
sizeOfExpr(hasArgumentOfType(hasDeclaration(record(hasName("A")))))));
|
||||
EXPECT_TRUE(notMatches("void x() { int a = sizeof(a); }", sizeOfExpr(
|
||||
hasArgumentOfType(hasDeclaration(record(hasName("string")))))));
|
||||
}
|
||||
|
||||
TEST(MemberExpression, DoesNotMatchClasses) {
|
||||
EXPECT_TRUE(notMatches("class Y { void x() {} };", memberExpression()));
|
||||
}
|
||||
@ -939,6 +1038,15 @@ TEST(HasAnyParameter, MatchesIndependentlyOfPosition) {
|
||||
method(hasAnyParameter(hasType(record(hasName("X")))))));
|
||||
}
|
||||
|
||||
TEST(Returns, MatchesReturnTypes) {
|
||||
EXPECT_TRUE(matches("class Y { int f() { return 1; } };",
|
||||
function(returns(asString("int")))));
|
||||
EXPECT_TRUE(notMatches("class Y { int f() { return 1; } };",
|
||||
function(returns(asString("float")))));
|
||||
EXPECT_TRUE(matches("class Y { Y getMe() { return *this; } };",
|
||||
function(returns(hasDeclaration(record(hasName("Y")))))));
|
||||
}
|
||||
|
||||
TEST(HasAnyParameter, DoesntMatchIfInnerMatcherDoesntMatch) {
|
||||
EXPECT_TRUE(notMatches("class Y {}; class X { void x(int) {} };",
|
||||
method(hasAnyParameter(hasType(record(hasName("X")))))));
|
||||
@ -1062,6 +1170,15 @@ TEST(ConstructorDeclaration, IsImplicit) {
|
||||
constructor(unless(isImplicit()))));
|
||||
}
|
||||
|
||||
TEST(DestructorDeclaration, MatchesVirtualDestructor) {
|
||||
EXPECT_TRUE(matches("class Foo { virtual ~Foo(); };",
|
||||
destructor(ofClass(hasName("Foo")))));
|
||||
}
|
||||
|
||||
TEST(DestructorDeclaration, DoesNotMatchImplicitDestructor) {
|
||||
EXPECT_TRUE(notMatches("class Foo {};", destructor(ofClass(hasName("Foo")))));
|
||||
}
|
||||
|
||||
TEST(HasAnyConstructorInitializer, SimpleCase) {
|
||||
EXPECT_TRUE(notMatches(
|
||||
"class Foo { Foo() { } };",
|
||||
@ -1162,6 +1279,11 @@ TEST(Matcher, NewExpressionArgumentCount) {
|
||||
New));
|
||||
}
|
||||
|
||||
TEST(Matcher, DeleteExpression) {
|
||||
EXPECT_TRUE(matches("struct A {}; void f(A* a) { delete a; }",
|
||||
deleteExpression()));
|
||||
}
|
||||
|
||||
TEST(Matcher, DefaultArgument) {
|
||||
StatementMatcher Arg = defaultArgument();
|
||||
|
||||
@ -1412,6 +1534,32 @@ TEST(Matcher, ConditionalOperator) {
|
||||
notMatches("void x() { true ? false : true; }", ConditionalFalse));
|
||||
}
|
||||
|
||||
TEST(ArraySubscriptMatchers, ArraySubscripts) {
|
||||
EXPECT_TRUE(matches("int i[2]; void f() { i[1] = 1; }",
|
||||
arraySubscriptExpr()));
|
||||
EXPECT_TRUE(notMatches("int i; void f() { i = 1; }",
|
||||
arraySubscriptExpr()));
|
||||
}
|
||||
|
||||
TEST(ArraySubscriptMatchers, ArrayIndex) {
|
||||
EXPECT_TRUE(matches(
|
||||
"int i[2]; void f() { i[1] = 1; }",
|
||||
arraySubscriptExpr(hasIndex(integerLiteral(equals(1))))));
|
||||
EXPECT_TRUE(matches(
|
||||
"int i[2]; void f() { 1[i] = 1; }",
|
||||
arraySubscriptExpr(hasIndex(integerLiteral(equals(1))))));
|
||||
EXPECT_TRUE(notMatches(
|
||||
"int i[2]; void f() { i[1] = 1; }",
|
||||
arraySubscriptExpr(hasIndex(integerLiteral(equals(0))))));
|
||||
}
|
||||
|
||||
TEST(ArraySubscriptMatchers, MatchesArrayBase) {
|
||||
EXPECT_TRUE(matches(
|
||||
"int i[2]; void f() { i[1] = 2; }",
|
||||
arraySubscriptExpr(hasBase(implicitCast(
|
||||
hasSourceExpression(declarationReference()))))));
|
||||
}
|
||||
|
||||
TEST(Matcher, HasNameSupportsNamespaces) {
|
||||
EXPECT_TRUE(matches("namespace a { namespace b { class C; } }",
|
||||
record(hasName("a::b::C"))));
|
||||
@ -1519,8 +1667,33 @@ TEST(Matcher, VisitsTemplateInstantiations) {
|
||||
hasDescendant(call(callee(method(hasName("x"))))))));
|
||||
}
|
||||
|
||||
TEST(Matcher, HandlesNullQualTypes) {
|
||||
// FIXME: Add a Type matcher so we can replace uses of this
|
||||
// variable with Type(True())
|
||||
const TypeMatcher AnyType = anything();
|
||||
|
||||
// We don't really care whether this matcher succeeds; we're testing that
|
||||
// it completes without crashing.
|
||||
EXPECT_TRUE(matches(
|
||||
"struct A { };"
|
||||
"template <typename T>"
|
||||
"void f(T t) {"
|
||||
" T local_t(t /* this becomes a null QualType in the AST */);"
|
||||
"}"
|
||||
"void g() {"
|
||||
" f(0);"
|
||||
"}",
|
||||
expression(hasType(TypeMatcher(
|
||||
anyOf(
|
||||
TypeMatcher(hasDeclaration(anything())),
|
||||
pointsTo(AnyType),
|
||||
references(AnyType)
|
||||
// Other QualType matchers should go here.
|
||||
))))));
|
||||
}
|
||||
|
||||
// For testing AST_MATCHER_P().
|
||||
AST_MATCHER_P(clang::Decl, just, internal::Matcher<clang::Decl>, AMatcher) {
|
||||
AST_MATCHER_P(Decl, just, internal::Matcher<Decl>, AMatcher) {
|
||||
// Make sure all special variables are used: node, match_finder,
|
||||
// bound_nodes_builder, and the parameter named 'AMatcher'.
|
||||
return AMatcher.matches(Node, Finder, Builder);
|
||||
@ -1530,21 +1703,21 @@ TEST(AstMatcherPMacro, Works) {
|
||||
DeclarationMatcher HasClassB = just(has(id("b", record(hasName("B")))));
|
||||
|
||||
EXPECT_TRUE(matchAndVerifyResultTrue("class A { class B {}; };",
|
||||
HasClassB, new VerifyIdIsBoundToDecl<clang::Decl>("b")));
|
||||
HasClassB, new VerifyIdIsBoundToDecl<Decl>("b")));
|
||||
|
||||
EXPECT_TRUE(matchAndVerifyResultFalse("class A { class B {}; };",
|
||||
HasClassB, new VerifyIdIsBoundToDecl<clang::Decl>("a")));
|
||||
HasClassB, new VerifyIdIsBoundToDecl<Decl>("a")));
|
||||
|
||||
EXPECT_TRUE(matchAndVerifyResultFalse("class A { class C {}; };",
|
||||
HasClassB, new VerifyIdIsBoundToDecl<clang::Decl>("b")));
|
||||
HasClassB, new VerifyIdIsBoundToDecl<Decl>("b")));
|
||||
}
|
||||
|
||||
AST_POLYMORPHIC_MATCHER_P(
|
||||
polymorphicHas, internal::Matcher<clang::Decl>, AMatcher) {
|
||||
TOOLING_COMPILE_ASSERT((llvm::is_same<NodeType, clang::Decl>::value) ||
|
||||
(llvm::is_same<NodeType, clang::Stmt>::value),
|
||||
polymorphicHas, internal::Matcher<Decl>, AMatcher) {
|
||||
TOOLING_COMPILE_ASSERT((llvm::is_same<NodeType, Decl>::value) ||
|
||||
(llvm::is_same<NodeType, Stmt>::value),
|
||||
assert_node_type_is_accessible);
|
||||
internal::TypedBaseMatcher<clang::Decl> ChildMatcher(AMatcher);
|
||||
internal::TypedBaseMatcher<Decl> ChildMatcher(AMatcher);
|
||||
return Finder->matchesChildOf(
|
||||
Node, ChildMatcher, Builder,
|
||||
ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses,
|
||||
@ -1555,13 +1728,13 @@ TEST(AstPolymorphicMatcherPMacro, Works) {
|
||||
DeclarationMatcher HasClassB = polymorphicHas(id("b", record(hasName("B"))));
|
||||
|
||||
EXPECT_TRUE(matchAndVerifyResultTrue("class A { class B {}; };",
|
||||
HasClassB, new VerifyIdIsBoundToDecl<clang::Decl>("b")));
|
||||
HasClassB, new VerifyIdIsBoundToDecl<Decl>("b")));
|
||||
|
||||
EXPECT_TRUE(matchAndVerifyResultFalse("class A { class B {}; };",
|
||||
HasClassB, new VerifyIdIsBoundToDecl<clang::Decl>("a")));
|
||||
HasClassB, new VerifyIdIsBoundToDecl<Decl>("a")));
|
||||
|
||||
EXPECT_TRUE(matchAndVerifyResultFalse("class A { class C {}; };",
|
||||
HasClassB, new VerifyIdIsBoundToDecl<clang::Decl>("b")));
|
||||
HasClassB, new VerifyIdIsBoundToDecl<Decl>("b")));
|
||||
|
||||
StatementMatcher StatementHasClassB =
|
||||
polymorphicHas(record(hasName("B")));
|
||||
@ -1831,6 +2004,41 @@ TEST(DeclarationStatement, MatchesVariableDeclarationStatements) {
|
||||
EXPECT_TRUE(matches("void x() { int a; }", declarationStatement()));
|
||||
}
|
||||
|
||||
TEST(InitListExpression, MatchesInitListExpression) {
|
||||
EXPECT_TRUE(matches("int a[] = { 1, 2 };",
|
||||
initListExpr(hasType(asString("int [2]")))));
|
||||
EXPECT_TRUE(matches("struct B { int x, y; }; B b = { 5, 6 };",
|
||||
initListExpr(hasType(record(hasName("B"))))));
|
||||
}
|
||||
|
||||
TEST(UsingDeclaration, MatchesUsingDeclarations) {
|
||||
EXPECT_TRUE(matches("namespace X { int x; } using X::x;",
|
||||
usingDecl()));
|
||||
}
|
||||
|
||||
TEST(UsingDeclaration, MatchesShadowUsingDelcarations) {
|
||||
EXPECT_TRUE(matches("namespace f { int a; } using f::a;",
|
||||
usingDecl(hasAnyUsingShadowDecl(hasName("a")))));
|
||||
}
|
||||
|
||||
TEST(UsingDeclaration, MatchesSpecificTarget) {
|
||||
EXPECT_TRUE(matches("namespace f { int a; void b(); } using f::b;",
|
||||
usingDecl(hasAnyUsingShadowDecl(
|
||||
hasTargetDecl(function())))));
|
||||
EXPECT_TRUE(notMatches("namespace f { int a; void b(); } using f::a;",
|
||||
usingDecl(hasAnyUsingShadowDecl(
|
||||
hasTargetDecl(function())))));
|
||||
}
|
||||
|
||||
TEST(UsingDeclaration, ThroughUsingDeclaration) {
|
||||
EXPECT_TRUE(matches(
|
||||
"namespace a { void f(); } using a::f; void g() { f(); }",
|
||||
declarationReference(throughUsingDecl(anything()))));
|
||||
EXPECT_TRUE(notMatches(
|
||||
"namespace a { void f(); } using a::f; void g() { a::f(); }",
|
||||
declarationReference(throughUsingDecl(anything()))));
|
||||
}
|
||||
|
||||
TEST(While, MatchesWhileLoops) {
|
||||
EXPECT_TRUE(notMatches("void x() {}", whileStmt()));
|
||||
EXPECT_TRUE(matches("void x() { while(true); }", whileStmt()));
|
||||
@ -1871,26 +2079,26 @@ TEST(HasConditionVariableStatement, MatchesConditionVariables) {
|
||||
TEST(ForEach, BindsOneNode) {
|
||||
EXPECT_TRUE(matchAndVerifyResultTrue("class C { int x; };",
|
||||
record(hasName("C"), forEach(id("x", field(hasName("x"))))),
|
||||
new VerifyIdIsBoundToDecl<clang::FieldDecl>("x", 1)));
|
||||
new VerifyIdIsBoundToDecl<FieldDecl>("x", 1)));
|
||||
}
|
||||
|
||||
TEST(ForEach, BindsMultipleNodes) {
|
||||
EXPECT_TRUE(matchAndVerifyResultTrue("class C { int x; int y; int z; };",
|
||||
record(hasName("C"), forEach(id("f", field()))),
|
||||
new VerifyIdIsBoundToDecl<clang::FieldDecl>("f", 3)));
|
||||
new VerifyIdIsBoundToDecl<FieldDecl>("f", 3)));
|
||||
}
|
||||
|
||||
TEST(ForEach, BindsRecursiveCombinations) {
|
||||
EXPECT_TRUE(matchAndVerifyResultTrue(
|
||||
"class C { class D { int x; int y; }; class E { int y; int z; }; };",
|
||||
record(hasName("C"), forEach(record(forEach(id("f", field()))))),
|
||||
new VerifyIdIsBoundToDecl<clang::FieldDecl>("f", 4)));
|
||||
new VerifyIdIsBoundToDecl<FieldDecl>("f", 4)));
|
||||
}
|
||||
|
||||
TEST(ForEachDescendant, BindsOneNode) {
|
||||
EXPECT_TRUE(matchAndVerifyResultTrue("class C { class D { int x; }; };",
|
||||
record(hasName("C"), forEachDescendant(id("x", field(hasName("x"))))),
|
||||
new VerifyIdIsBoundToDecl<clang::FieldDecl>("x", 1)));
|
||||
new VerifyIdIsBoundToDecl<FieldDecl>("x", 1)));
|
||||
}
|
||||
|
||||
TEST(ForEachDescendant, BindsMultipleNodes) {
|
||||
@ -1898,7 +2106,7 @@ TEST(ForEachDescendant, BindsMultipleNodes) {
|
||||
"class C { class D { int x; int y; }; "
|
||||
" class E { class F { int y; int z; }; }; };",
|
||||
record(hasName("C"), forEachDescendant(id("f", field()))),
|
||||
new VerifyIdIsBoundToDecl<clang::FieldDecl>("f", 4)));
|
||||
new VerifyIdIsBoundToDecl<FieldDecl>("f", 4)));
|
||||
}
|
||||
|
||||
TEST(ForEachDescendant, BindsRecursiveCombinations) {
|
||||
@ -1907,7 +2115,7 @@ TEST(ForEachDescendant, BindsRecursiveCombinations) {
|
||||
" class E { class F { class G { int y; int z; }; }; }; }; };",
|
||||
record(hasName("C"), forEachDescendant(record(
|
||||
forEachDescendant(id("f", field()))))),
|
||||
new VerifyIdIsBoundToDecl<clang::FieldDecl>("f", 8)));
|
||||
new VerifyIdIsBoundToDecl<FieldDecl>("f", 8)));
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user