From: Stephan Bergmann Date: Tue, 27 Jun 2017 08:04:08 +0000 (+0000) Subject: Make sure TraverseInitListExpr visits InitListExpr exactly twice X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1c3de69555dec079e21aa5b223f7117add0719f4;p=clang Make sure TraverseInitListExpr visits InitListExpr exactly twice ... once each for the syntactic and semantic form. Without this fix, behavior of the newly added tests would have been InitListExprIsPreOrderVisitedTwice: syntactic: 1 semantic: 2 InitListExprIsPostOrderVisitedTwice: syntactic: 0 semantic: 1 InitListExprIsPreOrderNoQueueVisitedTwice: syntactic: 1 semantic: 2 InitListExprIsPostOrderNoQueueVisitedTwice: syntactic: 0 semantic: 2 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@306374 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index ad3f40d0d3..152e05bca7 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -593,6 +593,16 @@ bool RecursiveASTVisitor::PostVisitStmt(Stmt *S) { #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" } @@ -2220,13 +2230,15 @@ bool RecursiveASTVisitor::TraverseSynOrSemInitListExpr( // 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 diff --git a/unittests/Tooling/RecursiveASTVisitorTest.cpp b/unittests/Tooling/RecursiveASTVisitorTest.cpp index 269bdbb34a..74c9c3db34 100644 --- a/unittests/Tooling/RecursiveASTVisitorTest.cpp +++ b/unittests/Tooling/RecursiveASTVisitorTest.cpp @@ -158,4 +158,90 @@ TEST(RecursiveASTVisitor, DefaultArgumentsAreVisited) { "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