Skip to content

Commit 3b97fed

Browse files
committed
[ASTWalker] Re-introduce Action::SkipChildren
Now with the behavior of resuming at the post-walk.
1 parent 05615fa commit 3b97fed

File tree

2 files changed

+73
-18
lines changed

2 files changed

+73
-18
lines changed

include/swift/AST/ASTWalker.h

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ class ASTWalker {
163163

164164
// The 'Action' set of types, which do not take a payload.
165165
struct ContinueWalkAction {};
166-
struct SkipChildrenIfWalkAction { bool Cond; };
166+
struct SkipChildrenIfWalkAction { bool Cond; bool SkipPostWalk; };
167167
struct StopIfWalkAction { bool Cond; };
168168
struct StopWalkAction {};
169169

@@ -216,13 +216,30 @@ class ASTWalker {
216216
return {Continue(), std::move(node)};
217217
}
218218

219-
/// Skips visiting both the node's children and its post-visitation.
219+
/// Continue the current walk, replacing the current node with \p node.
220+
/// However, skip visiting the children of \p node, and resume at its
221+
/// post-walk.
222+
template <typename T>
223+
static _Detail::SkipChildrenIfWalkResult<T> SkipChildren(T node) {
224+
return SkipChildrenIf(true, std::move(node));
225+
}
226+
227+
/// Similar to \c Action::SkipChildren, but also skips the call to the
228+
/// post-visitation method.
220229
template <typename T>
221230
static _Detail::SkipChildrenIfWalkResult<T>
222231
SkipNode(T node) {
223232
return SkipNodeIf(true, std::move(node));
224233
}
225234

235+
/// If \p cond is true, this is equivalent to \c Action::SkipChildren(node).
236+
/// Otherwise, it is equivalent to \c Action::Continue(node).
237+
template <typename T>
238+
static _Detail::SkipChildrenIfWalkResult<T>
239+
SkipChildrenIf(bool cond, T node) {
240+
return {SkipChildrenIf(cond), std::move(node)};
241+
}
242+
226243
/// If \p cond is true, this is equivalent to \c Action::SkipNode(node).
227244
/// Otherwise, it is equivalent to \c Action::Continue(node).
228245
template <typename T>
@@ -231,6 +248,14 @@ class ASTWalker {
231248
return {SkipNodeIf(cond), std::move(node)};
232249
}
233250

251+
/// If \p cond is true, this is equivalent to \c Action::Continue(node).
252+
/// Otherwise, it is equivalent to \c Action::SkipChildren(node).
253+
template <typename T>
254+
static _Detail::SkipChildrenIfWalkResult<T>
255+
VisitChildrenIf(bool cond, T node) {
256+
return SkipChildrenIf(!cond, std::move(node));
257+
}
258+
234259
/// If \p cond is true, this is equivalent to \c Action::Continue(node).
235260
/// Otherwise, it is equivalent to \c Action::SkipNode(node).
236261
template <typename T>
@@ -249,16 +274,35 @@ class ASTWalker {
249274
/// Continue the current walk.
250275
static _Detail::ContinueWalkAction Continue() { return {}; }
251276

252-
/// Skips visiting both the node's children and its post-visitation.
277+
/// Continue the current walk, but do not visit the children of the current
278+
/// node, resuming at its post-walk.
279+
static _Detail::SkipChildrenIfWalkAction SkipChildren() {
280+
return SkipChildrenIf(true);
281+
}
282+
283+
/// Similar to \c Action::SkipChildren, but also skips the call to the
284+
/// post-visitation method.
253285
static _Detail::SkipChildrenIfWalkAction SkipNode() {
254286
return SkipNodeIf(true);
255287
}
256288

289+
/// If \p cond is true, this is equivalent to \c Action::SkipChildren().
290+
/// Otherwise, it is equivalent to \c Action::Continue().
291+
static _Detail::SkipChildrenIfWalkAction SkipChildrenIf(bool cond) {
292+
return {cond, /*SkipPostWalk*/ false};
293+
}
294+
257295
/// If \p cond is true, this is equivalent to \c Action::SkipNode().
258296
/// Otherwise, it is equivalent to \c Action::Continue().
259297
static _Detail::SkipChildrenIfWalkAction
260298
SkipNodeIf(bool cond) {
261-
return {cond};
299+
return {cond, /*SkipPostWalk*/ true};
300+
}
301+
302+
/// If \p cond is true, this is equivalent to \c Action::Continue().
303+
/// Otherwise, it is equivalent to \c Action::SkipChildren().
304+
static _Detail::SkipChildrenIfWalkAction VisitChildrenIf(bool cond) {
305+
return SkipChildrenIf(!cond);
262306
}
263307

264308
/// If \p cond is true, this is equivalent to \c Action::Continue().
@@ -281,14 +325,19 @@ class ASTWalker {
281325
/// A pre-visitation action for AST nodes that do not support being replaced
282326
/// while walking.
283327
struct PreWalkAction {
284-
enum Kind { Stop, SkipNode, Continue };
328+
enum Kind { Stop, SkipChildren, SkipNode, Continue };
285329
Kind Action;
286330

287331
PreWalkAction(_Detail::ContinueWalkAction) : Action(Continue) {}
288332
PreWalkAction(_Detail::StopWalkAction) : Action(Stop) {}
289333

290-
PreWalkAction(_Detail::SkipChildrenIfWalkAction action)
291-
: Action(action.Cond ? SkipNode : Continue) {}
334+
PreWalkAction(_Detail::SkipChildrenIfWalkAction action) {
335+
if (action.Cond) {
336+
Action = action.SkipPostWalk ? SkipNode : SkipChildren;
337+
} else {
338+
Action = Continue;
339+
}
340+
}
292341

293342
PreWalkAction(_Detail::StopIfWalkAction action)
294343
: Action(action.Cond ? Stop : Continue) {}

lib/AST/ASTWalker.cpp

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1457,11 +1457,13 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
14571457
return true;
14581458
case PreWalkAction::SkipNode:
14591459
return false;
1460+
case PreWalkAction::SkipChildren:
1461+
break;
14601462
case PreWalkAction::Continue:
1463+
if (VisitChildren())
1464+
return true;
14611465
break;
14621466
}
1463-
if (VisitChildren())
1464-
return true;
14651467
switch (WalkPost().Action) {
14661468
case PostWalkAction::Stop:
14671469
return true;
@@ -1476,21 +1478,25 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
14761478
T *traverse(PreWalkResult<T *> Pre,
14771479
llvm::function_ref<T *(T *)> VisitChildren,
14781480
llvm::function_ref<PostWalkResult<T *>(T *)> WalkPost) {
1481+
auto Node = Pre.Value;
1482+
assert(!Node || *Node && "Use Action::Stop instead of returning nullptr");
14791483
switch (Pre.Action.Action) {
14801484
case PreWalkAction::Stop:
14811485
return nullptr;
14821486
case PreWalkAction::SkipNode:
1483-
assert(*Pre.Value && "Use Action::Stop instead of returning nullptr");
1484-
return *Pre.Value;
1485-
case PreWalkAction::Continue:
1487+
return *Node;
1488+
case PreWalkAction::SkipChildren:
14861489
break;
1487-
}
1488-
assert(*Pre.Value && "Use Action::Stop instead of returning nullptr");
1489-
auto Value = VisitChildren(*Pre.Value);
1490-
if (!Value)
1491-
return nullptr;
1490+
case PreWalkAction::Continue: {
1491+
auto NewNode = VisitChildren(*Node);
1492+
if (!NewNode)
1493+
return nullptr;
14921494

1493-
auto Post = WalkPost(Value);
1495+
Node = NewNode;
1496+
break;
1497+
}
1498+
}
1499+
auto Post = WalkPost(*Node);
14941500
switch (Post.Action.Action) {
14951501
case PostWalkAction::Stop:
14961502
return nullptr;

0 commit comments

Comments
 (0)