Skip to content

Commit 0a42fe7

Browse files
committed
[AST] Treat semantic form of InitListExpr as implicit code in traversals
Summary: In particular, do not traverse the semantic form if shouldVisitImplicitCode() returns false. This simplifies the common case of traversals, avoiding the need to worry about some expressions being traversed twice. No tests break after the change, the change would allow to simplify at least one of the usages, i.e. r366070 which had to handle this in clangd. Reviewers: gribozavr Reviewed By: gribozavr Subscribers: kadircet, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D64762 llvm-svn: 366672
1 parent 3a52e50 commit 0a42fe7

File tree

2 files changed

+35
-7
lines changed

2 files changed

+35
-7
lines changed

clang/include/clang/AST/RecursiveASTVisitor.h

+17-6
Original file line numberDiff line numberDiff line change
@@ -2308,19 +2308,30 @@ bool RecursiveASTVisitor<Derived>::TraverseSynOrSemInitListExpr(
23082308
return true;
23092309
}
23102310

2311-
// This method is called once for each pair of syntactic and semantic
2312-
// InitListExpr, and it traverses the subtrees defined by the two forms. This
2313-
// may cause some of the children to be visited twice, if they appear both in
2314-
// the syntactic and the semantic form.
2311+
// If shouldVisitImplicitCode() returns false, this method traverses only the
2312+
// syntactic form of InitListExpr.
2313+
// If shouldVisitImplicitCode() return true, this method is called once for
2314+
// each pair of syntactic and semantic InitListExpr, and it traverses the
2315+
// subtrees defined by the two forms. This may cause some of the children to be
2316+
// visited twice, if they appear both in the syntactic and the semantic form.
23152317
//
23162318
// There is no guarantee about which form \p S takes when this method is called.
23172319
template <typename Derived>
23182320
bool RecursiveASTVisitor<Derived>::TraverseInitListExpr(
23192321
InitListExpr *S, DataRecursionQueue *Queue) {
2322+
if (S->isSemanticForm() && S->isSyntacticForm()) {
2323+
// `S` does not have alternative forms, traverse only once.
2324+
TRY_TO(TraverseSynOrSemInitListExpr(S, Queue));
2325+
return true;
2326+
}
23202327
TRY_TO(TraverseSynOrSemInitListExpr(
23212328
S->isSemanticForm() ? S->getSyntacticForm() : S, Queue));
2322-
TRY_TO(TraverseSynOrSemInitListExpr(
2323-
S->isSemanticForm() ? S : S->getSemanticForm(), Queue));
2329+
if (getDerived().shouldVisitImplicitCode()) {
2330+
// Only visit the semantic form if the clients are interested in implicit
2331+
// compiler-generated.
2332+
TRY_TO(TraverseSynOrSemInitListExpr(
2333+
S->isSemanticForm() ? S : S->getSemanticForm(), Queue));
2334+
}
23242335
return true;
23252336
}
23262337

clang/unittests/Tooling/RecursiveASTVisitorTests/InitListExprPreOrder.cpp

+18-1
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,36 @@ namespace {
1717
class InitListExprPreOrderVisitor
1818
: public ExpectedLocationVisitor<InitListExprPreOrderVisitor> {
1919
public:
20+
InitListExprPreOrderVisitor(bool VisitImplicitCode)
21+
: VisitImplicitCode(VisitImplicitCode) {}
22+
23+
bool shouldVisitImplicitCode() const { return VisitImplicitCode; }
24+
2025
bool VisitInitListExpr(InitListExpr *ILE) {
2126
Match(ILE->isSemanticForm() ? "semantic" : "syntactic", ILE->getBeginLoc());
2227
return true;
2328
}
29+
30+
private:
31+
bool VisitImplicitCode;
2432
};
2533

2634
TEST(RecursiveASTVisitor, InitListExprIsPreOrderVisitedTwice) {
27-
InitListExprPreOrderVisitor Visitor;
35+
InitListExprPreOrderVisitor Visitor(/*VisitImplicitCode=*/true);
2836
Visitor.ExpectMatch("syntactic", 2, 21);
2937
Visitor.ExpectMatch("semantic", 2, 21);
3038
EXPECT_TRUE(Visitor.runOver("struct S { int x; };\n"
3139
"static struct S s = {.x = 0};\n",
3240
InitListExprPreOrderVisitor::Lang_C));
3341
}
3442

43+
TEST(RecursiveASTVisitor, InitListExprVisitedOnceWhenNoImplicit) {
44+
InitListExprPreOrderVisitor Visitor(/*VisitImplicitCode=*/false);
45+
Visitor.ExpectMatch("syntactic", 2, 21);
46+
Visitor.DisallowMatch("semantic", 2, 21);
47+
EXPECT_TRUE(Visitor.runOver("struct S { int x; };\n"
48+
"static struct S s = {.x = 0};\n",
49+
InitListExprPreOrderVisitor::Lang_C));
50+
}
51+
3552
} // end anonymous namespace

0 commit comments

Comments
 (0)