]> granicus.if.org Git - clang/commitdiff
Make sure TraverseInitListExpr visits InitListExpr exactly twice
authorStephan Bergmann <sbergman@redhat.com>
Tue, 27 Jun 2017 08:04:08 +0000 (08:04 +0000)
committerStephan Bergmann <sbergman@redhat.com>
Tue, 27 Jun 2017 08:04:08 +0000 (08:04 +0000)
... 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

include/clang/AST/RecursiveASTVisitor.h
unittests/Tooling/RecursiveASTVisitorTest.cpp

index ad3f40d0d3f64cfd2ad55e173944e5f32a252f69..152e05bca740a3b6c4f66bc6c1634255675a9b61 100644 (file)
@@ -593,6 +593,16 @@ bool RecursiveASTVisitor<Derived>::PostVisitStmt(Stmt *S) {
 #define STMT(CLASS, PARENT)                                                    \
   case Stmt::CLASS##Class:                                                     \
     TRY_TO(WalkUpFrom##CLASS(static_cast<CLASS *>(S))); break;
+#define INITLISTEXPR(CLASS, PARENT)                                            \
+  case Stmt::CLASS##Class:                                                     \
+    {                                                                          \
+      auto ILE = static_cast<CLASS *>(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<Derived>::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 <typename Derived>
+bool RecursiveASTVisitor<Derived>::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 269bdbb34ab139537c4d107b34c98ca9da605138..74c9c3db34d89f2d7efe39ca88cb39a9491f45c9 100644 (file)
@@ -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<InitListExprPreOrderVisitor> {
+public:
+  bool VisitInitListExpr(InitListExpr *ILE) {
+    Match(ILE->isSemanticForm() ? "semantic" : "syntactic", ILE->getLocStart());
+    return true;
+  }
+};
+
+class InitListExprPostOrderVisitor
+    : public ExpectedLocationVisitor<InitListExprPostOrderVisitor> {
+public:
+  bool shouldTraversePostOrder() const { return true; }
+
+  bool VisitInitListExpr(InitListExpr *ILE) {
+    Match(ILE->isSemanticForm() ? "semantic" : "syntactic", ILE->getLocStart());
+    return true;
+  }
+};
+
+class InitListExprPreOrderNoQueueVisitor
+    : public ExpectedLocationVisitor<InitListExprPreOrderNoQueueVisitor> {
+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<InitListExprPostOrderNoQueueVisitor> {
+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