[clang] [clang][AST] Qualify DeclRefExpr printing (PR #206041)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 26 05:01:10 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: mygitljf
<details>
<summary>Changes</summary>
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
---
Full diff: https://github.com/llvm/llvm-project/pull/206041.diff
3 Files Affected:
- (modified) clang/lib/AST/StmtPrinter.cpp (+40-33)
- (modified) clang/unittests/AST/StmtPrinterTest.cpp (+43)
- (modified) clang/unittests/AST/TypePrinterTest.cpp (+24)
``````````diff
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>
``````````
</details>
https://github.com/llvm/llvm-project/pull/206041
More information about the cfe-commits
mailing list