Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -593,6 +593,16 @@ #define STMT(CLASS, PARENT) \ case Stmt::CLASS##Class: \ TRY_TO(WalkUpFrom##CLASS(static_cast(S))); break; +#define INITLISTEXPR(CLASS, PARENT) \ + case Stmt::CLASS##Class: \ + { \ + auto ILE = static_cast(S); \ + if (auto Syn = ILE->isSemanticForm() ? ILE->getSyntacticForm() : ILE) \ + TRY_TO(WalkUpFrom##CLASS(Syn)); \ + if (auto Sem = ILE->isSemanticForm() ? ILE : ILE->getSemanticForm()) \ + TRY_TO(WalkUpFrom##CLASS(Sem)); \ + break; \ + } #include "clang/AST/StmtNodes.inc" } @@ -2212,13 +2222,15 @@ // the syntactic and the semantic form. // // There is no guarantee about which form \p S takes when this method is called. -DEF_TRAVERSE_STMT(InitListExpr, { +template +bool RecursiveASTVisitor::TraverseInitListExpr( + InitListExpr *S, DataRecursionQueue *Queue) { TRY_TO(TraverseSynOrSemInitListExpr( S->isSemanticForm() ? S->getSyntacticForm() : S, Queue)); TRY_TO(TraverseSynOrSemInitListExpr( S->isSemanticForm() ? S : S->getSemanticForm(), Queue)); - ShouldVisitChildren = false; -}) + return true; +} // GenericSelectionExpr is a special case because the types and expressions // are interleaved. We also need to watch out for null types (default Index: unittests/Tooling/RecursiveASTVisitorTest.cpp =================================================================== --- unittests/Tooling/RecursiveASTVisitorTest.cpp +++ unittests/Tooling/RecursiveASTVisitorTest.cpp @@ -158,4 +158,90 @@ "static int k = f();\n")); } +// Check to ensure that InitListExpr is visited twice, once each for the +// syntactic and semantic form. +class InitListExprPreOrderVisitor + : public ExpectedLocationVisitor { +public: + bool VisitInitListExpr(InitListExpr *ILE) { + Match(ILE->isSemanticForm() ? "semantic" : "syntactic", ILE->getLocStart()); + return true; + } +}; + +class InitListExprPostOrderVisitor + : public ExpectedLocationVisitor { +public: + bool shouldTraversePostOrder() const { return true; } + + bool VisitInitListExpr(InitListExpr *ILE) { + Match(ILE->isSemanticForm() ? "semantic" : "syntactic", ILE->getLocStart()); + return true; + } +}; + +class InitListExprPreOrderNoQueueVisitor + : public ExpectedLocationVisitor { +public: + bool TraverseInitListExpr(InitListExpr *ILE) { + return ExpectedLocationVisitor::TraverseInitListExpr(ILE); + } + + bool VisitInitListExpr(InitListExpr *ILE) { + Match(ILE->isSemanticForm() ? "semantic" : "syntactic", ILE->getLocStart()); + return true; + } +}; + +class InitListExprPostOrderNoQueueVisitor + : public ExpectedLocationVisitor { +public: + bool shouldTraversePostOrder() const { return true; } + + bool TraverseInitListExpr(InitListExpr *ILE) { + return ExpectedLocationVisitor::TraverseInitListExpr(ILE); + } + + bool VisitInitListExpr(InitListExpr *ILE) { + Match(ILE->isSemanticForm() ? "semantic" : "syntactic", ILE->getLocStart()); + return true; + } +}; + +TEST(RecursiveASTVisitor, InitListExprIsPreOrderVisitedTwice) { + InitListExprPreOrderVisitor Visitor; + Visitor.ExpectMatch("syntactic", 2, 21); + Visitor.ExpectMatch("semantic", 2, 21); + EXPECT_TRUE(Visitor.runOver("struct S { int x; };\n" + "static struct S s = {.x = 0};\n", + InitListExprPreOrderVisitor::Lang_C)); +} + +TEST(RecursiveASTVisitor, InitListExprIsPostOrderVisitedTwice) { + InitListExprPostOrderVisitor Visitor; + Visitor.ExpectMatch("syntactic", 2, 21); + Visitor.ExpectMatch("semantic", 2, 21); + EXPECT_TRUE(Visitor.runOver("struct S { int x; };\n" + "static struct S s = {.x = 0};\n", + InitListExprPostOrderVisitor::Lang_C)); +} + +TEST(RecursiveASTVisitor, InitListExprIsPreOrderNoQueueVisitedTwice) { + InitListExprPreOrderNoQueueVisitor Visitor; + Visitor.ExpectMatch("syntactic", 2, 21); + Visitor.ExpectMatch("semantic", 2, 21); + EXPECT_TRUE(Visitor.runOver("struct S { int x; };\n" + "static struct S s = {.x = 0};\n", + InitListExprPreOrderNoQueueVisitor::Lang_C)); +} + +TEST(RecursiveASTVisitor, InitListExprIsPostOrderNoQueueVisitedTwice) { + InitListExprPostOrderNoQueueVisitor Visitor; + Visitor.ExpectMatch("syntactic", 2, 21); + Visitor.ExpectMatch("semantic", 2, 21); + EXPECT_TRUE(Visitor.runOver("struct S { int x; };\n" + "static struct S s = {.x = 0};\n", + InitListExprPostOrderNoQueueVisitor::Lang_C)); +} + } // end anonymous namespace