Author: lianjinfeng2003 Date: 2026-07-07T10:16:21+02:00 New Revision: 70646dd3eda3e64fc94b44d7403f946cd7455b92
URL: https://github.com/llvm/llvm-project/commit/70646dd3eda3e64fc94b44d7403f946cd7455b92 DIFF: https://github.com/llvm/llvm-project/commit/70646dd3eda3e64fc94b44d7403f946cd7455b92.diff LOG: [clang][AST] Qualify DeclRefExpr printing (#206041) I updated DeclRefExpr printing so fully-qualified printing consistently uses declaration ownership rather than only the written qualifier. This also preserves existing behavior for local names and cleaned parameter names. The added tests cover both the direct expression printer behavior and the original type-printing scenario that exposed the missing qualification. Fixes #205925 Added: Modified: clang/docs/ReleaseNotes.md clang/lib/AST/StmtPrinter.cpp clang/unittests/AST/StmtPrinterTest.cpp clang/unittests/AST/TypePrinterTest.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 9683dec78cec1..a37e1be5862b3 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -165,6 +165,10 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the 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 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> _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
