Index: include/clang/AST/PrettyPrinter.h =================================================================== --- include/clang/AST/PrettyPrinter.h +++ include/clang/AST/PrettyPrinter.h @@ -51,7 +51,8 @@ TerseOutput(false), PolishForDeclaration(false), Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar), IncludeNewlines(true), MSVCFormatting(false), - ConstantsAsWritten(false), SuppressImplicitBase(false) { } + ConstantsAsWritten(false), SuppressImplicitBase(false), + FullyQualifiedName(false) { } /// Adjust this printing policy for cases where it's known that we're /// printing C++ code (for instance, if AST dumping reaches a C++-only @@ -220,6 +221,10 @@ /// When true, don't print the implicit 'self' or 'this' expressions. bool SuppressImplicitBase : 1; + + /// When true, print the fully qualified name of function declarations. + /// This is the opposite of SuppressScope and thus overrules it. + bool FullyQualifiedName : 1; }; } // end namespace clang Index: lib/AST/DeclPrinter.cpp =================================================================== --- lib/AST/DeclPrinter.cpp +++ lib/AST/DeclPrinter.cpp @@ -513,13 +513,19 @@ PrintingPolicy SubPolicy(Policy); SubPolicy.SuppressSpecifiers = false; std::string Proto; - if (!Policy.SuppressScope) { - if (const NestedNameSpecifier *NS = D->getQualifier()) { - llvm::raw_string_ostream OS(Proto); - NS->print(OS, Policy); + + if (Policy.FullyQualifiedName) { + Proto += D->getQualifiedNameAsString(); + } else { + if (!Policy.SuppressScope) { + if (const NestedNameSpecifier *NS = D->getQualifier()) { + llvm::raw_string_ostream OS(Proto); + NS->print(OS, Policy); + } } + Proto += D->getNameInfo().getAsString(); } - Proto += D->getNameInfo().getAsString(); + if (GuideDecl) Proto = GuideDecl->getDeducedTemplate()->getDeclName().getAsString(); if (const TemplateArgumentList *TArgs = D->getTemplateSpecializationArgs()) { @@ -608,66 +614,69 @@ } if (CDecl) { - bool HasInitializerList = false; - for (const auto *BMInitializer : CDecl->inits()) { - if (BMInitializer->isInClassMemberInitializer()) - continue; - - if (!HasInitializerList) { - Proto += " : "; - Out << Proto; - Proto.clear(); - HasInitializerList = true; - } else - Out << ", "; + if (!Policy.TerseOutput) { + bool HasInitializerList = false; + for (const auto *BMInitializer : CDecl->inits()) { + if (BMInitializer->isInClassMemberInitializer()) + continue; - if (BMInitializer->isAnyMemberInitializer()) { - FieldDecl *FD = BMInitializer->getAnyMember(); - Out << *FD; - } else { - Out << QualType(BMInitializer->getBaseClass(), 0).getAsString(Policy); - } - - Out << "("; - if (!BMInitializer->getInit()) { - // Nothing to print - } else { - Expr *Init = BMInitializer->getInit(); - if (ExprWithCleanups *Tmp = dyn_cast(Init)) - Init = Tmp->getSubExpr(); - - Init = Init->IgnoreParens(); - - Expr *SimpleInit = nullptr; - Expr **Args = nullptr; - unsigned NumArgs = 0; - if (ParenListExpr *ParenList = dyn_cast(Init)) { - Args = ParenList->getExprs(); - NumArgs = ParenList->getNumExprs(); - } else if (CXXConstructExpr *Construct - = dyn_cast(Init)) { - Args = Construct->getArgs(); - NumArgs = Construct->getNumArgs(); + if (!HasInitializerList) { + Proto += " : "; + Out << Proto; + Proto.clear(); + HasInitializerList = true; } else - SimpleInit = Init; - - if (SimpleInit) - SimpleInit->printPretty(Out, nullptr, Policy, Indentation); - else { - for (unsigned I = 0; I != NumArgs; ++I) { - assert(Args[I] != nullptr && "Expected non-null Expr"); - if (isa(Args[I])) - break; - - if (I) - Out << ", "; - Args[I]->printPretty(Out, nullptr, Policy, Indentation); + Out << ", "; + + if (BMInitializer->isAnyMemberInitializer()) { + FieldDecl *FD = BMInitializer->getAnyMember(); + Out << *FD; + } else { + Out << QualType(BMInitializer->getBaseClass(), 0) + .getAsString(Policy); + } + + Out << "("; + if (!BMInitializer->getInit()) { + // Nothing to print + } else { + Expr *Init = BMInitializer->getInit(); + if (ExprWithCleanups *Tmp = dyn_cast(Init)) + Init = Tmp->getSubExpr(); + + Init = Init->IgnoreParens(); + + Expr *SimpleInit = nullptr; + Expr **Args = nullptr; + unsigned NumArgs = 0; + if (ParenListExpr *ParenList = dyn_cast(Init)) { + Args = ParenList->getExprs(); + NumArgs = ParenList->getNumExprs(); + } else if (CXXConstructExpr *Construct = + dyn_cast(Init)) { + Args = Construct->getArgs(); + NumArgs = Construct->getNumArgs(); + } else + SimpleInit = Init; + + if (SimpleInit) + SimpleInit->printPretty(Out, nullptr, Policy, Indentation); + else { + for (unsigned I = 0; I != NumArgs; ++I) { + assert(Args[I] != nullptr && "Expected non-null Expr"); + if (isa(Args[I])) + break; + + if (I) + Out << ", "; + Args[I]->printPretty(Out, nullptr, Policy, Indentation); + } } } + Out << ")"; + if (BMInitializer->isPackExpansion()) + Out << "..."; } - Out << ")"; - if (BMInitializer->isPackExpansion()) - Out << "..."; } } else if (!ConversionDecl && !isa(D)) { if (FT && FT->hasTrailingReturn()) { @@ -712,7 +721,7 @@ if (D->getBody()) D->getBody()->printPretty(Out, nullptr, SubPolicy, Indentation); } else { - if (isa(*D)) + if (!Policy.TerseOutput && isa(*D)) Out << " {}"; } } Index: test/Index/comment-cplus-decls.cpp =================================================================== --- test/Index/comment-cplus-decls.cpp +++ test/Index/comment-cplus-decls.cpp @@ -46,7 +46,7 @@ data* reserved; }; // CHECK: class Test {} -// CHECK: Test() : reserved(new Test::data()) {} +// CHECK: Test() // CHECK: unsigned int getID() const // CHECK: ~Test(){{( noexcept)?}} // CHECK: Test::data *reserved Index: unittests/AST/DeclPrinterTest.cpp =================================================================== --- unittests/AST/DeclPrinterTest.cpp +++ unittests/AST/DeclPrinterTest.cpp @@ -31,18 +31,25 @@ namespace { -void PrintDecl(raw_ostream &Out, const ASTContext *Context, const Decl *D) { +using PrintingPolicyModifier = void (*)(PrintingPolicy &policy); + +void PrintDecl(raw_ostream &Out, const ASTContext *Context, const Decl *D, + PrintingPolicyModifier PolicyModifier) { PrintingPolicy Policy = Context->getPrintingPolicy(); Policy.TerseOutput = true; + if (PolicyModifier) + PolicyModifier(Policy); D->print(Out, Policy, /*Indentation*/ 0, /*PrintInstantiation*/ false); } class PrintMatch : public MatchFinder::MatchCallback { SmallString<1024> Printed; unsigned NumFoundDecls; + PrintingPolicyModifier PolicyModifier; public: - PrintMatch() : NumFoundDecls(0) {} + PrintMatch(PrintingPolicyModifier PolicyModifier) + : NumFoundDecls(0), PolicyModifier(PolicyModifier) {} void run(const MatchFinder::MatchResult &Result) override { const Decl *D = Result.Nodes.getNodeAs("id"); @@ -53,7 +60,7 @@ return; llvm::raw_svector_ostream Out(Printed); - PrintDecl(Out, Result.Context, D); + PrintDecl(Out, Result.Context, D, PolicyModifier); } StringRef getPrinted() const { @@ -65,13 +72,12 @@ } }; -::testing::AssertionResult PrintedDeclMatches( - StringRef Code, - const std::vector &Args, - const DeclarationMatcher &NodeMatch, - StringRef ExpectedPrinted, - StringRef FileName) { - PrintMatch Printer; +::testing::AssertionResult +PrintedDeclMatches(StringRef Code, const std::vector &Args, + const DeclarationMatcher &NodeMatch, + StringRef ExpectedPrinted, StringRef FileName, + PrintingPolicyModifier PolicyModifier = nullptr) { + PrintMatch Printer(PolicyModifier); MatchFinder Finder; Finder.addMatcher(NodeMatch, &Printer); std::unique_ptr Factory( @@ -98,27 +104,30 @@ return ::testing::AssertionSuccess(); } -::testing::AssertionResult PrintedDeclCXX98Matches(StringRef Code, - StringRef DeclName, - StringRef ExpectedPrinted) { +::testing::AssertionResult +PrintedDeclCXX98Matches(StringRef Code, StringRef DeclName, + StringRef ExpectedPrinted, + PrintingPolicyModifier PolicyModifier = nullptr) { std::vector Args(1, "-std=c++98"); return PrintedDeclMatches(Code, Args, namedDecl(hasName(DeclName)).bind("id"), ExpectedPrinted, - "input.cc"); + "input.cc", + PolicyModifier); } -::testing::AssertionResult PrintedDeclCXX98Matches( - StringRef Code, - const DeclarationMatcher &NodeMatch, - StringRef ExpectedPrinted) { +::testing::AssertionResult +PrintedDeclCXX98Matches(StringRef Code, const DeclarationMatcher &NodeMatch, + StringRef ExpectedPrinted, + PrintingPolicyModifier PolicyModifier = nullptr) { std::vector Args(1, "-std=c++98"); return PrintedDeclMatches(Code, Args, NodeMatch, ExpectedPrinted, - "input.cc"); + "input.cc", + PolicyModifier); } ::testing::AssertionResult PrintedDeclCXX11Matches(StringRef Code, @@ -343,6 +352,47 @@ "void A()")); } +TEST(DeclPrinter, TestFreeFunctionDecl_FullyQualifiedName) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "void A();", + "A", + "void A()", + [](PrintingPolicy &Policy){ Policy.FullyQualifiedName = true; })); +} + +TEST(DeclPrinter, TestFreeFunctionDeclInNamespace_FullyQualifiedName) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "namespace X { void A(); };", + "A", + "void X::A()", + [](PrintingPolicy &Policy){ Policy.FullyQualifiedName = true; })); +} + +TEST(DeclPrinter, TestMemberFunction_FullyQualifiedName) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct X { void A(); };", + "A", + "void X::A()", + [](PrintingPolicy &Policy){ Policy.FullyQualifiedName = true; })); +} + +TEST(DeclPrinter, TestMemberFunctionInNamespace_FullyQualifiedName) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "namespace Z { struct X { void A(); }; }", + "A", + "void Z::X::A()", + [](PrintingPolicy &Policy){ Policy.FullyQualifiedName = true; })); +} + +TEST(DeclPrinter, TestMemberFunctionOutside_FullyQualifiedName) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct X { void A(); };" + "void X::A() {}", + functionDecl(hasName("A"), isDefinition()).bind("id"), + "void X::A()", + [](PrintingPolicy &Policy){ Policy.FullyQualifiedName = true; })); +} + TEST(DeclPrinter, TestFunctionDecl2) { ASSERT_TRUE(PrintedDeclCXX98Matches( "void A() {}", @@ -478,6 +528,27 @@ "A(const A &a, int = 0)")); } +TEST(DeclPrinter, TestCXXConstructorDeclWithMemberInitializer) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct A {" + " int m;" + " A() : m(2) {}" + "};", + cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), + "A()")); +} + +TEST(DeclPrinter, TestCXXConstructorDeclWithMemberInitializer_NoTerseOutput) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct A {" + " int m;" + " A() : m(2) {}" + "};", + cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), + "A() : m(2) {\n}\n", + [](PrintingPolicy &Policy){ Policy.TerseOutput = false; })); +} + TEST(DeclPrinter, TestCXXConstructorDecl5) { ASSERT_TRUE(PrintedDeclCXX11Matches( "struct A {" @@ -540,7 +611,7 @@ " A(T&&... ts) : T(ts)... {}" "};", cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), - "A(T &&...ts) : T(ts)... {}")); + "A(T &&...ts)")); } TEST(DeclPrinter, TestCXXDestructorDecl1) {