diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2023,7 +2023,8 @@ if (CXXConstructorDecl *Ctor = dyn_cast(D)) { // Constructor initializers. for (auto *I : Ctor->inits()) { - TRY_TO(TraverseConstructorInitializer(I)); + if (I->isWritten() || getDerived().shouldVisitImplicitCode()) + TRY_TO(TraverseConstructorInitializer(I)); } } diff --git a/clang/unittests/Tooling/RecursiveASTVisitorTests/InitListExprPreOrder.cpp b/clang/unittests/Tooling/RecursiveASTVisitorTests/InitListExprPreOrder.cpp --- a/clang/unittests/Tooling/RecursiveASTVisitorTests/InitListExprPreOrder.cpp +++ b/clang/unittests/Tooling/RecursiveASTVisitorTests/InitListExprPreOrder.cpp @@ -22,11 +22,19 @@ bool shouldVisitImplicitCode() const { return VisitImplicitCode; } + bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { + if (Init->getSourceLocation().isInvalid()) + InvalidLocsVisited = true; + Match("initializer", Init->getSourceLocation()); + return true; + } + bool VisitInitListExpr(InitListExpr *ILE) { Match(ILE->isSemanticForm() ? "semantic" : "syntactic", ILE->getBeginLoc()); return true; } + bool InvalidLocsVisited = false; private: bool VisitImplicitCode; }; @@ -49,4 +57,22 @@ InitListExprPreOrderVisitor::Lang_C)); } +TEST(RecursiveASTVisitor, CXXCtorInitializerVisitNoImplicit) { + std::vector Config{true, false}; + for (bool VisitImplCode : Config) { + InitListExprPreOrderVisitor Visitor(VisitImplCode); + Visitor.ExpectMatch("initializer", 7, 17); + EXPECT_TRUE(Visitor.runOver(R"cpp( + class A {}; + class B : public A { + B() {}; + }; + class C : public A { + C() : A() {} + }; + )cpp", + InitListExprPreOrderVisitor::Lang_CXX)); + EXPECT_EQ(Visitor.InvalidLocsVisited, VisitImplCode); + } +} } // end anonymous namespace