https://github.com/mygitljf updated https://github.com/llvm/llvm-project/pull/206041
>From f34d7896cebb2a33c7f68397ba8dd6c38a5b492c Mon Sep 17 00:00:00 2001 From: mygitljf <[email protected]> Date: Fri, 26 Jun 2026 19:42:36 +0000 Subject: [PATCH 1/2] [clang][AST] Qualify DeclRefExpr printing --- clang/lib/AST/StmtPrinter.cpp | 73 ++++++++++++++----------- clang/unittests/AST/StmtPrinterTest.cpp | 43 +++++++++++++++ clang/unittests/AST/TypePrinterTest.cpp | 24 ++++++++ 3 files changed, 107 insertions(+), 33 deletions(-) diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 6c3294573e9d4..e4dc41cf2c043 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1330,42 +1330,49 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { TPOD->printAsExpr(OS, Policy); return; } - Node->getQualifier().print(OS, Policy); - if (Node->hasTemplateKeyword()) - OS << "template "; - bool ForceAnonymous = Policy.PrintAsCanonical && VD->getKind() == Decl::NonTypeTemplateParm; - DeclarationNameInfo NameInfo = Node->getNameInfo(); - if (IdentifierInfo *ID = NameInfo.getName().getAsIdentifierInfo(); - !ForceAnonymous && - (ID || NameInfo.getName().getNameKind() != DeclarationName::Identifier)) { - if (Policy.CleanUglifiedParameters && - isa<ParmVarDecl, NonTypeTemplateParmDecl>(VD) && ID) - OS << ID->deuglifiedName(); - else - NameInfo.printName(OS, Policy); + bool CleanUglifiedParameter = Policy.CleanUglifiedParameters && + isa<ParmVarDecl, NonTypeTemplateParmDecl>(VD); + + if (Policy.FullyQualifiedName && !ForceAnonymous && !CleanUglifiedParameter) { + VD->printQualifiedName(OS, Policy); } else { - switch (VD->getKind()) { - case Decl::NonTypeTemplateParm: { - auto *TD = cast<NonTypeTemplateParmDecl>(VD); - OS << "value-parameter-" << TD->getDepth() << '-' << TD->getIndex() << ""; - break; - } - case Decl::ParmVar: { - auto *PD = cast<ParmVarDecl>(VD); - OS << "function-parameter-" << PD->getFunctionScopeDepth() << '-' - << PD->getFunctionScopeIndex(); - break; - } - case Decl::Decomposition: - OS << "decomposition"; - for (const auto &I : cast<DecompositionDecl>(VD)->bindings()) - OS << '-' << I->getName(); - break; - default: - OS << "unhandled-anonymous-" << VD->getDeclKindName(); - break; + Node->getQualifier().print(OS, Policy); + if (Node->hasTemplateKeyword()) + OS << "template "; + + DeclarationNameInfo NameInfo = Node->getNameInfo(); + if (IdentifierInfo *ID = NameInfo.getName().getAsIdentifierInfo(); + !ForceAnonymous && (ID || NameInfo.getName().getNameKind() != + DeclarationName::Identifier)) { + if (CleanUglifiedParameter && ID) + OS << ID->deuglifiedName(); + else + NameInfo.printName(OS, Policy); + } else { + switch (VD->getKind()) { + case Decl::NonTypeTemplateParm: { + auto *TD = cast<NonTypeTemplateParmDecl>(VD); + OS << "value-parameter-" << TD->getDepth() << '-' << TD->getIndex() + << ""; + break; + } + case Decl::ParmVar: { + auto *PD = cast<ParmVarDecl>(VD); + OS << "function-parameter-" << PD->getFunctionScopeDepth() << '-' + << PD->getFunctionScopeIndex(); + break; + } + case Decl::Decomposition: + OS << "decomposition"; + for (const auto &I : cast<DecompositionDecl>(VD)->bindings()) + OS << '-' << I->getName(); + break; + default: + OS << "unhandled-anonymous-" << VD->getDeclKindName(); + break; + } } } if (Node->hasExplicitTemplateArgs()) { diff --git a/clang/unittests/AST/StmtPrinterTest.cpp b/clang/unittests/AST/StmtPrinterTest.cpp index 24ad5f30d9480..2b75253fa6698 100644 --- a/clang/unittests/AST/StmtPrinterTest.cpp +++ b/clang/unittests/AST/StmtPrinterTest.cpp @@ -297,6 +297,42 @@ TEST(StmtPrinter, TerseOutputWithLambdas) { [](PrintingPolicy &PP) { PP.TerseOutput = true; })); } +TEST(StmtPrinter, FullyQualifiedDeclRefExpr) { + auto FullyQualified = [](PrintingPolicy &Policy) { + Policy.FullyQualifiedName = true; + }; + + ASSERT_TRUE(PrintedStmtCXXMatches( + StdVer::CXX17, + R"cpp( + namespace ns { int value; } + using namespace ns; + void A() { (void)value; } + )cpp", + declRefExpr(to(varDecl(hasName("::ns::value")))).bind("id"), "ns::value", + FullyQualified)); + + ASSERT_TRUE(PrintedStmtCXXMatches( + StdVer::CXX17, + R"cpp( + namespace ns { template <class T> void func(); } + using namespace ns; + void A() { func<int>(); } + )cpp", + declRefExpr(to(functionDecl(hasName("::ns::func")))).bind("id"), + "ns::func<int>", FullyQualified)); + + ASSERT_TRUE(PrintedStmtCXXMatches( + StdVer::CXX17, "void A(int param) { (void)param; }", + declRefExpr(to(parmVarDecl(hasName("param")))).bind("id"), "param", + FullyQualified)); + + ASSERT_TRUE(PrintedStmtCXXMatches( + StdVer::CXX17, "void A() { int local = 0; (void)local; }", + declRefExpr(to(varDecl(hasName("local")))).bind("id"), "local", + FullyQualified)); +} + TEST(StmtPrinter, ParamsUglified) { llvm::StringLiteral Code = R"cpp( template <typename _T, int _I, template <typename> class _C> @@ -307,6 +343,10 @@ TEST(StmtPrinter, ParamsUglified) { auto Clean = [](PrintingPolicy &Policy) { Policy.CleanUglifiedParameters = true; }; + auto CleanFullyQualified = [](PrintingPolicy &Policy) { + Policy.CleanUglifiedParameters = true; + Policy.FullyQualifiedName = true; + }; ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX14, Code, returnStmt().bind("id"), @@ -314,4 +354,7 @@ TEST(StmtPrinter, ParamsUglified) { ASSERT_TRUE( PrintedStmtCXXMatches(StdVer::CXX14, Code, returnStmt().bind("id"), "return typename C<T>::_F(I, j);\n", Clean)); + ASSERT_TRUE(PrintedStmtCXXMatches( + StdVer::CXX14, Code, returnStmt().bind("id"), + "return typename _C<T>::_F(I, j);\n", CleanFullyQualified)); } diff --git a/clang/unittests/AST/TypePrinterTest.cpp b/clang/unittests/AST/TypePrinterTest.cpp index 5023b5e093ec3..79f75909c57b5 100644 --- a/clang/unittests/AST/TypePrinterTest.cpp +++ b/clang/unittests/AST/TypePrinterTest.cpp @@ -121,6 +121,30 @@ TEST(TypePrinter, TemplateSpecializationFullyQualified) { [](PrintingPolicy &Policy) { Policy.FullyQualifiedName = true; })); } +TEST(TypePrinter, TemplateArgumentExpressionFullyQualified) { + llvm::StringLiteral Code = R"cpp( + namespace ns { + template <class T> inline constexpr bool pred_v = sizeof(T) > 0; + template <bool, class T> struct ei {}; + template <class T> struct ei<true, T> { using type = T; }; + template <bool B, class T> using enable_if_t = typename ei<B, T>::type; + struct Ret {}; + template <class T> enable_if_t<pred_v<T>, Ret> f() { return {}; } + } + inline auto *ns_f_int = &ns::f<int>; + )cpp"; + + auto Matcher = functionDecl(hasName("::ns::f"), isTemplateInstantiation(), + returns(qualType().bind("id"))); + ASSERT_TRUE(PrintedTypeMatches( + Code, {"-std=c++17"}, Matcher, "enable_if_t<pred_v<int>, Ret>", + [](PrintingPolicy &Policy) { Policy.FullyQualifiedName = false; })); + ASSERT_TRUE(PrintedTypeMatches( + Code, {"-std=c++17"}, Matcher, + "ns::enable_if_t<ns::pred_v<int>, ns::Ret>", + [](PrintingPolicy &Policy) { Policy.FullyQualifiedName = true; })); +} + TEST(TypePrinter, TemplateIdWithNTTP) { constexpr char Code[] = R"cpp( template <int N> >From 8a84ede955841c8605f580bd975ddef369beb3b1 Mon Sep 17 00:00:00 2001 From: mygitljf <[email protected]> Date: Sat, 27 Jun 2026 10:35:22 +0000 Subject: [PATCH 2/2] [clang][docs] Add AST printer release note --- clang/docs/ReleaseNotes.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index d1303d4c98507..f8e307a4510cc 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -125,6 +125,10 @@ AST Dumping Potentially Breaking Changes fields were missing from the JSON output. - Colons that appear at the end of a ParamCommentCommand name are not serialized as part of the name. +- AST pretty-printing now respects ``PrintingPolicy::FullyQualifiedName`` when + printing ``DeclRefExpr`` names, including expression-form non-type template + arguments in printed types. Previously, these references could be printed + unqualified. (#GH206041) Clang Frontend Potentially Breaking Changes ------------------------------------------- _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
