2012-07-06 13:48:52 +08:00
|
|
|
//===--- ASTMatchersInternal.cpp - Structural query framework -------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// Implements the base layer of the matcher framework.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "clang/ASTMatchers/ASTMatchers.h"
|
|
|
|
#include "clang/ASTMatchers/ASTMatchersInternal.h"
|
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace ast_matchers {
|
|
|
|
namespace internal {
|
|
|
|
|
Completely revamp node binding for AST matchers.
This is in preparation for the backwards references to bound
nodes, which will expose a lot more about how matches occur. Main
changes:
- instead of building the tree of bound nodes, we build a "set" of bound
nodes and explode all possible match combinations while running
through the matchers; this will allow us to also implement matchers
that filter down the current set of matches, like "equalsBoundNode"
- take the set of bound nodes at the start of the match into
consideration when doing memoization; as part of that, reevaluated
that memoization gives us benefits that are large enough (it still
does - the effect on common match patterns is up to an order of
magnitude)
- reset the bound nodes when a node does not match, thus never leaking
information from partial sub-matcher matches for failing matchers
Effects:
- we can now correctly "explode" combinatorial matches, for example:
allOf(forEachDescendant(...bind("a")),
forEachDescendant(...bind("b"))) will now trigger matches for all
combinations of matching "a" and "b"s.
- we now never expose bound nodes from partial matches in matchers that
did not match in the end - this fixes a long-standing issue
FIXMEs:
- rename BoundNodesTreeBuilder to BoundNodesBuilder or
BoundNodesSetBuilder, as we don't build a tree any more; this is out
of scope for this change, though
- we're seeing some performance regressions (around 10%), but I expect
some performance tuning will get that back, and it's easily worth
the increase in expressiveness for now
llvm-svn: 184313
2013-06-19 23:42:45 +08:00
|
|
|
void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) {
|
|
|
|
if (Bindings.empty())
|
|
|
|
Bindings.push_back(BoundNodesMap());
|
|
|
|
for (unsigned i = 0, e = Bindings.size(); i != e; ++i) {
|
|
|
|
ResultVisitor->visitMatch(BoundNodes(Bindings[i]));
|
2012-08-29 07:26:39 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-29 22:37:15 +08:00
|
|
|
DynTypedMatcher::MatcherStorage::~MatcherStorage() {}
|
|
|
|
|
Completely revamp node binding for AST matchers.
This is in preparation for the backwards references to bound
nodes, which will expose a lot more about how matches occur. Main
changes:
- instead of building the tree of bound nodes, we build a "set" of bound
nodes and explode all possible match combinations while running
through the matchers; this will allow us to also implement matchers
that filter down the current set of matches, like "equalsBoundNode"
- take the set of bound nodes at the start of the match into
consideration when doing memoization; as part of that, reevaluated
that memoization gives us benefits that are large enough (it still
does - the effect on common match patterns is up to an order of
magnitude)
- reset the bound nodes when a node does not match, thus never leaking
information from partial sub-matcher matches for failing matchers
Effects:
- we can now correctly "explode" combinatorial matches, for example:
allOf(forEachDescendant(...bind("a")),
forEachDescendant(...bind("b"))) will now trigger matches for all
combinations of matching "a" and "b"s.
- we now never expose bound nodes from partial matches in matchers that
did not match in the end - this fixes a long-standing issue
FIXMEs:
- rename BoundNodesTreeBuilder to BoundNodesBuilder or
BoundNodesSetBuilder, as we don't build a tree any more; this is out
of scope for this change, though
- we're seeing some performance regressions (around 10%), but I expect
some performance tuning will get that back, and it's easily worth
the increase in expressiveness for now
llvm-svn: 184313
2013-06-19 23:42:45 +08:00
|
|
|
void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) {
|
|
|
|
for (unsigned i = 0, e = Other.Bindings.size(); i != e; ++i) {
|
|
|
|
Bindings.push_back(Other.Bindings[i]);
|
2012-11-17 02:39:22 +08:00
|
|
|
}
|
2012-08-29 07:26:39 +08:00
|
|
|
}
|
|
|
|
|
2013-11-22 22:41:48 +08:00
|
|
|
bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode,
|
|
|
|
ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
|
|
|
|
ArrayRef<DynTypedMatcher> InnerMatchers) {
|
|
|
|
if (InnerMatchers.size() != 1)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// The 'unless' matcher will always discard the result:
|
|
|
|
// If the inner matcher doesn't match, unless returns true,
|
|
|
|
// but the inner matcher cannot have bound anything.
|
|
|
|
// If the inner matcher matches, the result is false, and
|
|
|
|
// any possible binding will be discarded.
|
|
|
|
// We still need to hand in all the bound nodes up to this
|
|
|
|
// point so the inner matcher can depend on bound nodes,
|
|
|
|
// and we need to actively discard the bound nodes, otherwise
|
|
|
|
// the inner matcher will reset the bound nodes if it doesn't
|
|
|
|
// match, but this would be inversed by 'unless'.
|
|
|
|
BoundNodesTreeBuilder Discard(*Builder);
|
|
|
|
return !InnerMatchers[0].matches(DynNode, Finder, &Discard);
|
|
|
|
}
|
|
|
|
|
2013-08-27 23:11:16 +08:00
|
|
|
bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
|
|
|
|
ASTMatchFinder *Finder,
|
|
|
|
BoundNodesTreeBuilder *Builder,
|
2013-10-29 22:37:15 +08:00
|
|
|
ArrayRef<DynTypedMatcher> InnerMatchers) {
|
2013-08-27 23:11:16 +08:00
|
|
|
// 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 (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
|
2013-10-29 22:37:15 +08:00
|
|
|
if (!InnerMatchers[i].matches(DynNode, Finder, Builder))
|
2013-08-27 23:11:16 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
|
|
|
|
ASTMatchFinder *Finder,
|
|
|
|
BoundNodesTreeBuilder *Builder,
|
2013-10-29 22:37:15 +08:00
|
|
|
ArrayRef<DynTypedMatcher> InnerMatchers) {
|
2013-08-27 23:11:16 +08:00
|
|
|
BoundNodesTreeBuilder Result;
|
|
|
|
bool Matched = false;
|
|
|
|
for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
|
|
|
|
BoundNodesTreeBuilder BuilderInner(*Builder);
|
2013-10-29 22:37:15 +08:00
|
|
|
if (InnerMatchers[i].matches(DynNode, Finder, &BuilderInner)) {
|
2013-08-27 23:11:16 +08:00
|
|
|
Matched = true;
|
|
|
|
Result.addMatch(BuilderInner);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*Builder = Result;
|
|
|
|
return Matched;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
|
|
|
|
ASTMatchFinder *Finder,
|
|
|
|
BoundNodesTreeBuilder *Builder,
|
2013-10-29 22:37:15 +08:00
|
|
|
ArrayRef<DynTypedMatcher> InnerMatchers) {
|
2013-08-27 23:11:16 +08:00
|
|
|
for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
|
|
|
|
BoundNodesTreeBuilder Result = *Builder;
|
2013-10-29 22:37:15 +08:00
|
|
|
if (InnerMatchers[i].matches(DynNode, Finder, &Result)) {
|
2013-08-27 23:11:16 +08:00
|
|
|
*Builder = Result;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-07-06 13:48:52 +08:00
|
|
|
} // end namespace internal
|
|
|
|
} // end namespace ast_matchers
|
|
|
|
} // end namespace clang
|