summaryrefslogtreecommitdiff
path: root/clang/lib/ASTMatchers
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/ASTMatchers')
-rw-r--r--clang/lib/ASTMatchers/ASTMatchFinder.cpp128
-rw-r--r--clang/lib/ASTMatchers/ASTMatchersInternal.cpp282
-rw-r--r--clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp4
-rw-r--r--clang/lib/ASTMatchers/Dynamic/Marshallers.cpp172
-rw-r--r--clang/lib/ASTMatchers/Dynamic/Marshallers.h264
-rw-r--r--clang/lib/ASTMatchers/Dynamic/Registry.cpp33
-rw-r--r--clang/lib/ASTMatchers/Dynamic/VariantValue.cpp11
-rw-r--r--clang/lib/ASTMatchers/GtestMatchers.cpp104
8 files changed, 780 insertions, 218 deletions
diff --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp
index 0d1f713db8d30..e88da16dd3d40 100644
--- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -43,6 +43,13 @@ typedef MatchFinder::MatchCallback MatchCallback;
// optimize this on.
static const unsigned MaxMemoizationEntries = 10000;
+enum class MatchType {
+ Ancestors,
+
+ Descendants,
+ Child,
+};
+
// We use memoization to avoid running the same matcher on the same
// AST node twice. This struct is the key for looking up match
// result. It consists of an ID of the MatcherInterface (for
@@ -57,14 +64,15 @@ static const unsigned MaxMemoizationEntries = 10000;
// provides enough benefit for the additional amount of code.
struct MatchKey {
DynTypedMatcher::MatcherIDType MatcherID;
- ast_type_traits::DynTypedNode Node;
+ DynTypedNode Node;
BoundNodesTreeBuilder BoundNodes;
- ast_type_traits::TraversalKind Traversal = ast_type_traits::TK_AsIs;
+ TraversalKind Traversal = TK_AsIs;
+ MatchType Type;
bool operator<(const MatchKey &Other) const {
- return std::tie(MatcherID, Node, BoundNodes, Traversal) <
- std::tie(Other.MatcherID, Other.Node, Other.BoundNodes,
- Other.Traversal);
+ return std::tie(Traversal, Type, MatcherID, Node, BoundNodes) <
+ std::tie(Other.Traversal, Other.Type, Other.MatcherID, Other.Node,
+ Other.BoundNodes);
}
};
@@ -87,8 +95,7 @@ public:
// matching the descendants.
MatchChildASTVisitor(const DynTypedMatcher *Matcher, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder, int MaxDepth,
- ast_type_traits::TraversalKind Traversal,
- ASTMatchFinder::BindKind Bind)
+ TraversalKind Traversal, ASTMatchFinder::BindKind Bind)
: Matcher(Matcher), Finder(Finder), Builder(Builder), CurrentDepth(0),
MaxDepth(MaxDepth), Traversal(Traversal), Bind(Bind), Matches(false) {}
@@ -103,7 +110,7 @@ public:
// Traverse*(c) for each child c of 'node'.
// - Traverse*(c) in turn calls Traverse(c), completing the
// recursion.
- bool findMatch(const ast_type_traits::DynTypedNode &DynNode) {
+ bool findMatch(const DynTypedNode &DynNode) {
reset();
if (const Decl *D = DynNode.get<Decl>())
traverse(*D);
@@ -143,14 +150,16 @@ public:
Stmt *StmtToTraverse = StmtNode;
if (auto *ExprNode = dyn_cast_or_null<Expr>(StmtNode)) {
auto *LambdaNode = dyn_cast_or_null<LambdaExpr>(StmtNode);
- if (LambdaNode && Finder->getASTContext().getTraversalKind() ==
- ast_type_traits::TK_IgnoreUnlessSpelledInSource)
+ if (LambdaNode &&
+ Finder->getASTContext().getParentMapContext().getTraversalKind() ==
+ TK_IgnoreUnlessSpelledInSource)
StmtToTraverse = LambdaNode;
else
- StmtToTraverse = Finder->getASTContext().traverseIgnored(ExprNode);
+ StmtToTraverse =
+ Finder->getASTContext().getParentMapContext().traverseIgnored(
+ ExprNode);
}
- if (Traversal ==
- ast_type_traits::TraversalKind::TK_IgnoreImplicitCastsAndParentheses) {
+ if (Traversal == TraversalKind::TK_IgnoreImplicitCastsAndParentheses) {
if (Expr *ExprNode = dyn_cast_or_null<Expr>(StmtNode))
StmtToTraverse = ExprNode->IgnoreParenImpCasts();
}
@@ -216,8 +225,8 @@ public:
return traverse(*CtorInit);
}
bool TraverseLambdaExpr(LambdaExpr *Node) {
- if (Finder->getASTContext().getTraversalKind() !=
- ast_type_traits::TK_IgnoreUnlessSpelledInSource)
+ if (Finder->getASTContext().getParentMapContext().getTraversalKind() !=
+ TK_IgnoreUnlessSpelledInSource)
return VisitorBase::TraverseLambdaExpr(Node);
if (!Node)
return true;
@@ -308,7 +317,7 @@ private:
}
if (Bind != ASTMatchFinder::BK_All) {
BoundNodesTreeBuilder RecursiveBuilder(*Builder);
- if (Matcher->matches(ast_type_traits::DynTypedNode::create(Node), Finder,
+ if (Matcher->matches(DynTypedNode::create(Node), Finder,
&RecursiveBuilder)) {
Matches = true;
ResultBindings.addMatch(RecursiveBuilder);
@@ -316,7 +325,7 @@ private:
}
} else {
BoundNodesTreeBuilder RecursiveBuilder(*Builder);
- if (Matcher->matches(ast_type_traits::DynTypedNode::create(Node), Finder,
+ if (Matcher->matches(DynTypedNode::create(Node), Finder,
&RecursiveBuilder)) {
// After the first match the matcher succeeds.
Matches = true;
@@ -343,7 +352,7 @@ private:
BoundNodesTreeBuilder ResultBindings;
int CurrentDepth;
const int MaxDepth;
- const ast_type_traits::TraversalKind Traversal;
+ const TraversalKind Traversal;
const ASTMatchFinder::BindKind Bind;
bool Matches;
};
@@ -440,12 +449,10 @@ public:
bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit);
// Matches children or descendants of 'Node' with 'BaseMatcher'.
- bool memoizedMatchesRecursively(const ast_type_traits::DynTypedNode &Node,
- ASTContext &Ctx,
+ bool memoizedMatchesRecursively(const DynTypedNode &Node, ASTContext &Ctx,
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder, int MaxDepth,
- ast_type_traits::TraversalKind Traversal,
- BindKind Bind) {
+ TraversalKind Traversal, BindKind Bind) {
// For AST-nodes that don't have an identity, we can't memoize.
if (!Node.getMemoizationData() || !Builder->isComparable())
return matchesRecursively(Node, Matcher, Builder, MaxDepth, Traversal,
@@ -456,8 +463,9 @@ public:
Key.Node = Node;
// Note that we key on the bindings *before* the match.
Key.BoundNodes = *Builder;
- Key.Traversal = Ctx.getTraversalKind();
-
+ Key.Traversal = Ctx.getParentMapContext().getTraversalKind();
+ // Memoize result even doing a single-level match, it might be expensive.
+ Key.Type = MaxDepth == 1 ? MatchType::Child : MatchType::Descendants;
MemoizationMap::iterator I = ResultCache.find(Key);
if (I != ResultCache.end()) {
*Builder = I->second.Nodes;
@@ -477,11 +485,10 @@ public:
}
// Matches children or descendants of 'Node' with 'BaseMatcher'.
- bool matchesRecursively(const ast_type_traits::DynTypedNode &Node,
+ bool matchesRecursively(const DynTypedNode &Node,
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder, int MaxDepth,
- ast_type_traits::TraversalKind Traversal,
- BindKind Bind) {
+ TraversalKind Traversal, BindKind Bind) {
MatchChildASTVisitor Visitor(
&Matcher, this, Builder, MaxDepth, Traversal, Bind);
return Visitor.findMatch(Node);
@@ -498,10 +505,9 @@ public:
bool Directly) override;
// Implements ASTMatchFinder::matchesChildOf.
- bool matchesChildOf(const ast_type_traits::DynTypedNode &Node,
- ASTContext &Ctx, const DynTypedMatcher &Matcher,
- BoundNodesTreeBuilder *Builder,
- ast_type_traits::TraversalKind Traversal,
+ bool matchesChildOf(const DynTypedNode &Node, ASTContext &Ctx,
+ const DynTypedMatcher &Matcher,
+ BoundNodesTreeBuilder *Builder, TraversalKind Traversal,
BindKind Bind) override {
if (ResultCache.size() > MaxMemoizationEntries)
ResultCache.clear();
@@ -509,19 +515,18 @@ public:
Bind);
}
// Implements ASTMatchFinder::matchesDescendantOf.
- bool matchesDescendantOf(const ast_type_traits::DynTypedNode &Node,
- ASTContext &Ctx, const DynTypedMatcher &Matcher,
+ bool matchesDescendantOf(const DynTypedNode &Node, ASTContext &Ctx,
+ const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
BindKind Bind) override {
if (ResultCache.size() > MaxMemoizationEntries)
ResultCache.clear();
return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, INT_MAX,
- ast_type_traits::TraversalKind::TK_AsIs,
- Bind);
+ TraversalKind::TK_AsIs, Bind);
}
// Implements ASTMatchFinder::matchesAncestorOf.
- bool matchesAncestorOf(const ast_type_traits::DynTypedNode &Node,
- ASTContext &Ctx, const DynTypedMatcher &Matcher,
+ bool matchesAncestorOf(const DynTypedNode &Node, ASTContext &Ctx,
+ const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
AncestorMatchMode MatchMode) override {
// Reset the cache outside of the recursive call to make sure we
@@ -534,7 +539,7 @@ public:
// Matches all registered matchers on the given node and calls the
// result callback for every node that matches.
- void match(const ast_type_traits::DynTypedNode &Node) {
+ void match(const DynTypedNode &Node) {
// FIXME: Improve this with a switch or a visitor pattern.
if (auto *N = Node.get<Decl>()) {
match(*N);
@@ -612,7 +617,7 @@ private:
}
}
- void matchWithFilter(const ast_type_traits::DynTypedNode &DynNode) {
+ void matchWithFilter(const DynTypedNode &DynNode) {
auto Kind = DynNode.getNodeKind();
auto it = MatcherFiltersMap.find(Kind);
const auto &Filter =
@@ -636,8 +641,7 @@ private:
}
}
- const std::vector<unsigned short> &
- getFilterForKind(ast_type_traits::ASTNodeKind Kind) {
+ const std::vector<unsigned short> &getFilterForKind(ASTNodeKind Kind) {
auto &Filter = MatcherFiltersMap[Kind];
auto &Matchers = this->Matchers->DeclOrStmt;
assert((Matchers.size() < USHRT_MAX) && "Too many matchers.");
@@ -652,10 +656,10 @@ private:
/// @{
/// Overloads to pair the different node types to their matchers.
void matchDispatch(const Decl *Node) {
- return matchWithFilter(ast_type_traits::DynTypedNode::create(*Node));
+ return matchWithFilter(DynTypedNode::create(*Node));
}
void matchDispatch(const Stmt *Node) {
- return matchWithFilter(ast_type_traits::DynTypedNode::create(*Node));
+ return matchWithFilter(DynTypedNode::create(*Node));
}
void matchDispatch(const Type *Node) {
@@ -692,12 +696,16 @@ private:
// Once there are multiple parents, the breadth first search order does not
// allow simple memoization on the ancestors. Thus, we only memoize as long
// as there is a single parent.
- bool memoizedMatchesAncestorOfRecursively(
- const ast_type_traits::DynTypedNode &Node, ASTContext &Ctx,
- const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder,
- AncestorMatchMode MatchMode) {
+ bool memoizedMatchesAncestorOfRecursively(const DynTypedNode &Node,
+ ASTContext &Ctx,
+ const DynTypedMatcher &Matcher,
+ BoundNodesTreeBuilder *Builder,
+ AncestorMatchMode MatchMode) {
// For AST-nodes that don't have an identity, we can't memoize.
- if (!Builder->isComparable())
+ // When doing a single-level match, we don't need to memoize because
+ // ParentMap (in ASTContext) already memoizes the result.
+ if (!Builder->isComparable() ||
+ MatchMode == AncestorMatchMode::AMM_ParentOnly)
return matchesAncestorOfRecursively(Node, Ctx, Matcher, Builder,
MatchMode);
@@ -705,7 +713,8 @@ private:
Key.MatcherID = Matcher.getID();
Key.Node = Node;
Key.BoundNodes = *Builder;
- Key.Traversal = Ctx.getTraversalKind();
+ Key.Traversal = Ctx.getParentMapContext().getTraversalKind();
+ Key.Type = MatchType::Ancestors;
// Note that we cannot use insert and reuse the iterator, as recursive
// calls to match might invalidate the result cache iterators.
@@ -727,8 +736,7 @@ private:
return CachedResult.ResultOfMatch;
}
- bool matchesAncestorOfRecursively(const ast_type_traits::DynTypedNode &Node,
- ASTContext &Ctx,
+ bool matchesAncestorOfRecursively(const DynTypedNode &Node, ASTContext &Ctx,
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
AncestorMatchMode MatchMode) {
@@ -747,7 +755,7 @@ private:
return D->getKind() == Decl::TranslationUnit;
})) {
llvm::errs() << "Tried to match orphan node:\n";
- Node.dump(llvm::errs(), ActiveASTContext->getSourceManager());
+ Node.dump(llvm::errs(), *ActiveASTContext);
llvm_unreachable("Parent map should be complete!");
}
#endif
@@ -755,7 +763,7 @@ private:
}
if (Parents.size() == 1) {
// Only one parent - do recursive memoization.
- const ast_type_traits::DynTypedNode Parent = Parents[0];
+ const DynTypedNode Parent = Parents[0];
BoundNodesTreeBuilder BuilderCopy = *Builder;
if (Matcher.matches(Parent, this, &BuilderCopy)) {
*Builder = std::move(BuilderCopy);
@@ -770,8 +778,7 @@ private:
} else {
// Multiple parents - BFS over the rest of the nodes.
llvm::DenseSet<const void *> Visited;
- std::deque<ast_type_traits::DynTypedNode> Queue(Parents.begin(),
- Parents.end());
+ std::deque<DynTypedNode> Queue(Parents.begin(), Parents.end());
while (!Queue.empty()) {
BoundNodesTreeBuilder BuilderCopy = *Builder;
if (Matcher.matches(Queue.front(), this, &BuilderCopy)) {
@@ -861,8 +868,7 @@ private:
/// kind (and derived kinds) so it is a waste to try every matcher on every
/// node.
/// We precalculate a list of matchers that pass the toplevel restrict check.
- llvm::DenseMap<ast_type_traits::ASTNodeKind, std::vector<unsigned short>>
- MatcherFiltersMap;
+ llvm::DenseMap<ASTNodeKind, std::vector<unsigned short>> MatcherFiltersMap;
const MatchFinder::MatchFinderOptions &Options;
ASTContext *ActiveASTContext;
@@ -923,9 +929,8 @@ bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
if (!ClassDecl)
continue;
if (ClassDecl == Declaration) {
- // This can happen for recursive template definitions; if the
- // current declaration did not match, we can safely return false.
- return false;
+ // This can happen for recursive template definitions.
+ continue;
}
BoundNodesTreeBuilder Result(*Builder);
if (Base.matches(*ClassDecl, this, &Result)) {
@@ -1137,8 +1142,7 @@ std::unique_ptr<ASTConsumer> MatchFinder::newASTConsumer() {
return std::make_unique<internal::MatchASTConsumer>(this, ParsingDone);
}
-void MatchFinder::match(const clang::ast_type_traits::DynTypedNode &Node,
- ASTContext &Context) {
+void MatchFinder::match(const clang::DynTypedNode &Node, ASTContext &Context) {
internal::MatchASTVisitor Visitor(&Matchers, Options);
Visitor.set_active_ast_context(&Context);
Visitor.match(Node);
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index 199a6d839e2eb..4b9baf7a0e751 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -15,9 +15,11 @@
#include "clang/AST/ASTTypeTraits.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ParentMapContext.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Basic/LLVM.h"
+#include "clang/Lex/Lexer.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/None.h"
@@ -27,6 +29,8 @@
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
@@ -40,39 +44,56 @@ namespace ast_matchers {
AST_MATCHER_P(ObjCMessageExpr, hasAnySelectorMatcher, std::vector<std::string>,
Matches) {
- std::string SelString = Node.getSelector().getAsString();
- for (const std::string &S : Matches)
- if (S == SelString)
- return true;
- return false;
+ return llvm::is_contained(Matches, Node.getSelector().getAsString());
}
namespace internal {
-bool NotUnaryOperator(const ast_type_traits::DynTypedNode &DynNode,
- ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
+bool NotUnaryOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder,
ArrayRef<DynTypedMatcher> InnerMatchers);
-bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
- ASTMatchFinder *Finder,
+bool AllOfVariadicOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder,
ArrayRef<DynTypedMatcher> InnerMatchers);
-bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
- ASTMatchFinder *Finder,
+bool EachOfVariadicOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder,
ArrayRef<DynTypedMatcher> InnerMatchers);
-bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
- ASTMatchFinder *Finder,
+bool AnyOfVariadicOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder,
ArrayRef<DynTypedMatcher> InnerMatchers);
-bool OptionallyVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
+bool OptionallyVariadicOperator(const DynTypedNode &DynNode,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder,
ArrayRef<DynTypedMatcher> InnerMatchers);
+bool matchesAnyBase(const CXXRecordDecl &Node,
+ const Matcher<CXXBaseSpecifier> &BaseSpecMatcher,
+ ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) {
+ if (!Node.hasDefinition())
+ return false;
+
+ CXXBasePaths Paths;
+ Paths.setOrigin(&Node);
+
+ const auto basePredicate =
+ [Finder, Builder, &BaseSpecMatcher](const CXXBaseSpecifier *BaseSpec,
+ CXXBasePath &IgnoredParam) {
+ BoundNodesTreeBuilder Result(*Builder);
+ if (BaseSpecMatcher.matches(*BaseSpec, Finder, Builder)) {
+ *Builder = std::move(Result);
+ return true;
+ }
+ return false;
+ };
+
+ return Node.lookupInBases(basePredicate, Paths,
+ /*LookupInDependent =*/true);
+}
+
void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) {
if (Bindings.empty())
Bindings.push_back(BoundNodesMap());
@@ -84,7 +105,7 @@ void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) {
namespace {
using VariadicOperatorFunction = bool (*)(
- const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder,
+ const DynTypedNode &DynNode, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers);
template <VariadicOperatorFunction Func>
@@ -93,8 +114,7 @@ public:
VariadicMatcher(std::vector<DynTypedMatcher> InnerMatchers)
: InnerMatchers(std::move(InnerMatchers)) {}
- bool dynMatches(const ast_type_traits::DynTypedNode &DynNode,
- ASTMatchFinder *Finder,
+ bool dynMatches(const DynTypedNode &DynNode, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const override {
return Func(DynNode, Finder, Builder, InnerMatchers);
}
@@ -109,16 +129,14 @@ public:
IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher)
: ID(ID), InnerMatcher(std::move(InnerMatcher)) {}
- bool dynMatches(const ast_type_traits::DynTypedNode &DynNode,
- ASTMatchFinder *Finder,
+ bool dynMatches(const DynTypedNode &DynNode, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const override {
bool Result = InnerMatcher->dynMatches(DynNode, Finder, Builder);
if (Result) Builder->setBinding(ID, DynNode);
return Result;
}
- llvm::Optional<ast_type_traits::TraversalKind>
- TraversalKind() const override {
+ llvm::Optional<clang::TraversalKind> TraversalKind() const override {
return InnerMatcher->TraversalKind();
}
@@ -138,20 +156,45 @@ public:
Retain(); // Reference count will never become zero.
}
- bool dynMatches(const ast_type_traits::DynTypedNode &, ASTMatchFinder *,
+ bool dynMatches(const DynTypedNode &, ASTMatchFinder *,
BoundNodesTreeBuilder *) const override {
return true;
}
};
+/// A matcher that specifies a particular \c TraversalKind.
+///
+/// The kind provided to the constructor overrides any kind that may be
+/// specified by the `InnerMatcher`.
+class DynTraversalMatcherImpl : public DynMatcherInterface {
+public:
+ explicit DynTraversalMatcherImpl(
+ clang::TraversalKind TK,
+ IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher)
+ : TK(TK), InnerMatcher(std::move(InnerMatcher)) {}
+
+ bool dynMatches(const DynTypedNode &DynNode, ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const override {
+ return this->InnerMatcher->dynMatches(DynNode, Finder, Builder);
+ }
+
+ llvm::Optional<clang::TraversalKind> TraversalKind() const override {
+ return TK;
+ }
+
+private:
+ clang::TraversalKind TK;
+ IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher;
+};
+
} // namespace
static llvm::ManagedStatic<TrueMatcherImpl> TrueMatcherInstance;
-DynTypedMatcher DynTypedMatcher::constructVariadic(
- DynTypedMatcher::VariadicOperator Op,
- ast_type_traits::ASTNodeKind SupportedKind,
- std::vector<DynTypedMatcher> InnerMatchers) {
+DynTypedMatcher
+DynTypedMatcher::constructVariadic(DynTypedMatcher::VariadicOperator Op,
+ ASTNodeKind SupportedKind,
+ std::vector<DynTypedMatcher> InnerMatchers) {
assert(!InnerMatchers.empty() && "Array must not be empty.");
assert(llvm::all_of(InnerMatchers,
[SupportedKind](const DynTypedMatcher &M) {
@@ -172,8 +215,8 @@ DynTypedMatcher DynTypedMatcher::constructVariadic(
// invalid types earlier and we can elide the kind checks inside the
// matcher.
for (auto &IM : InnerMatchers) {
- RestrictKind = ast_type_traits::ASTNodeKind::getMostDerivedType(
- RestrictKind, IM.RestrictKind);
+ RestrictKind =
+ ASTNodeKind::getMostDerivedType(RestrictKind, IM.RestrictKind);
}
return DynTypedMatcher(
SupportedKind, RestrictKind,
@@ -204,40 +247,45 @@ DynTypedMatcher DynTypedMatcher::constructVariadic(
llvm_unreachable("Invalid Op value.");
}
-DynTypedMatcher DynTypedMatcher::constructRestrictedWrapper(
- const DynTypedMatcher &InnerMatcher,
- ast_type_traits::ASTNodeKind RestrictKind) {
+DynTypedMatcher
+DynTypedMatcher::constructRestrictedWrapper(const DynTypedMatcher &InnerMatcher,
+ ASTNodeKind RestrictKind) {
DynTypedMatcher Copy = InnerMatcher;
Copy.RestrictKind = RestrictKind;
return Copy;
}
-DynTypedMatcher DynTypedMatcher::trueMatcher(
- ast_type_traits::ASTNodeKind NodeKind) {
+DynTypedMatcher
+DynTypedMatcher::withTraversalKind(ast_type_traits::TraversalKind TK) {
+ auto Copy = *this;
+ Copy.Implementation =
+ new DynTraversalMatcherImpl(TK, std::move(Copy.Implementation));
+ return Copy;
+}
+
+DynTypedMatcher DynTypedMatcher::trueMatcher(ASTNodeKind NodeKind) {
return DynTypedMatcher(NodeKind, NodeKind, &*TrueMatcherInstance);
}
-bool DynTypedMatcher::canMatchNodesOfKind(
- ast_type_traits::ASTNodeKind Kind) const {
+bool DynTypedMatcher::canMatchNodesOfKind(ASTNodeKind Kind) const {
return RestrictKind.isBaseOf(Kind);
}
-DynTypedMatcher DynTypedMatcher::dynCastTo(
- const ast_type_traits::ASTNodeKind Kind) const {
+DynTypedMatcher DynTypedMatcher::dynCastTo(const ASTNodeKind Kind) const {
auto Copy = *this;
Copy.SupportedKind = Kind;
- Copy.RestrictKind =
- ast_type_traits::ASTNodeKind::getMostDerivedType(Kind, RestrictKind);
+ Copy.RestrictKind = ASTNodeKind::getMostDerivedType(Kind, RestrictKind);
return Copy;
}
-bool DynTypedMatcher::matches(const ast_type_traits::DynTypedNode &DynNode,
+bool DynTypedMatcher::matches(const DynTypedNode &DynNode,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
TraversalKindScope RAII(Finder->getASTContext(),
Implementation->TraversalKind());
- auto N = Finder->getASTContext().traverseIgnored(DynNode);
+ auto N =
+ Finder->getASTContext().getParentMapContext().traverseIgnored(DynNode);
if (RestrictKind.isBaseOf(N.getNodeKind()) &&
Implementation->dynMatches(N, Finder, Builder)) {
@@ -250,13 +298,14 @@ bool DynTypedMatcher::matches(const ast_type_traits::DynTypedNode &DynNode,
return false;
}
-bool DynTypedMatcher::matchesNoKindCheck(
- const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder,
- BoundNodesTreeBuilder *Builder) const {
+bool DynTypedMatcher::matchesNoKindCheck(const DynTypedNode &DynNode,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
TraversalKindScope raii(Finder->getASTContext(),
Implementation->TraversalKind());
- auto N = Finder->getASTContext().traverseIgnored(DynNode);
+ auto N =
+ Finder->getASTContext().getParentMapContext().traverseIgnored(DynNode);
assert(RestrictKind.isBaseOf(N.getNodeKind()));
if (Implementation->dynMatches(N, Finder, Builder)) {
@@ -277,10 +326,10 @@ llvm::Optional<DynTypedMatcher> DynTypedMatcher::tryBind(StringRef ID) const {
return std::move(Result);
}
-bool DynTypedMatcher::canConvertTo(ast_type_traits::ASTNodeKind To) const {
+bool DynTypedMatcher::canConvertTo(ASTNodeKind To) const {
const auto From = getSupportedKind();
- auto QualKind = ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>();
- auto TypeKind = ast_type_traits::ASTNodeKind::getFromNodeKind<Type>();
+ auto QualKind = ASTNodeKind::getFromNodeKind<QualType>();
+ auto TypeKind = ASTNodeKind::getFromNodeKind<Type>();
/// Mimic the implicit conversions of Matcher<>.
/// - From Matcher<Type> to Matcher<QualType>
if (From.isSame(TypeKind) && To.isSame(QualKind)) return true;
@@ -292,8 +341,8 @@ void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) {
Bindings.append(Other.Bindings.begin(), Other.Bindings.end());
}
-bool NotUnaryOperator(const ast_type_traits::DynTypedNode &DynNode,
- ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
+bool NotUnaryOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder,
ArrayRef<DynTypedMatcher> InnerMatchers) {
if (InnerMatchers.size() != 1)
return false;
@@ -312,22 +361,18 @@ bool NotUnaryOperator(const ast_type_traits::DynTypedNode &DynNode,
return !InnerMatchers[0].matches(DynNode, Finder, &Discard);
}
-bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
- ASTMatchFinder *Finder,
+bool AllOfVariadicOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder,
ArrayRef<DynTypedMatcher> InnerMatchers) {
// allOf leads to one matcher for each alternative in the first
// matcher combined with each alternative in the second matcher.
// Thus, we can reuse the same Builder.
- for (const DynTypedMatcher &InnerMatcher : InnerMatchers) {
- if (!InnerMatcher.matchesNoKindCheck(DynNode, Finder, Builder))
- return false;
- }
- return true;
+ return llvm::all_of(InnerMatchers, [&](const DynTypedMatcher &InnerMatcher) {
+ return InnerMatcher.matchesNoKindCheck(DynNode, Finder, Builder);
+ });
}
-bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
- ASTMatchFinder *Finder,
+bool EachOfVariadicOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder,
ArrayRef<DynTypedMatcher> InnerMatchers) {
BoundNodesTreeBuilder Result;
@@ -343,8 +388,7 @@ bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
return Matched;
}
-bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
- ASTMatchFinder *Finder,
+bool AnyOfVariadicOperator(const DynTypedNode &DynNode, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder,
ArrayRef<DynTypedMatcher> InnerMatchers) {
for (const DynTypedMatcher &InnerMatcher : InnerMatchers) {
@@ -357,31 +401,31 @@ bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
return false;
}
-bool OptionallyVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
+bool OptionallyVariadicOperator(const DynTypedNode &DynNode,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder,
ArrayRef<DynTypedMatcher> InnerMatchers) {
- BoundNodesTreeBuilder Result;
- for (const DynTypedMatcher &InnerMatcher : InnerMatchers) {
- BoundNodesTreeBuilder BuilderInner(*Builder);
- if (InnerMatcher.matches(DynNode, Finder, &BuilderInner))
- Result.addMatch(BuilderInner);
- }
- *Builder = std::move(Result);
+ if (InnerMatchers.size() != 1)
+ return false;
+
+ BoundNodesTreeBuilder Result(*Builder);
+ if (InnerMatchers[0].matches(DynNode, Finder, &Result))
+ *Builder = std::move(Result);
return true;
}
inline static
std::vector<std::string> vectorFromRefs(ArrayRef<const StringRef *> NameRefs) {
std::vector<std::string> Names;
+ Names.reserve(NameRefs.size());
for (auto *Name : NameRefs)
Names.emplace_back(*Name);
return Names;
}
Matcher<NamedDecl> hasAnyNameFunc(ArrayRef<const StringRef *> NameRefs) {
- std::vector<std::string> Names = vectorFromRefs(NameRefs);
- return internal::Matcher<NamedDecl>(new internal::HasNameMatcher(Names));
+ return internal::Matcher<NamedDecl>(
+ new internal::HasNameMatcher(vectorFromRefs(NameRefs)));
}
Matcher<ObjCMessageExpr> hasAnySelectorFunc(
@@ -389,10 +433,18 @@ Matcher<ObjCMessageExpr> hasAnySelectorFunc(
return hasAnySelectorMatcher(vectorFromRefs(NameRefs));
}
+HasOpNameMatcher hasAnyOperatorNameFunc(ArrayRef<const StringRef *> NameRefs) {
+ return HasOpNameMatcher(vectorFromRefs(NameRefs));
+}
+
+HasOverloadOpNameMatcher
+hasAnyOverloadedOperatorNameFunc(ArrayRef<const StringRef *> NameRefs) {
+ return HasOverloadOpNameMatcher(vectorFromRefs(NameRefs));
+}
+
HasNameMatcher::HasNameMatcher(std::vector<std::string> N)
- : UseUnqualifiedMatch(std::all_of(
- N.begin(), N.end(),
- [](StringRef Name) { return Name.find("::") == Name.npos; })),
+ : UseUnqualifiedMatch(llvm::all_of(
+ N, [](StringRef Name) { return Name.find("::") == Name.npos; })),
Names(std::move(N)) {
#ifndef NDEBUG
for (StringRef Name : Names)
@@ -450,6 +502,7 @@ namespace {
class PatternSet {
public:
PatternSet(ArrayRef<std::string> Names) {
+ Patterns.reserve(Names.size());
for (StringRef Name : Names)
Patterns.push_back({Name, Name.startswith("::")});
}
@@ -474,10 +527,10 @@ public:
/// A match will be a pattern that was fully consumed, that also matches the
/// 'fully qualified' requirement.
bool foundMatch(bool AllowFullyQualified) const {
- for (auto& P: Patterns)
- if (P.P.empty() && (AllowFullyQualified || !P.IsFullyQualified))
- return true;
- return false;
+ return llvm::any_of(Patterns, [&](const Pattern &Pattern) {
+ return Pattern.P.empty() &&
+ (AllowFullyQualified || !Pattern.IsFullyQualified);
+ });
}
private:
@@ -523,7 +576,13 @@ bool HasNameMatcher::matchesNodeFullFast(const NamedDecl &Node) const {
if (Ctx->isFunctionOrMethod())
return Patterns.foundMatch(/*AllowFullyQualified=*/false);
- for (; Ctx && isa<NamedDecl>(Ctx); Ctx = Ctx->getParent()) {
+ for (; Ctx; Ctx = Ctx->getParent()) {
+ // Linkage Spec can just be ignored
+ // FIXME: Any other DeclContext kinds that can be safely disregarded
+ if (isa<LinkageSpecDecl>(Ctx))
+ continue;
+ if (!isa<NamedDecl>(Ctx))
+ break;
if (Patterns.foundMatch(/*AllowFullyQualified=*/false))
return true;
@@ -592,6 +651,52 @@ bool HasNameMatcher::matchesNode(const NamedDecl &Node) const {
return matchesNodeFullFast(Node);
}
+// Checks whether \p Loc points to a token with source text of \p TokenText.
+static bool isTokenAtLoc(const SourceManager &SM, const LangOptions &LangOpts,
+ StringRef Text, SourceLocation Loc) {
+ llvm::SmallString<16> Buffer;
+ bool Invalid = false;
+ // Since `Loc` may point into an expansion buffer, which has no corresponding
+ // source, we need to look at the spelling location to read the actual source.
+ StringRef TokenText = Lexer::getSpelling(SM.getSpellingLoc(Loc), Buffer, SM,
+ LangOpts, &Invalid);
+ return !Invalid && Text == TokenText;
+}
+
+llvm::Optional<SourceLocation>
+getExpansionLocOfMacro(StringRef MacroName, SourceLocation Loc,
+ const ASTContext &Context) {
+ auto &SM = Context.getSourceManager();
+ const LangOptions &LangOpts = Context.getLangOpts();
+ while (Loc.isMacroID()) {
+ SrcMgr::ExpansionInfo Expansion =
+ SM.getSLocEntry(SM.getFileID(Loc)).getExpansion();
+ if (Expansion.isMacroArgExpansion())
+ // Check macro argument for an expansion of the given macro. For example,
+ // `F(G(3))`, where `MacroName` is `G`.
+ if (llvm::Optional<SourceLocation> ArgLoc = getExpansionLocOfMacro(
+ MacroName, Expansion.getSpellingLoc(), Context))
+ return ArgLoc;
+ Loc = Expansion.getExpansionLocStart();
+ if (isTokenAtLoc(SM, LangOpts, MacroName, Loc))
+ return Loc;
+ }
+ return llvm::None;
+}
+
+std::shared_ptr<llvm::Regex> createAndVerifyRegex(StringRef Regex,
+ llvm::Regex::RegexFlags Flags,
+ StringRef MatcherID) {
+ assert(!Regex.empty() && "Empty regex string");
+ auto SharedRegex = std::make_shared<llvm::Regex>(Regex, Flags);
+ std::string Error;
+ if (!SharedRegex->isValid(Error)) {
+ llvm::WithColor::error()
+ << "building matcher '" << MatcherID << "': " << Error << "\n";
+ llvm::WithColor::note() << " input was '" << Regex << "'\n";
+ }
+ return SharedRegex;
+}
} // end namespace internal
const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCAutoreleasePoolStmt>
@@ -647,6 +752,7 @@ const internal::VariadicDynCastAllOfMatcher<Decl, CXXDestructorDecl>
const internal::VariadicDynCastAllOfMatcher<Decl, EnumDecl> enumDecl;
const internal::VariadicDynCastAllOfMatcher<Decl, EnumConstantDecl>
enumConstantDecl;
+const internal::VariadicDynCastAllOfMatcher<Decl, TagDecl> tagDecl;
const internal::VariadicDynCastAllOfMatcher<Decl, CXXMethodDecl> cxxMethodDecl;
const internal::VariadicDynCastAllOfMatcher<Decl, CXXConversionDecl>
cxxConversionDecl;
@@ -727,6 +833,8 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, MaterializeTemporaryExpr>
materializeTemporaryExpr;
const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNewExpr> cxxNewExpr;
const internal::VariadicDynCastAllOfMatcher<Stmt, CXXDeleteExpr> cxxDeleteExpr;
+const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNoexceptExpr>
+ cxxNoexceptExpr;
const internal::VariadicDynCastAllOfMatcher<Stmt, ArraySubscriptExpr>
arraySubscriptExpr;
const internal::VariadicDynCastAllOfMatcher<Stmt, CXXDefaultArgExpr>
@@ -768,6 +876,8 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, IntegerLiteral>
integerLiteral;
const internal::VariadicDynCastAllOfMatcher<Stmt, FloatingLiteral> floatLiteral;
const internal::VariadicDynCastAllOfMatcher<Stmt, ImaginaryLiteral> imaginaryLiteral;
+const internal::VariadicDynCastAllOfMatcher<Stmt, FixedPointLiteral>
+ fixedPointLiteral;
const internal::VariadicDynCastAllOfMatcher<Stmt, UserDefinedLiteral>
userDefinedLiteral;
const internal::VariadicDynCastAllOfMatcher<Stmt, CompoundLiteralExpr>
@@ -821,12 +931,18 @@ const internal::VariadicOperatorMatcherFunc<
const internal::VariadicOperatorMatcherFunc<
2, std::numeric_limits<unsigned>::max()>
allOf = {internal::DynTypedMatcher::VO_AllOf};
-const internal::VariadicOperatorMatcherFunc<
- 1, std::numeric_limits<unsigned>::max()>
- optionally = {internal::DynTypedMatcher::VO_Optionally};
+const internal::VariadicOperatorMatcherFunc<1, 1> optionally = {
+ internal::DynTypedMatcher::VO_Optionally};
const internal::VariadicFunction<internal::Matcher<NamedDecl>, StringRef,
internal::hasAnyNameFunc>
hasAnyName = {};
+
+const internal::VariadicFunction<internal::HasOpNameMatcher, StringRef,
+ internal::hasAnyOperatorNameFunc>
+ hasAnyOperatorName = {};
+const internal::VariadicFunction<internal::HasOverloadOpNameMatcher, StringRef,
+ internal::hasAnyOverloadedOperatorNameFunc>
+ hasAnyOverloadedOperatorName = {};
const internal::VariadicFunction<internal::Matcher<ObjCMessageExpr>, StringRef,
internal::hasAnySelectorFunc>
hasAnySelector = {};
@@ -858,6 +974,8 @@ const AstTypeMatcher<BuiltinType> builtinType;
const AstTypeMatcher<ArrayType> arrayType;
const AstTypeMatcher<ComplexType> complexType;
const AstTypeMatcher<ConstantArrayType> constantArrayType;
+const AstTypeMatcher<DeducedTemplateSpecializationType>
+ deducedTemplateSpecializationType;
const AstTypeMatcher<DependentSizedArrayType> dependentSizedArrayType;
const AstTypeMatcher<IncompleteArrayType> incompleteArrayType;
const AstTypeMatcher<VariableArrayType> variableArrayType;
diff --git a/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp b/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp
index 8656bca870ec5..88c2279afb2e3 100644
--- a/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp
@@ -1,4 +1,4 @@
-//===--- Diagnostics.cpp - Helper class for error diagnostics -----*- C++ -*-===//
+//===--- Diagnostics.cpp - Helper class for error diagnostics ---*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -98,6 +98,8 @@ static StringRef errorTypeToFormatString(Diagnostics::ErrorType Type) {
return "Ambiguous matcher overload.";
case Diagnostics::ET_RegistryValueNotFound:
return "Value not found: $0";
+ case Diagnostics::ET_RegistryUnknownEnumWithReplace:
+ return "Unknown value '$1' for arg $0; did you mean '$2'";
case Diagnostics::ET_ParserStringError:
return "Error parsing string token: <$0>";
diff --git a/clang/lib/ASTMatchers/Dynamic/Marshallers.cpp b/clang/lib/ASTMatchers/Dynamic/Marshallers.cpp
new file mode 100644
index 0000000000000..989ee0fa75cdd
--- /dev/null
+++ b/clang/lib/ASTMatchers/Dynamic/Marshallers.cpp
@@ -0,0 +1,172 @@
+//===--- Marshallers.cpp ----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Marshallers.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Regex.h"
+#include <string>
+
+static llvm::Optional<std::string>
+getBestGuess(llvm::StringRef Search, llvm::ArrayRef<llvm::StringRef> Allowed,
+ llvm::StringRef DropPrefix = "", unsigned MaxEditDistance = 3) {
+ if (MaxEditDistance != ~0U)
+ ++MaxEditDistance;
+ llvm::StringRef Res;
+ for (const llvm::StringRef &Item : Allowed) {
+ if (Item.equals_lower(Search)) {
+ assert(!Item.equals(Search) && "This should be handled earlier on.");
+ MaxEditDistance = 1;
+ Res = Item;
+ continue;
+ }
+ unsigned Distance = Item.edit_distance(Search);
+ if (Distance < MaxEditDistance) {
+ MaxEditDistance = Distance;
+ Res = Item;
+ }
+ }
+ if (!Res.empty())
+ return Res.str();
+ if (!DropPrefix.empty()) {
+ --MaxEditDistance; // Treat dropping the prefix as 1 edit
+ for (const llvm::StringRef &Item : Allowed) {
+ auto NoPrefix = Item;
+ if (!NoPrefix.consume_front(DropPrefix))
+ continue;
+ if (NoPrefix.equals_lower(Search)) {
+ if (NoPrefix.equals(Search))
+ return Item.str();
+ MaxEditDistance = 1;
+ Res = Item;
+ continue;
+ }
+ unsigned Distance = NoPrefix.edit_distance(Search);
+ if (Distance < MaxEditDistance) {
+ MaxEditDistance = Distance;
+ Res = Item;
+ }
+ }
+ if (!Res.empty())
+ return Res.str();
+ }
+ return llvm::None;
+}
+
+llvm::Optional<std::string>
+clang::ast_matchers::dynamic::internal::ArgTypeTraits<
+ clang::attr::Kind>::getBestGuess(const VariantValue &Value) {
+ static constexpr llvm::StringRef Allowed[] = {
+#define ATTR(X) "attr::" #X,
+#include "clang/Basic/AttrList.inc"
+ };
+ if (Value.isString())
+ return ::getBestGuess(Value.getString(), llvm::makeArrayRef(Allowed),
+ "attr::");
+ return llvm::None;
+}
+
+llvm::Optional<std::string>
+clang::ast_matchers::dynamic::internal::ArgTypeTraits<
+ clang::CastKind>::getBestGuess(const VariantValue &Value) {
+ static constexpr llvm::StringRef Allowed[] = {
+#define CAST_OPERATION(Name) "CK_" #Name,
+#include "clang/AST/OperationKinds.def"
+ };
+ if (Value.isString())
+ return ::getBestGuess(Value.getString(), llvm::makeArrayRef(Allowed),
+ "CK_");
+ return llvm::None;
+}
+
+llvm::Optional<std::string>
+clang::ast_matchers::dynamic::internal::ArgTypeTraits<
+ clang::OpenMPClauseKind>::getBestGuess(const VariantValue &Value) {
+ static constexpr llvm::StringRef Allowed[] = {
+#define OMP_CLAUSE_CLASS(Enum, Str, Class) #Enum,
+#include "llvm/Frontend/OpenMP/OMPKinds.def"
+ };
+ if (Value.isString())
+ return ::getBestGuess(Value.getString(), llvm::makeArrayRef(Allowed),
+ "OMPC_");
+ return llvm::None;
+}
+
+llvm::Optional<std::string>
+clang::ast_matchers::dynamic::internal::ArgTypeTraits<
+ clang::UnaryExprOrTypeTrait>::getBestGuess(const VariantValue &Value) {
+ static constexpr llvm::StringRef Allowed[] = {
+#define UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) "UETT_" #Name,
+#define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) "UETT_" #Name,
+#include "clang/Basic/TokenKinds.def"
+ };
+ if (Value.isString())
+ return ::getBestGuess(Value.getString(), llvm::makeArrayRef(Allowed),
+ "UETT_");
+ return llvm::None;
+}
+
+static constexpr std::pair<llvm::StringRef, llvm::Regex::RegexFlags>
+ RegexMap[] = {
+ {"NoFlags", llvm::Regex::RegexFlags::NoFlags},
+ {"IgnoreCase", llvm::Regex::RegexFlags::IgnoreCase},
+ {"Newline", llvm::Regex::RegexFlags::Newline},
+ {"BasicRegex", llvm::Regex::RegexFlags::BasicRegex},
+};
+
+llvm::Optional<llvm::Regex::RegexFlags> getRegexFlag(llvm::StringRef Flag) {
+ for (const auto &StringFlag : RegexMap) {
+ if (Flag == StringFlag.first)
+ return StringFlag.second;
+ }
+ return llvm::None;
+}
+
+llvm::Optional<llvm::StringRef> getCloseRegexMatch(llvm::StringRef Flag) {
+ for (const auto &StringFlag : RegexMap) {
+ if (Flag.edit_distance(StringFlag.first) < 3)
+ return StringFlag.first;
+ }
+ return llvm::None;
+}
+
+llvm::Optional<llvm::Regex::RegexFlags>
+clang::ast_matchers::dynamic::internal::ArgTypeTraits<
+ llvm::Regex::RegexFlags>::getFlags(llvm::StringRef Flags) {
+ llvm::Optional<llvm::Regex::RegexFlags> Flag;
+ SmallVector<StringRef, 4> Split;
+ Flags.split(Split, '|', -1, false);
+ for (StringRef OrFlag : Split) {
+ if (llvm::Optional<llvm::Regex::RegexFlags> NextFlag =
+ getRegexFlag(OrFlag.trim()))
+ Flag = Flag.getValueOr(llvm::Regex::NoFlags) | *NextFlag;
+ else
+ return None;
+ }
+ return Flag;
+}
+
+llvm::Optional<std::string>
+clang::ast_matchers::dynamic::internal::ArgTypeTraits<
+ llvm::Regex::RegexFlags>::getBestGuess(const VariantValue &Value) {
+ if (!Value.isString())
+ return llvm::None;
+ SmallVector<StringRef, 4> Split;
+ llvm::StringRef(Value.getString()).split(Split, '|', -1, false);
+ for (llvm::StringRef &Flag : Split) {
+ if (llvm::Optional<llvm::StringRef> BestGuess =
+ getCloseRegexMatch(Flag.trim()))
+ Flag = *BestGuess;
+ else
+ return None;
+ }
+ if (Split.empty())
+ return None;
+ return llvm::join(Split, " | ");
+}
diff --git a/clang/lib/ASTMatchers/Dynamic/Marshallers.h b/clang/lib/ASTMatchers/Dynamic/Marshallers.h
index 9f46108d1848d..33f6d1e4155cb 100644
--- a/clang/lib/ASTMatchers/Dynamic/Marshallers.h
+++ b/clang/lib/ASTMatchers/Dynamic/Marshallers.h
@@ -27,12 +27,15 @@
#include "clang/Basic/AttrKinds.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/OpenMPKinds.h"
+#include "clang/Basic/TypeTraits.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Regex.h"
#include <cassert>
#include <cstddef>
#include <iterator>
@@ -64,6 +67,10 @@ template <> struct ArgTypeTraits<std::string> {
static ArgKind getKind() {
return ArgKind(ArgKind::AK_String);
}
+
+ static llvm::Optional<std::string> getBestGuess(const VariantValue &) {
+ return llvm::None;
+ }
};
template <>
@@ -80,7 +87,11 @@ template <class T> struct ArgTypeTraits<ast_matchers::internal::Matcher<T>> {
}
static ArgKind getKind() {
- return ArgKind(ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
+ return ArgKind(ASTNodeKind::getFromNodeKind<T>());
+ }
+
+ static llvm::Optional<std::string> getBestGuess(const VariantValue &) {
+ return llvm::None;
}
};
@@ -94,6 +105,10 @@ template <> struct ArgTypeTraits<bool> {
static ArgKind getKind() {
return ArgKind(ArgKind::AK_Boolean);
}
+
+ static llvm::Optional<std::string> getBestGuess(const VariantValue &) {
+ return llvm::None;
+ }
};
template <> struct ArgTypeTraits<double> {
@@ -106,6 +121,10 @@ template <> struct ArgTypeTraits<double> {
static ArgKind getKind() {
return ArgKind(ArgKind::AK_Double);
}
+
+ static llvm::Optional<std::string> getBestGuess(const VariantValue &) {
+ return llvm::None;
+ }
};
template <> struct ArgTypeTraits<unsigned> {
@@ -118,6 +137,10 @@ template <> struct ArgTypeTraits<unsigned> {
static ArgKind getKind() {
return ArgKind(ArgKind::AK_Unsigned);
}
+
+ static llvm::Optional<std::string> getBestGuess(const VariantValue &) {
+ return llvm::None;
+ }
};
template <> struct ArgTypeTraits<attr::Kind> {
@@ -141,13 +164,15 @@ public:
static ArgKind getKind() {
return ArgKind(ArgKind::AK_String);
}
+
+ static llvm::Optional<std::string> getBestGuess(const VariantValue &Value);
};
template <> struct ArgTypeTraits<CastKind> {
private:
static Optional<CastKind> getCastKind(llvm::StringRef AttrKind) {
return llvm::StringSwitch<Optional<CastKind>>(AttrKind)
-#define CAST_OPERATION(Name) .Case( #Name, CK_##Name)
+#define CAST_OPERATION(Name) .Case("CK_" #Name, CK_##Name)
#include "clang/AST/OperationKinds.def"
.Default(llvm::None);
}
@@ -164,15 +189,34 @@ public:
static ArgKind getKind() {
return ArgKind(ArgKind::AK_String);
}
+
+ static llvm::Optional<std::string> getBestGuess(const VariantValue &Value);
+};
+
+template <> struct ArgTypeTraits<llvm::Regex::RegexFlags> {
+private:
+ static Optional<llvm::Regex::RegexFlags> getFlags(llvm::StringRef Flags);
+
+public:
+ static bool is(const VariantValue &Value) {
+ return Value.isString() && getFlags(Value.getString());
+ }
+
+ static llvm::Regex::RegexFlags get(const VariantValue &Value) {
+ return *getFlags(Value.getString());
+ }
+
+ static ArgKind getKind() { return ArgKind(ArgKind::AK_String); }
+
+ static llvm::Optional<std::string> getBestGuess(const VariantValue &Value);
};
template <> struct ArgTypeTraits<OpenMPClauseKind> {
private:
static Optional<OpenMPClauseKind> getClauseKind(llvm::StringRef ClauseKind) {
return llvm::StringSwitch<Optional<OpenMPClauseKind>>(ClauseKind)
-#define OPENMP_CLAUSE(TextualSpelling, Class) \
- .Case("OMPC_" #TextualSpelling, OMPC_##TextualSpelling)
-#include "clang/Basic/OpenMPKinds.def"
+#define OMP_CLAUSE_CLASS(Enum, Str, Class) .Case(#Enum, llvm::omp::Clause::Enum)
+#include "llvm/Frontend/OpenMP/OMPKinds.def"
.Default(llvm::None);
}
@@ -186,6 +230,35 @@ public:
}
static ArgKind getKind() { return ArgKind(ArgKind::AK_String); }
+
+ static llvm::Optional<std::string> getBestGuess(const VariantValue &Value);
+};
+
+template <> struct ArgTypeTraits<UnaryExprOrTypeTrait> {
+private:
+ static Optional<UnaryExprOrTypeTrait>
+ getUnaryOrTypeTraitKind(llvm::StringRef ClauseKind) {
+ return llvm::StringSwitch<Optional<UnaryExprOrTypeTrait>>(ClauseKind)
+#define UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) \
+ .Case("UETT_" #Name, UETT_##Name)
+#define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) \
+ .Case("UETT_" #Name, UETT_##Name)
+#include "clang/Basic/TokenKinds.def"
+ .Default(llvm::None);
+ }
+
+public:
+ static bool is(const VariantValue &Value) {
+ return Value.isString() && getUnaryOrTypeTraitKind(Value.getString());
+ }
+
+ static UnaryExprOrTypeTrait get(const VariantValue &Value) {
+ return *getUnaryOrTypeTraitKind(Value.getString());
+ }
+
+ static ArgKind getKind() { return ArgKind(ArgKind::AK_String); }
+
+ static llvm::Optional<std::string> getBestGuess(const VariantValue &Value);
};
/// Matcher descriptor interface.
@@ -211,7 +284,7 @@ public:
/// set of argument types accepted for argument \p ArgNo to \p ArgKinds.
// FIXME: We should provide the ability to constrain the output of this
// function based on the types of other matcher arguments.
- virtual void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo,
+ virtual void getArgKinds(ASTNodeKind ThisKind, unsigned ArgNo,
std::vector<ArgKind> &ArgKinds) const = 0;
/// Returns whether this matcher is convertible to the given type. If it is
@@ -221,20 +294,19 @@ public:
/// same matcher overload. Zero specificity indicates that this conversion
/// would produce a trivial matcher that will either always or never match.
/// Such matchers are excluded from code completion results.
- virtual bool isConvertibleTo(
- ast_type_traits::ASTNodeKind Kind, unsigned *Specificity = nullptr,
- ast_type_traits::ASTNodeKind *LeastDerivedKind = nullptr) const = 0;
+ virtual bool
+ isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity = nullptr,
+ ASTNodeKind *LeastDerivedKind = nullptr) const = 0;
/// Returns whether the matcher will, given a matcher of any type T, yield a
/// matcher of type T.
virtual bool isPolymorphic() const { return false; }
};
-inline bool isRetKindConvertibleTo(
- ArrayRef<ast_type_traits::ASTNodeKind> RetKinds,
- ast_type_traits::ASTNodeKind Kind, unsigned *Specificity,
- ast_type_traits::ASTNodeKind *LeastDerivedKind) {
- for (const ast_type_traits::ASTNodeKind &NodeKind : RetKinds) {
+inline bool isRetKindConvertibleTo(ArrayRef<ASTNodeKind> RetKinds,
+ ASTNodeKind Kind, unsigned *Specificity,
+ ASTNodeKind *LeastDerivedKind) {
+ for (const ASTNodeKind &NodeKind : RetKinds) {
if (ArgKind(NodeKind).isConvertibleTo(Kind, Specificity)) {
if (LeastDerivedKind)
*LeastDerivedKind = NodeKind;
@@ -264,10 +336,10 @@ public:
/// \param RetKinds The list of matcher types to which the matcher is
/// convertible.
/// \param ArgKinds The types of the arguments this matcher takes.
- FixedArgCountMatcherDescriptor(
- MarshallerType Marshaller, void (*Func)(), StringRef MatcherName,
- ArrayRef<ast_type_traits::ASTNodeKind> RetKinds,
- ArrayRef<ArgKind> ArgKinds)
+ FixedArgCountMatcherDescriptor(MarshallerType Marshaller, void (*Func)(),
+ StringRef MatcherName,
+ ArrayRef<ASTNodeKind> RetKinds,
+ ArrayRef<ArgKind> ArgKinds)
: Marshaller(Marshaller), Func(Func), MatcherName(MatcherName),
RetKinds(RetKinds.begin(), RetKinds.end()),
ArgKinds(ArgKinds.begin(), ArgKinds.end()) {}
@@ -281,14 +353,13 @@ public:
bool isVariadic() const override { return false; }
unsigned getNumArgs() const override { return ArgKinds.size(); }
- void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo,
+ void getArgKinds(ASTNodeKind ThisKind, unsigned ArgNo,
std::vector<ArgKind> &Kinds) const override {
Kinds.push_back(ArgKinds[ArgNo]);
}
- bool isConvertibleTo(
- ast_type_traits::ASTNodeKind Kind, unsigned *Specificity,
- ast_type_traits::ASTNodeKind *LeastDerivedKind) const override {
+ bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity,
+ ASTNodeKind *LeastDerivedKind) const override {
return isRetKindConvertibleTo(RetKinds, Kind, Specificity,
LeastDerivedKind);
}
@@ -297,7 +368,7 @@ private:
const MarshallerType Marshaller;
void (* const Func)();
const std::string MatcherName;
- const std::vector<ast_type_traits::ASTNodeKind> RetKinds;
+ const std::vector<ASTNodeKind> RetKinds;
const std::vector<ArgKind> ArgKinds;
};
@@ -321,7 +392,7 @@ static void mergePolyMatchers(const PolyMatcher &Poly,
/// polymorphic matcher. For the former, we just construct the VariantMatcher.
/// For the latter, we instantiate all the possible Matcher<T> of the poly
/// matcher.
-static VariantMatcher outvalueToVariantMatcher(const DynTypedMatcher &Matcher) {
+inline VariantMatcher outvalueToVariantMatcher(const DynTypedMatcher &Matcher) {
return VariantMatcher::SingleMatcher(Matcher);
}
@@ -336,36 +407,35 @@ static VariantMatcher outvalueToVariantMatcher(const T &PolyMatcher,
}
template <typename T>
-inline void buildReturnTypeVectorFromTypeList(
- std::vector<ast_type_traits::ASTNodeKind> &RetTypes) {
- RetTypes.push_back(
- ast_type_traits::ASTNodeKind::getFromNodeKind<typename T::head>());
+inline void
+buildReturnTypeVectorFromTypeList(std::vector<ASTNodeKind> &RetTypes) {
+ RetTypes.push_back(ASTNodeKind::getFromNodeKind<typename T::head>());
buildReturnTypeVectorFromTypeList<typename T::tail>(RetTypes);
}
template <>
inline void
buildReturnTypeVectorFromTypeList<ast_matchers::internal::EmptyTypeList>(
- std::vector<ast_type_traits::ASTNodeKind> &RetTypes) {}
+ std::vector<ASTNodeKind> &RetTypes) {}
template <typename T>
struct BuildReturnTypeVector {
- static void build(std::vector<ast_type_traits::ASTNodeKind> &RetTypes) {
+ static void build(std::vector<ASTNodeKind> &RetTypes) {
buildReturnTypeVectorFromTypeList<typename T::ReturnTypes>(RetTypes);
}
};
template <typename T>
struct BuildReturnTypeVector<ast_matchers::internal::Matcher<T>> {
- static void build(std::vector<ast_type_traits::ASTNodeKind> &RetTypes) {
- RetTypes.push_back(ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
+ static void build(std::vector<ASTNodeKind> &RetTypes) {
+ RetTypes.push_back(ASTNodeKind::getFromNodeKind<T>());
}
};
template <typename T>
struct BuildReturnTypeVector<ast_matchers::internal::BindableMatcher<T>> {
- static void build(std::vector<ast_type_traits::ASTNodeKind> &RetTypes) {
- RetTypes.push_back(ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
+ static void build(std::vector<ASTNodeKind> &RetTypes) {
+ RetTypes.push_back(ASTNodeKind::getFromNodeKind<T>());
}
};
@@ -439,14 +509,13 @@ public:
bool isVariadic() const override { return true; }
unsigned getNumArgs() const override { return 0; }
- void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo,
+ void getArgKinds(ASTNodeKind ThisKind, unsigned ArgNo,
std::vector<ArgKind> &Kinds) const override {
Kinds.push_back(ArgsKind);
}
- bool isConvertibleTo(
- ast_type_traits::ASTNodeKind Kind, unsigned *Specificity,
- ast_type_traits::ASTNodeKind *LeastDerivedKind) const override {
+ bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity,
+ ASTNodeKind *LeastDerivedKind) const override {
return isRetKindConvertibleTo(RetKinds, Kind, Specificity,
LeastDerivedKind);
}
@@ -454,7 +523,7 @@ public:
private:
const RunFunc Func;
const std::string MatcherName;
- std::vector<ast_type_traits::ASTNodeKind> RetKinds;
+ std::vector<ASTNodeKind> RetKinds;
const ArgKind ArgsKind;
};
@@ -466,12 +535,10 @@ public:
ast_matchers::internal::VariadicDynCastAllOfMatcher<BaseT, DerivedT> Func,
StringRef MatcherName)
: VariadicFuncMatcherDescriptor(Func, MatcherName),
- DerivedKind(ast_type_traits::ASTNodeKind::getFromNodeKind<DerivedT>()) {
- }
+ DerivedKind(ASTNodeKind::getFromNodeKind<DerivedT>()) {}
- bool
- isConvertibleTo(ast_type_traits::ASTNodeKind Kind, unsigned *Specificity,
- ast_type_traits::ASTNodeKind *LeastDerivedKind) const override {
+ bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity,
+ ASTNodeKind *LeastDerivedKind) const override {
// If Kind is not a base of DerivedKind, either DerivedKind is a base of
// Kind (in which case the match will always succeed) or Kind and
// DerivedKind are unrelated (in which case it will always fail), so set
@@ -489,7 +556,7 @@ public:
}
private:
- const ast_type_traits::ASTNodeKind DerivedKind;
+ const ASTNodeKind DerivedKind;
};
/// Helper macros to check the arguments on all marshaller functions.
@@ -502,9 +569,16 @@ private:
#define CHECK_ARG_TYPE(index, type) \
if (!ArgTypeTraits<type>::is(Args[index].Value)) { \
- Error->addError(Args[index].Range, Error->ET_RegistryWrongArgType) \
- << (index + 1) << ArgTypeTraits<type>::getKind().asString() \
- << Args[index].Value.getTypeAsString(); \
+ if (llvm::Optional<std::string> BestGuess = \
+ ArgTypeTraits<type>::getBestGuess(Args[index].Value)) { \
+ Error->addError(Args[index].Range, \
+ Error->ET_RegistryUnknownEnumWithReplace) \
+ << index + 1 << Args[index].Value.getString() << *BestGuess; \
+ } else { \
+ Error->addError(Args[index].Range, Error->ET_RegistryWrongArgType) \
+ << (index + 1) << ArgTypeTraits<type>::getKind().asString() \
+ << Args[index].Value.getTypeAsString(); \
+ } \
return VariantMatcher(); \
}
@@ -635,7 +709,7 @@ public:
return Overload0NumArgs;
}
- void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo,
+ void getArgKinds(ASTNodeKind ThisKind, unsigned ArgNo,
std::vector<ArgKind> &Kinds) const override {
for (const auto &O : Overloads) {
if (O->isConvertibleTo(ThisKind))
@@ -643,9 +717,8 @@ public:
}
}
- bool isConvertibleTo(
- ast_type_traits::ASTNodeKind Kind, unsigned *Specificity,
- ast_type_traits::ASTNodeKind *LeastDerivedKind) const override {
+ bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity,
+ ASTNodeKind *LeastDerivedKind) const override {
for (const auto &O : Overloads) {
if (O->isConvertibleTo(Kind, Specificity, LeastDerivedKind))
return true;
@@ -657,6 +730,71 @@ private:
std::vector<std::unique_ptr<MatcherDescriptor>> Overloads;
};
+template <typename ReturnType>
+class RegexMatcherDescriptor : public MatcherDescriptor {
+public:
+ RegexMatcherDescriptor(ReturnType (*WithFlags)(StringRef,
+ llvm::Regex::RegexFlags),
+ ReturnType (*NoFlags)(StringRef),
+ ArrayRef<ASTNodeKind> RetKinds)
+ : WithFlags(WithFlags), NoFlags(NoFlags),
+ RetKinds(RetKinds.begin(), RetKinds.end()) {}
+ bool isVariadic() const override { return true; }
+ unsigned getNumArgs() const override { return 0; }
+
+ void getArgKinds(ASTNodeKind ThisKind, unsigned ArgNo,
+ std::vector<ArgKind> &Kinds) const override {
+ assert(ArgNo < 2);
+ Kinds.push_back(ArgKind::AK_String);
+ }
+
+ bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity,
+ ASTNodeKind *LeastDerivedKind) const override {
+ return isRetKindConvertibleTo(RetKinds, Kind, Specificity,
+ LeastDerivedKind);
+ }
+
+ VariantMatcher create(SourceRange NameRange, ArrayRef<ParserValue> Args,
+ Diagnostics *Error) const override {
+ if (Args.size() < 1 || Args.size() > 2) {
+ Error->addError(NameRange, Diagnostics::ET_RegistryWrongArgCount)
+ << "1 or 2" << Args.size();
+ return VariantMatcher();
+ }
+ if (!ArgTypeTraits<StringRef>::is(Args[0].Value)) {
+ Error->addError(Args[0].Range, Error->ET_RegistryWrongArgType)
+ << 1 << ArgTypeTraits<StringRef>::getKind().asString()
+ << Args[0].Value.getTypeAsString();
+ return VariantMatcher();
+ }
+ if (Args.size() == 1) {
+ return outvalueToVariantMatcher(
+ NoFlags(ArgTypeTraits<StringRef>::get(Args[0].Value)));
+ }
+ if (!ArgTypeTraits<llvm::Regex::RegexFlags>::is(Args[1].Value)) {
+ if (llvm::Optional<std::string> BestGuess =
+ ArgTypeTraits<llvm::Regex::RegexFlags>::getBestGuess(
+ Args[1].Value)) {
+ Error->addError(Args[1].Range, Error->ET_RegistryUnknownEnumWithReplace)
+ << 2 << Args[1].Value.getString() << *BestGuess;
+ } else {
+ Error->addError(Args[1].Range, Error->ET_RegistryWrongArgType)
+ << 2 << ArgTypeTraits<llvm::Regex::RegexFlags>::getKind().asString()
+ << Args[1].Value.getTypeAsString();
+ }
+ return VariantMatcher();
+ }
+ return outvalueToVariantMatcher(
+ WithFlags(ArgTypeTraits<StringRef>::get(Args[0].Value),
+ ArgTypeTraits<llvm::Regex::RegexFlags>::get(Args[1].Value)));
+ }
+
+private:
+ ReturnType (*const WithFlags)(StringRef, llvm::Regex::RegexFlags);
+ ReturnType (*const NoFlags)(StringRef);
+ const std::vector<ASTNodeKind> RetKinds;
+};
+
/// Variadic operator marshaller function.
class VariadicOperatorMatcherDescriptor : public MatcherDescriptor {
public:
@@ -697,13 +835,13 @@ public:
bool isVariadic() const override { return true; }
unsigned getNumArgs() const override { return 0; }
- void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo,
+ void getArgKinds(ASTNodeKind ThisKind, unsigned ArgNo,
std::vector<ArgKind> &Kinds) const override {
Kinds.push_back(ThisKind);
}
- bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, unsigned *Specificity,
- ast_type_traits::ASTNodeKind *LeastDerivedKind) const override {
+ bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity,
+ ASTNodeKind *LeastDerivedKind) const override {
if (Specificity)
*Specificity = 1;
if (LeastDerivedKind)
@@ -727,7 +865,7 @@ private:
template <typename ReturnType>
std::unique_ptr<MatcherDescriptor>
makeMatcherAutoMarshall(ReturnType (*Func)(), StringRef MatcherName) {
- std::vector<ast_type_traits::ASTNodeKind> RetTypes;
+ std::vector<ASTNodeKind> RetTypes;
BuildReturnTypeVector<ReturnType>::build(RetTypes);
return std::make_unique<FixedArgCountMatcherDescriptor>(
matcherMarshall0<ReturnType>, reinterpret_cast<void (*)()>(Func),
@@ -738,7 +876,7 @@ makeMatcherAutoMarshall(ReturnType (*Func)(), StringRef MatcherName) {
template <typename ReturnType, typename ArgType1>
std::unique_ptr<MatcherDescriptor>
makeMatcherAutoMarshall(ReturnType (*Func)(ArgType1), StringRef MatcherName) {
- std::vector<ast_type_traits::ASTNodeKind> RetTypes;
+ std::vector<ASTNodeKind> RetTypes;
BuildReturnTypeVector<ReturnType>::build(RetTypes);
ArgKind AK = ArgTypeTraits<ArgType1>::getKind();
return std::make_unique<FixedArgCountMatcherDescriptor>(
@@ -751,7 +889,7 @@ template <typename ReturnType, typename ArgType1, typename ArgType2>
std::unique_ptr<MatcherDescriptor>
makeMatcherAutoMarshall(ReturnType (*Func)(ArgType1, ArgType2),
StringRef MatcherName) {
- std::vector<ast_type_traits::ASTNodeKind> RetTypes;
+ std::vector<ASTNodeKind> RetTypes;
BuildReturnTypeVector<ReturnType>::build(RetTypes);
ArgKind AKs[] = { ArgTypeTraits<ArgType1>::getKind(),
ArgTypeTraits<ArgType2>::getKind() };
@@ -760,6 +898,16 @@ makeMatcherAutoMarshall(ReturnType (*Func)(ArgType1, ArgType2),
reinterpret_cast<void (*)()>(Func), MatcherName, RetTypes, AKs);
}
+template <typename ReturnType>
+std::unique_ptr<MatcherDescriptor> makeMatcherRegexMarshall(
+ ReturnType (*FuncFlags)(llvm::StringRef, llvm::Regex::RegexFlags),
+ ReturnType (*Func)(llvm::StringRef)) {
+ std::vector<ASTNodeKind> RetTypes;
+ BuildReturnTypeVector<ReturnType>::build(RetTypes);
+ return std::make_unique<RegexMatcherDescriptor<ReturnType>>(FuncFlags, Func,
+ RetTypes);
+}
+
/// Variadic overload.
template <typename ResultT, typename ArgT,
ResultT (*Func)(ArrayRef<const ArgT *>)>
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
index 1c0930c5983a1..ec2215804c098 100644
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -90,14 +90,14 @@ void RegistryMaps::registerMatcher(
REGISTER_MATCHER_OVERLOAD(name); \
} while (false)
+#define REGISTER_REGEX_MATCHER(name) \
+ registerMatcher(#name, internal::makeMatcherRegexMarshall(name, name))
+
/// Generate a registry map with all the known matchers.
/// Please keep sorted alphabetically!
RegistryMaps::RegistryMaps() {
// TODO: Here is the list of the missing matchers, grouped by reason.
//
- // Need Variant/Parser fixes:
- // ofKind
- //
// Polymorphic + argument overload:
// findAll
//
@@ -124,6 +124,10 @@ RegistryMaps::RegistryMaps() {
};
REGISTER_MATCHER_OVERLOAD(equals);
+ REGISTER_REGEX_MATCHER(isExpansionInFileMatching);
+ REGISTER_REGEX_MATCHER(matchesName);
+ REGISTER_REGEX_MATCHER(matchesSelector);
+
REGISTER_MATCHER(accessSpecDecl);
REGISTER_MATCHER(addrLabelExpr);
REGISTER_MATCHER(alignOfExpr);
@@ -154,6 +158,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(characterLiteral);
REGISTER_MATCHER(chooseExpr);
REGISTER_MATCHER(classTemplateDecl);
+ REGISTER_MATCHER(classTemplatePartialSpecializationDecl);
REGISTER_MATCHER(classTemplateSpecializationDecl);
REGISTER_MATCHER(complexType);
REGISTER_MATCHER(compoundLiteralExpr);
@@ -183,6 +188,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(cxxMemberCallExpr);
REGISTER_MATCHER(cxxMethodDecl);
REGISTER_MATCHER(cxxNewExpr);
+ REGISTER_MATCHER(cxxNoexceptExpr);
REGISTER_MATCHER(cxxNullPtrLiteralExpr);
REGISTER_MATCHER(cxxOperatorCallExpr);
REGISTER_MATCHER(cxxRecordDecl);
@@ -201,6 +207,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(declStmt);
REGISTER_MATCHER(declaratorDecl);
REGISTER_MATCHER(decltypeType);
+ REGISTER_MATCHER(deducedTemplateSpecializationType);
REGISTER_MATCHER(defaultStmt);
REGISTER_MATCHER(dependentSizedArrayType);
REGISTER_MATCHER(designatedInitExpr);
@@ -237,11 +244,15 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(has);
REGISTER_MATCHER(hasAncestor);
REGISTER_MATCHER(hasAnyArgument);
+ REGISTER_MATCHER(hasAnyBase);
REGISTER_MATCHER(hasAnyClause);
REGISTER_MATCHER(hasAnyConstructorInitializer);
REGISTER_MATCHER(hasAnyDeclaration);
REGISTER_MATCHER(hasAnyName);
+ REGISTER_MATCHER(hasAnyOperatorName);
+ REGISTER_MATCHER(hasAnyOverloadedOperatorName);
REGISTER_MATCHER(hasAnyParameter);
+ REGISTER_MATCHER(hasAnyPlacementArg);
REGISTER_MATCHER(hasAnySelector);
REGISTER_MATCHER(hasAnySubstatement);
REGISTER_MATCHER(hasAnyTemplateArgument);
@@ -267,6 +278,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(hasDefinition);
REGISTER_MATCHER(hasDescendant);
REGISTER_MATCHER(hasDestinationType);
+ REGISTER_MATCHER(hasDirectBase);
REGISTER_MATCHER(hasDynamicExceptionSpec);
REGISTER_MATCHER(hasEitherOperand);
REGISTER_MATCHER(hasElementType);
@@ -292,6 +304,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(hasName);
REGISTER_MATCHER(hasNullSelector);
REGISTER_MATCHER(hasObjectExpression);
+ REGISTER_MATCHER(hasOperands);
REGISTER_MATCHER(hasOperatorName);
REGISTER_MATCHER(hasOverloadedOperatorName);
REGISTER_MATCHER(hasParameter);
@@ -303,6 +316,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(hasReceiverType);
REGISTER_MATCHER(hasReplacementType);
REGISTER_MATCHER(hasReturnValue);
+ REGISTER_MATCHER(hasPlacementArg);
REGISTER_MATCHER(hasSelector);
REGISTER_MATCHER(hasSingleDecl);
REGISTER_MATCHER(hasSize);
@@ -347,12 +361,14 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(isArray);
REGISTER_MATCHER(isArrow);
REGISTER_MATCHER(isAssignmentOperator);
+ REGISTER_MATCHER(isAtPosition);
REGISTER_MATCHER(isBaseInitializer);
REGISTER_MATCHER(isBitField);
REGISTER_MATCHER(isCatchAll);
REGISTER_MATCHER(isClass);
REGISTER_MATCHER(isClassMessage);
REGISTER_MATCHER(isClassMethod);
+ REGISTER_MATCHER(isComparisonOperator);
REGISTER_MATCHER(isConst);
REGISTER_MATCHER(isConstQualified);
REGISTER_MATCHER(isConstexpr);
@@ -363,8 +379,9 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(isDefinition);
REGISTER_MATCHER(isDelegatingConstructor);
REGISTER_MATCHER(isDeleted);
+ REGISTER_MATCHER(isEnum);
REGISTER_MATCHER(isExceptionVariable);
- REGISTER_MATCHER(isExpansionInFileMatching);
+ REGISTER_MATCHER(isExpandedFromMacro);
REGISTER_MATCHER(isExpansionInMainFile);
REGISTER_MATCHER(isExpansionInSystemHeader);
REGISTER_MATCHER(isExplicit);
@@ -372,6 +389,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(isExpr);
REGISTER_MATCHER(isExternC);
REGISTER_MATCHER(isFinal);
+ REGISTER_MATCHER(isFirstPrivateKind);
REGISTER_MATCHER(isImplicit);
REGISTER_MATCHER(isInStdNamespace);
REGISTER_MATCHER(isInTemplateInstantiation);
@@ -391,7 +409,6 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(isNoReturn);
REGISTER_MATCHER(isNoThrow);
REGISTER_MATCHER(isNoneKind);
- REGISTER_MATCHER(isOMPStructuredBlock);
REGISTER_MATCHER(isOverride);
REGISTER_MATCHER(isPrivate);
REGISTER_MATCHER(isProtected);
@@ -420,8 +437,6 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(labelStmt);
REGISTER_MATCHER(lambdaExpr);
REGISTER_MATCHER(linkageSpecDecl);
- REGISTER_MATCHER(matchesName);
- REGISTER_MATCHER(matchesSelector);
REGISTER_MATCHER(materializeTemporaryExpr);
REGISTER_MATCHER(member);
REGISTER_MATCHER(memberExpr);
@@ -452,6 +467,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(objcThrowStmt);
REGISTER_MATCHER(objcTryStmt);
REGISTER_MATCHER(ofClass);
+ REGISTER_MATCHER(ofKind);
REGISTER_MATCHER(ompDefaultClause);
REGISTER_MATCHER(ompExecutableDirective);
REGISTER_MATCHER(on);
@@ -492,6 +508,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(substTemplateTypeParmType);
REGISTER_MATCHER(switchCase);
REGISTER_MATCHER(switchStmt);
+ REGISTER_MATCHER(tagDecl);
REGISTER_MATCHER(tagType);
REGISTER_MATCHER(templateArgument);
REGISTER_MATCHER(templateArgumentCountIs);
@@ -652,7 +669,7 @@ Registry::getMatcherCompletions(ArrayRef<ArgKind> AcceptedTypes) {
OS << "...";
OS << ")";
- std::string TypedText = Name;
+ std::string TypedText = std::string(Name);
TypedText += "(";
if (ArgsKinds.empty())
TypedText += ")";
diff --git a/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp b/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp
index 118ca2a41cb18..866e2d0e3491a 100644
--- a/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp
@@ -1,4 +1,4 @@
-//===--- VariantValue.cpp - Polymorphic value type -*- C++ -*-===/
+//===--- VariantValue.cpp - Polymorphic value type --------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -101,8 +101,7 @@ public:
return llvm::None;
}
- bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
- unsigned *Specificity) const override {
+ bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity) const override {
return ArgKind(Matcher.getSupportedKind())
.isConvertibleTo(Kind, Specificity);
}
@@ -159,8 +158,7 @@ public:
return llvm::None;
}
- bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
- unsigned *Specificity) const override {
+ bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity) const override {
unsigned MaxSpecificity = 0;
for (const DynTypedMatcher &Matcher : Matchers) {
unsigned ThisSpecificity;
@@ -202,8 +200,7 @@ public:
return Ops.constructVariadicOperator(Op, Args);
}
- bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
- unsigned *Specificity) const override {
+ bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity) const override {
for (const VariantMatcher &Matcher : Args) {
if (!Matcher.isConvertibleTo(Kind, Specificity))
return false;
diff --git a/clang/lib/ASTMatchers/GtestMatchers.cpp b/clang/lib/ASTMatchers/GtestMatchers.cpp
new file mode 100644
index 0000000000000..c99fdf6c0fcd6
--- /dev/null
+++ b/clang/lib/ASTMatchers/GtestMatchers.cpp
@@ -0,0 +1,104 @@
+//===- GtestMatchers.cpp - AST Matchers for Gtest ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/ASTMatchers/GtestMatchers.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Timer.h"
+#include <deque>
+#include <memory>
+#include <set>
+
+namespace clang {
+namespace ast_matchers {
+
+static DeclarationMatcher getComparisonDecl(GtestCmp Cmp) {
+ switch (Cmp) {
+ case GtestCmp::Eq:
+ return cxxMethodDecl(hasName("Compare"),
+ ofClass(cxxRecordDecl(isSameOrDerivedFrom(
+ hasName("::testing::internal::EqHelper")))));
+ case GtestCmp::Ne:
+ return functionDecl(hasName("::testing::internal::CmpHelperNE"));
+ case GtestCmp::Ge:
+ return functionDecl(hasName("::testing::internal::CmpHelperGE"));
+ case GtestCmp::Gt:
+ return functionDecl(hasName("::testing::internal::CmpHelperGT"));
+ case GtestCmp::Le:
+ return functionDecl(hasName("::testing::internal::CmpHelperLE"));
+ case GtestCmp::Lt:
+ return functionDecl(hasName("::testing::internal::CmpHelperLT"));
+ }
+ llvm_unreachable("Unhandled GtestCmp enum");
+}
+
+static llvm::StringRef getAssertMacro(GtestCmp Cmp) {
+ switch (Cmp) {
+ case GtestCmp::Eq:
+ return "ASSERT_EQ";
+ case GtestCmp::Ne:
+ return "ASSERT_NE";
+ case GtestCmp::Ge:
+ return "ASSERT_GE";
+ case GtestCmp::Gt:
+ return "ASSERT_GT";
+ case GtestCmp::Le:
+ return "ASSERT_LE";
+ case GtestCmp::Lt:
+ return "ASSERT_LT";
+ }
+ llvm_unreachable("Unhandled GtestCmp enum");
+}
+
+static llvm::StringRef getExpectMacro(GtestCmp Cmp) {
+ switch (Cmp) {
+ case GtestCmp::Eq:
+ return "EXPECT_EQ";
+ case GtestCmp::Ne:
+ return "EXPECT_NE";
+ case GtestCmp::Ge:
+ return "EXPECT_GE";
+ case GtestCmp::Gt:
+ return "EXPECT_GT";
+ case GtestCmp::Le:
+ return "EXPECT_LE";
+ case GtestCmp::Lt:
+ return "EXPECT_LT";
+ }
+ llvm_unreachable("Unhandled GtestCmp enum");
+}
+
+// In general, AST matchers cannot match calls to macros. However, we can
+// simulate such matches if the macro definition has identifiable elements that
+// themselves can be matched. In that case, we can match on those elements and
+// then check that the match occurs within an expansion of the desired
+// macro. The more uncommon the identified elements, the more efficient this
+// process will be.
+//
+// We use this approach to implement the derived matchers gtestAssert and
+// gtestExpect.
+internal::BindableMatcher<Stmt> gtestAssert(GtestCmp Cmp, StatementMatcher Left,
+ StatementMatcher Right) {
+ return callExpr(callee(getComparisonDecl(Cmp)),
+ isExpandedFromMacro(getAssertMacro(Cmp)),
+ hasArgument(2, Left), hasArgument(3, Right));
+}
+
+internal::BindableMatcher<Stmt> gtestExpect(GtestCmp Cmp, StatementMatcher Left,
+ StatementMatcher Right) {
+ return callExpr(callee(getComparisonDecl(Cmp)),
+ isExpandedFromMacro(getExpectMacro(Cmp)),
+ hasArgument(2, Left), hasArgument(3, Right));
+}
+
+} // end namespace ast_matchers
+} // end namespace clang