Index: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h =================================================================== --- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h +++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h @@ -2308,19 +2308,30 @@ return true; } -// This method is called once for each pair of syntactic and semantic -// InitListExpr, and it traverses the subtrees defined by the two forms. This -// may cause some of the children to be visited twice, if they appear both in -// the syntactic and the semantic form. +// If shouldVisitImplicitCode() returns false, this method traverses only the +// syntactic form of InitListExpr. +// If shouldVisitImplicitCode() return true, this method is called once for +// each pair of syntactic and semantic InitListExpr, and it traverses the +// subtrees defined by the two forms. This may cause some of the children to be +// visited twice, if they appear both in the syntactic and the semantic form. // // There is no guarantee about which form \p S takes when this method is called. template bool RecursiveASTVisitor::TraverseInitListExpr( InitListExpr *S, DataRecursionQueue *Queue) { + if (S->isSemanticForm() && S->isSyntacticForm()) { + // `S` does not have alternative forms, traverse only once. + TRY_TO(TraverseSynOrSemInitListExpr(S, Queue)); + return true; + } TRY_TO(TraverseSynOrSemInitListExpr( S->isSemanticForm() ? S->getSyntacticForm() : S, Queue)); - TRY_TO(TraverseSynOrSemInitListExpr( - S->isSemanticForm() ? S : S->getSemanticForm(), Queue)); + if (getDerived().shouldVisitImplicitCode()) { + // Only visit the semantic form if the clients are interested in implicit + // compiler-generated. + TRY_TO(TraverseSynOrSemInitListExpr( + S->isSemanticForm() ? S : S->getSemanticForm(), Queue)); + } return true; } Index: cfe/trunk/unittests/Tooling/RecursiveASTVisitorTests/InitListExprPreOrder.cpp =================================================================== --- cfe/trunk/unittests/Tooling/RecursiveASTVisitorTests/InitListExprPreOrder.cpp +++ cfe/trunk/unittests/Tooling/RecursiveASTVisitorTests/InitListExprPreOrder.cpp @@ -17,14 +17,22 @@ class InitListExprPreOrderVisitor : public ExpectedLocationVisitor { public: + InitListExprPreOrderVisitor(bool VisitImplicitCode) + : VisitImplicitCode(VisitImplicitCode) {} + + bool shouldVisitImplicitCode() const { return VisitImplicitCode; } + bool VisitInitListExpr(InitListExpr *ILE) { Match(ILE->isSemanticForm() ? "semantic" : "syntactic", ILE->getBeginLoc()); return true; } + +private: + bool VisitImplicitCode; }; TEST(RecursiveASTVisitor, InitListExprIsPreOrderVisitedTwice) { - InitListExprPreOrderVisitor Visitor; + InitListExprPreOrderVisitor Visitor(/*VisitImplicitCode=*/true); Visitor.ExpectMatch("syntactic", 2, 21); Visitor.ExpectMatch("semantic", 2, 21); EXPECT_TRUE(Visitor.runOver("struct S { int x; };\n" @@ -32,4 +40,13 @@ InitListExprPreOrderVisitor::Lang_C)); } +TEST(RecursiveASTVisitor, InitListExprVisitedOnceWhenNoImplicit) { + InitListExprPreOrderVisitor Visitor(/*VisitImplicitCode=*/false); + Visitor.ExpectMatch("syntactic", 2, 21); + Visitor.DisallowMatch("semantic", 2, 21); + EXPECT_TRUE(Visitor.runOver("struct S { int x; };\n" + "static struct S s = {.x = 0};\n", + InitListExprPreOrderVisitor::Lang_C)); +} + } // end anonymous namespace