Skip to content

Commit 0a717d5

Browse files
committed
Make it possible control matcher traversal kind with ASTContext
Summary: This will eventually allow traversal of an AST while ignoring invisible AST nodes. Currently it depends on the available enum values for TraversalKinds. That can be extended to ignore all invisible nodes in the future. Reviewers: klimek, aaron.ballman Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D61837
1 parent b4f4e37 commit 0a717d5

File tree

8 files changed

+278
-37
lines changed

8 files changed

+278
-37
lines changed

clang/include/clang/AST/ASTContext.h

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,17 @@ class ASTContext : public RefCountedBase<ASTContext> {
569569
clang::PrintingPolicy PrintingPolicy;
570570
std::unique_ptr<interp::Context> InterpContext;
571571

572+
ast_type_traits::TraversalKind Traversal = ast_type_traits::TK_AsIs;
573+
572574
public:
575+
ast_type_traits::TraversalKind getTraversalKind() const { return Traversal; }
576+
void setTraversalKind(ast_type_traits::TraversalKind TK) { Traversal = TK; }
577+
578+
const Expr *traverseIgnored(const Expr *E) const;
579+
Expr *traverseIgnored(Expr *E) const;
580+
ast_type_traits::DynTypedNode
581+
traverseIgnored(const ast_type_traits::DynTypedNode &N) const;
582+
573583
IdentifierTable &Idents;
574584
SelectorTable &Selectors;
575585
Builtin::Context &BuiltinInfo;
@@ -2996,7 +3006,7 @@ OPT_LIST(V)
29963006

29973007
std::vector<Decl *> TraversalScope;
29983008
class ParentMap;
2999-
std::unique_ptr<ParentMap> Parents;
3009+
std::map<ast_type_traits::TraversalKind, std::unique_ptr<ParentMap>> Parents;
30003010

30013011
std::unique_ptr<VTableContextBase> VTContext;
30023012

@@ -3040,6 +3050,22 @@ inline Selector GetUnarySelector(StringRef name, ASTContext &Ctx) {
30403050
return Ctx.Selectors.getSelector(1, &II);
30413051
}
30423052

3053+
class TraversalKindScope {
3054+
ASTContext &Ctx;
3055+
ast_type_traits::TraversalKind TK = ast_type_traits::TK_AsIs;
3056+
3057+
public:
3058+
TraversalKindScope(ASTContext &Ctx,
3059+
llvm::Optional<ast_type_traits::TraversalKind> ScopeTK)
3060+
: Ctx(Ctx) {
3061+
TK = Ctx.getTraversalKind();
3062+
if (ScopeTK)
3063+
Ctx.setTraversalKind(*ScopeTK);
3064+
}
3065+
3066+
~TraversalKindScope() { Ctx.setTraversalKind(TK); }
3067+
};
3068+
30433069
} // namespace clang
30443070

30453071
// operator new and delete aren't allowed inside namespaces.

clang/include/clang/AST/ASTNodeTraverser.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ class ASTNodeTraverser
6565
/// not already been loaded.
6666
bool Deserialize = false;
6767

68+
ast_type_traits::TraversalKind Traversal =
69+
ast_type_traits::TraversalKind::TK_AsIs;
70+
6871
NodeDelegateType &getNodeDelegate() {
6972
return getDerived().doGetNodeDelegate();
7073
}
@@ -74,6 +77,8 @@ class ASTNodeTraverser
7477
void setDeserialize(bool D) { Deserialize = D; }
7578
bool getDeserialize() const { return Deserialize; }
7679

80+
void SetTraversalKind(ast_type_traits::TraversalKind TK) { Traversal = TK; }
81+
7782
void Visit(const Decl *D) {
7883
getNodeDelegate().AddChild([=] {
7984
getNodeDelegate().Visit(D);
@@ -97,8 +102,20 @@ class ASTNodeTraverser
97102
});
98103
}
99104

100-
void Visit(const Stmt *S, StringRef Label = {}) {
105+
void Visit(const Stmt *Node, StringRef Label = {}) {
101106
getNodeDelegate().AddChild(Label, [=] {
107+
const Stmt *S = Node;
108+
109+
if (auto *E = dyn_cast_or_null<Expr>(S)) {
110+
switch (Traversal) {
111+
case ast_type_traits::TK_AsIs:
112+
break;
113+
case ast_type_traits::TK_IgnoreImplicitCastsAndParentheses:
114+
S = E->IgnoreParenImpCasts();
115+
break;
116+
}
117+
}
118+
102119
getNodeDelegate().Visit(S);
103120

104121
if (!S) {

clang/include/clang/ASTMatchers/ASTMatchers.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,31 @@ AST_POLYMORPHIC_MATCHER_P(
689689
Builder);
690690
}
691691

692+
/// Causes all nested matchers to be matched with the specified traversal kind.
693+
///
694+
/// Given
695+
/// \code
696+
/// void foo()
697+
/// {
698+
/// int i = 3.0;
699+
/// }
700+
/// \endcode
701+
/// The matcher
702+
/// \code
703+
/// traverse(ast_type_traits::TK_IgnoreImplicitCastsAndParentheses,
704+
/// varDecl(hasInitializer(floatLiteral().bind("init")))
705+
/// )
706+
/// \endcode
707+
/// matches the variable declaration with "init" bound to the "3.0".
708+
template <typename T>
709+
internal::Matcher<T> traverse(ast_type_traits::TraversalKind TK,
710+
const internal::Matcher<T> &InnerMatcher) {
711+
return internal::DynTypedMatcher::constructRestrictedWrapper(
712+
new internal::TraversalMatcher<T>(TK, InnerMatcher),
713+
InnerMatcher.getID().first)
714+
.template unconditionalConvertTo<T>();
715+
}
716+
692717
/// Matches expressions that match InnerMatcher after any implicit AST
693718
/// nodes are stripped off.
694719
///

clang/include/clang/ASTMatchers/ASTMatchersInternal.h

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,10 @@ class DynMatcherInterface
283283
virtual bool dynMatches(const ast_type_traits::DynTypedNode &DynNode,
284284
ASTMatchFinder *Finder,
285285
BoundNodesTreeBuilder *Builder) const = 0;
286+
287+
virtual llvm::Optional<ast_type_traits::TraversalKind> TraversalKind() const {
288+
return llvm::None;
289+
}
286290
};
287291

288292
/// Generic interface for matchers on an AST node of type T.
@@ -371,6 +375,10 @@ class DynTypedMatcher {
371375
ast_type_traits::ASTNodeKind SupportedKind,
372376
std::vector<DynTypedMatcher> InnerMatchers);
373377

378+
static DynTypedMatcher
379+
constructRestrictedWrapper(const DynTypedMatcher &InnerMatcher,
380+
ast_type_traits::ASTNodeKind RestrictKind);
381+
374382
/// Get a "true" matcher for \p NodeKind.
375383
///
376384
/// It only checks that the node is of the right kind.
@@ -1002,7 +1010,7 @@ class ASTMatchFinder {
10021010
std::is_base_of<QualType, T>::value,
10031011
"unsupported type for recursive matching");
10041012
return matchesChildOf(ast_type_traits::DynTypedNode::create(Node),
1005-
Matcher, Builder, Traverse, Bind);
1013+
getASTContext(), Matcher, Builder, Traverse, Bind);
10061014
}
10071015

10081016
template <typename T>
@@ -1018,7 +1026,7 @@ class ASTMatchFinder {
10181026
std::is_base_of<QualType, T>::value,
10191027
"unsupported type for recursive matching");
10201028
return matchesDescendantOf(ast_type_traits::DynTypedNode::create(Node),
1021-
Matcher, Builder, Bind);
1029+
getASTContext(), Matcher, Builder, Bind);
10221030
}
10231031

10241032
// FIXME: Implement support for BindKind.
@@ -1033,24 +1041,26 @@ class ASTMatchFinder {
10331041
std::is_base_of<TypeLoc, T>::value,
10341042
"type not allowed for recursive matching");
10351043
return matchesAncestorOf(ast_type_traits::DynTypedNode::create(Node),
1036-
Matcher, Builder, MatchMode);
1044+
getASTContext(), Matcher, Builder, MatchMode);
10371045
}
10381046

10391047
virtual ASTContext &getASTContext() const = 0;
10401048

10411049
protected:
10421050
virtual bool matchesChildOf(const ast_type_traits::DynTypedNode &Node,
1043-
const DynTypedMatcher &Matcher,
1051+
ASTContext &Ctx, const DynTypedMatcher &Matcher,
10441052
BoundNodesTreeBuilder *Builder,
10451053
ast_type_traits::TraversalKind Traverse,
10461054
BindKind Bind) = 0;
10471055

10481056
virtual bool matchesDescendantOf(const ast_type_traits::DynTypedNode &Node,
1057+
ASTContext &Ctx,
10491058
const DynTypedMatcher &Matcher,
10501059
BoundNodesTreeBuilder *Builder,
10511060
BindKind Bind) = 0;
10521061

10531062
virtual bool matchesAncestorOf(const ast_type_traits::DynTypedNode &Node,
1063+
ASTContext &Ctx,
10541064
const DynTypedMatcher &Matcher,
10551065
BoundNodesTreeBuilder *Builder,
10561066
AncestorMatchMode MatchMode) = 0;
@@ -1162,6 +1172,28 @@ struct ArgumentAdaptingMatcherFunc {
11621172
}
11631173
};
11641174

1175+
template <typename T>
1176+
class TraversalMatcher : public WrapperMatcherInterface<T> {
1177+
ast_type_traits::TraversalKind Traversal;
1178+
1179+
public:
1180+
explicit TraversalMatcher(ast_type_traits::TraversalKind TK,
1181+
const Matcher<T> &ChildMatcher)
1182+
: TraversalMatcher::WrapperMatcherInterface(ChildMatcher), Traversal(TK) {
1183+
}
1184+
1185+
bool matches(const T &Node, ASTMatchFinder *Finder,
1186+
BoundNodesTreeBuilder *Builder) const override {
1187+
return this->InnerMatcher.matches(
1188+
ast_type_traits::DynTypedNode::create(Node), Finder, Builder);
1189+
}
1190+
1191+
llvm::Optional<ast_type_traits::TraversalKind>
1192+
TraversalKind() const override {
1193+
return Traversal;
1194+
}
1195+
};
1196+
11651197
/// A PolymorphicMatcherWithParamN<MatcherT, P1, ..., PN> object can be
11661198
/// created from N parameters p1, ..., pN (of type P1, ..., PN) and
11671199
/// used as a Matcher<T> where a MatcherT<T, P1, ..., PN>(p1, ..., pN)

clang/lib/AST/ASTContext.cpp

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,30 @@ using namespace clang;
9999
enum FloatingRank {
100100
Float16Rank, HalfRank, FloatRank, DoubleRank, LongDoubleRank, Float128Rank
101101
};
102+
const Expr *ASTContext::traverseIgnored(const Expr *E) const {
103+
return traverseIgnored(const_cast<Expr *>(E));
104+
}
105+
106+
Expr *ASTContext::traverseIgnored(Expr *E) const {
107+
if (!E)
108+
return nullptr;
109+
110+
switch (Traversal) {
111+
case ast_type_traits::TK_AsIs:
112+
return E;
113+
case ast_type_traits::TK_IgnoreImplicitCastsAndParentheses:
114+
return E->IgnoreParenImpCasts();
115+
}
116+
llvm_unreachable("Invalid Traversal type!");
117+
}
118+
119+
ast_type_traits::DynTypedNode
120+
ASTContext::traverseIgnored(const ast_type_traits::DynTypedNode &N) const {
121+
if (const auto *E = N.get<Expr>()) {
122+
return ast_type_traits::DynTypedNode::create(*traverseIgnored(E));
123+
}
124+
return N;
125+
}
102126

103127
/// \returns location that is relevant when searching for Doc comments related
104128
/// to \p D.
@@ -959,7 +983,7 @@ class ASTContext::ParentMap {
959983

960984
void ASTContext::setTraversalScope(const std::vector<Decl *> &TopLevelDecls) {
961985
TraversalScope = TopLevelDecls;
962-
Parents.reset();
986+
Parents.clear();
963987
}
964988

965989
void ASTContext::AddDeallocation(void (*Callback)(void *), void *Data) const {
@@ -10397,7 +10421,8 @@ createDynTypedNode(const NestedNameSpecifierLoc &Node) {
1039710421
class ASTContext::ParentMap::ASTVisitor
1039810422
: public RecursiveASTVisitor<ASTVisitor> {
1039910423
public:
10400-
ASTVisitor(ParentMap &Map) : Map(Map) {}
10424+
ASTVisitor(ParentMap &Map, ASTContext &Context)
10425+
: Map(Map), Context(Context) {}
1040110426

1040210427
private:
1040310428
friend class RecursiveASTVisitor<ASTVisitor>;
@@ -10467,9 +10492,12 @@ class ASTContext::ParentMap::ASTVisitor
1046710492
}
1046810493

1046910494
bool TraverseStmt(Stmt *StmtNode) {
10470-
return TraverseNode(
10471-
StmtNode, StmtNode, [&] { return VisitorBase::TraverseStmt(StmtNode); },
10472-
&Map.PointerParents);
10495+
Stmt *FilteredNode = StmtNode;
10496+
if (auto *ExprNode = dyn_cast_or_null<Expr>(FilteredNode))
10497+
FilteredNode = Context.traverseIgnored(ExprNode);
10498+
return TraverseNode(FilteredNode, FilteredNode,
10499+
[&] { return VisitorBase::TraverseStmt(FilteredNode); },
10500+
&Map.PointerParents);
1047310501
}
1047410502

1047510503
bool TraverseTypeLoc(TypeLoc TypeLocNode) {
@@ -10487,20 +10515,22 @@ class ASTContext::ParentMap::ASTVisitor
1048710515
}
1048810516

1048910517
ParentMap &Map;
10518+
ASTContext &Context;
1049010519
llvm::SmallVector<ast_type_traits::DynTypedNode, 16> ParentStack;
1049110520
};
1049210521

1049310522
ASTContext::ParentMap::ParentMap(ASTContext &Ctx) {
10494-
ASTVisitor(*this).TraverseAST(Ctx);
10523+
ASTVisitor(*this, Ctx).TraverseAST(Ctx);
1049510524
}
1049610525

1049710526
ASTContext::DynTypedNodeList
1049810527
ASTContext::getParents(const ast_type_traits::DynTypedNode &Node) {
10499-
if (!Parents)
10528+
std::unique_ptr<ParentMap> &P = Parents[Traversal];
10529+
if (!P)
1050010530
// We build the parent map for the traversal scope (usually whole TU), as
1050110531
// hasAncestor can escape any subtree.
10502-
Parents = std::make_unique<ParentMap>(*this);
10503-
return Parents->getParents(Node);
10532+
P = std::make_unique<ParentMap>(*this);
10533+
return P->getParents(Node);
1050410534
}
1050510535

1050610536
bool

0 commit comments

Comments
 (0)