summaryrefslogtreecommitdiffstats
path: root/clang/lib/ASTMatchers/ASTMatchFinder.cpp
diff options
context:
space:
mode:
authorSamuel Benzaquen <sbenza@google.com>2014-11-24 21:21:09 +0000
committerSamuel Benzaquen <sbenza@google.com>2014-11-24 21:21:09 +0000
commit074bbb698db6f2b4559a65a247e9d7aa0686de94 (patch)
tree6b1d510de2cccf6c1f0fe268be203bd99cb3d56d /clang/lib/ASTMatchers/ASTMatchFinder.cpp
parent6953a3a6e006ee1f023e999a4304fddfbf70f1fc (diff)
downloadbcm5719-llvm-074bbb698db6f2b4559a65a247e9d7aa0686de94.tar.gz
bcm5719-llvm-074bbb698db6f2b4559a65a247e9d7aa0686de94.zip
Filter the toplevel matchers by kind.
Summary: Filter the toplevel matchers by kind. Decl and Stmt matchers are tied to a specific node kind and trying to match incompatible nodes is a waste. Precalculate a filtered list of matchers that have a chance of matching the node and ignore the rest. Speeds up our clang-tidy benchmark by ~10% Reviewers: klimek Subscribers: klimek, cfe-commits Differential Revision: http://reviews.llvm.org/D6361 llvm-svn: 222688
Diffstat (limited to 'clang/lib/ASTMatchers/ASTMatchFinder.cpp')
-rw-r--r--clang/lib/ASTMatchers/ASTMatchFinder.cpp77
1 files changed, 67 insertions, 10 deletions
diff --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp
index 27c02bbd2c9..fa7968a805c 100644
--- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -20,6 +20,7 @@
#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>
@@ -523,7 +524,7 @@ private:
///
/// Used by \c matchDispatch() below.
template <typename T, typename MC>
- void matchImpl(const T &Node, const MC &Matchers) {
+ void matchWithoutFilter(const T &Node, const MC &Matchers) {
const bool EnableCheckProfiling = Options.CheckProfiling.hasValue();
TimeBucketRegion Timer;
for (const auto &MP : Matchers) {
@@ -537,22 +538,66 @@ private:
}
}
+ void matchWithFilter(const ast_type_traits::DynTypedNode &DynNode) {
+ auto Kind = DynNode.getNodeKind();
+ auto it = MatcherFiltersMap.find(Kind);
+ const auto &Filter =
+ it != MatcherFiltersMap.end() ? it->second : getFilterForKind(Kind);
+
+ if (Filter.empty())
+ return;
+
+ const bool EnableCheckProfiling = Options.CheckProfiling.hasValue();
+ TimeBucketRegion Timer;
+ auto &Matchers = this->Matchers->DeclOrStmt;
+ for (unsigned short I : Filter) {
+ auto &MP = Matchers[I];
+ if (EnableCheckProfiling)
+ Timer.setBucket(&TimeByBucket[MP.second->getID()]);
+ BoundNodesTreeBuilder Builder;
+ if (MP.first.matchesNoKindCheck(DynNode, this, &Builder)) {
+ MatchVisitor Visitor(ActiveASTContext, MP.second);
+ Builder.visitMatches(&Visitor);
+ }
+ }
+ }
+
+ const std::vector<unsigned short> &
+ getFilterForKind(ast_type_traits::ASTNodeKind Kind) {
+ auto &Filter = MatcherFiltersMap[Kind];
+ auto &Matchers = this->Matchers->DeclOrStmt;
+ assert((Matchers.size() < USHRT_MAX) && "Too many matchers.");
+ for (unsigned I = 0, E = Matchers.size(); I != E; ++I) {
+ if (Matchers[I].first.canMatchNodesOfKind(Kind)) {
+ Filter.push_back(I);
+ }
+ }
+ return Filter;
+ }
+
/// @{
/// \brief Overloads to pair the different node types to their matchers.
- void matchDispatch(const Decl *Node) { matchImpl(*Node, Matchers->Decl); }
- void matchDispatch(const Stmt *Node) { matchImpl(*Node, Matchers->Stmt); }
+ void matchDispatch(const Decl *Node) {
+ return matchWithFilter(ast_type_traits::DynTypedNode::create(*Node));
+ }
+ void matchDispatch(const Stmt *Node) {
+ return matchWithFilter(ast_type_traits::DynTypedNode::create(*Node));
+ }
+
void matchDispatch(const Type *Node) {
- matchImpl(QualType(Node, 0), Matchers->Type);
+ matchWithoutFilter(QualType(Node, 0), Matchers->Type);
}
void matchDispatch(const TypeLoc *Node) {
- matchImpl(*Node, Matchers->TypeLoc);
+ matchWithoutFilter(*Node, Matchers->TypeLoc);
+ }
+ void matchDispatch(const QualType *Node) {
+ matchWithoutFilter(*Node, Matchers->Type);
}
- void matchDispatch(const QualType *Node) { matchImpl(*Node, Matchers->Type); }
void matchDispatch(const NestedNameSpecifier *Node) {
- matchImpl(*Node, Matchers->NestedNameSpecifier);
+ matchWithoutFilter(*Node, Matchers->NestedNameSpecifier);
}
void matchDispatch(const NestedNameSpecifierLoc *Node) {
- matchImpl(*Node, Matchers->NestedNameSpecifierLoc);
+ matchWithoutFilter(*Node, Matchers->NestedNameSpecifierLoc);
}
void matchDispatch(const void *) { /* Do nothing. */ }
/// @}
@@ -685,6 +730,18 @@ private:
llvm::StringMap<llvm::TimeRecord> TimeByBucket;
const MatchFinder::MatchersByType *Matchers;
+
+ /// \brief Filtered list of matcher indices for each matcher kind.
+ ///
+ /// \c Decl and \c Stmt toplevel matchers usually apply to a specific node
+ /// 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.
+ /// This also allows us to skip the restrict check at matching time. See
+ /// use \c matchesNoKindCheck() above.
+ llvm::DenseMap<ast_type_traits::ASTNodeKind, std::vector<unsigned short>>
+ MatcherFiltersMap;
+
const MatchFinder::MatchFinderOptions &Options;
ASTContext *ActiveASTContext;
@@ -855,7 +912,7 @@ MatchFinder::~MatchFinder() {}
void MatchFinder::addMatcher(const DeclarationMatcher &NodeMatch,
MatchCallback *Action) {
- Matchers.Decl.push_back(std::make_pair(NodeMatch, Action));
+ Matchers.DeclOrStmt.push_back(std::make_pair(NodeMatch, Action));
Matchers.AllCallbacks.push_back(Action);
}
@@ -867,7 +924,7 @@ void MatchFinder::addMatcher(const TypeMatcher &NodeMatch,
void MatchFinder::addMatcher(const StatementMatcher &NodeMatch,
MatchCallback *Action) {
- Matchers.Stmt.push_back(std::make_pair(NodeMatch, Action));
+ Matchers.DeclOrStmt.push_back(std::make_pair(NodeMatch, Action));
Matchers.AllCallbacks.push_back(Action);
}
OpenPOWER on IntegriCloud