https://github.com/alejandro-alvarez-sonarsource updated https://github.com/llvm/llvm-project/pull/109147
From d369d26aad940299eb98ff0c322614043144c558 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20=C3=81lvarez=20Ayll=C3=B3n?= <alejandro.alva...@sonarsource.com> Date: Mon, 24 Jul 2023 13:56:29 +0200 Subject: [PATCH 1/3] [clang] Ignore inline namespace for hasName Add a new flag AlwaysSuppressInlineNamespace to PrintingPolicy that is explicit about *always* removing inline namespaces regardless of ambiguity. Specializing a template from an inline namespace should be transparent to said namespace. For instance ``` namespace foo { inline namespace v1 { template<typename A> void function(A&); } } namespace foo { template<> void function<int>(int&); } ``` `hasName` should match both declarations of `foo::function`. Makes the behavior of `matchesNodeFullSlow` and `matchesNodeFullFast` consistent. --- clang/include/clang/AST/PrettyPrinter.h | 11 +++++-- clang/lib/AST/Decl.cpp | 7 +++-- clang/lib/ASTMatchers/ASTMatchersInternal.cpp | 1 + .../ASTMatchers/ASTMatchersNarrowingTest.cpp | 29 +++++++++++++++++++ 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h index 332ac3c6a004a9..a671211bf3ef93 100644 --- a/clang/include/clang/AST/PrettyPrinter.h +++ b/clang/include/clang/AST/PrettyPrinter.h @@ -61,9 +61,9 @@ struct PrintingPolicy { SuppressTagKeyword(LO.CPlusPlus), IncludeTagDefinition(false), SuppressScope(false), SuppressUnwrittenScope(false), SuppressInlineNamespace(true), SuppressElaboration(false), - SuppressInitializers(false), ConstantArraySizeAsWritten(false), - AnonymousTagLocations(true), SuppressStrongLifetime(false), - SuppressLifetimeQualifiers(false), + AlwaysSuppressInlineNamespace(false), SuppressInitializers(false), + ConstantArraySizeAsWritten(false), AnonymousTagLocations(true), + SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false), SuppressTemplateArgsInCXXConstructors(false), SuppressDefaultTemplateArgs(true), Bool(LO.Bool), Nullptr(LO.CPlusPlus11 || LO.C23), NullptrTypeInNamespace(LO.CPlusPlus), @@ -151,6 +151,11 @@ struct PrintingPolicy { LLVM_PREFERRED_TYPE(bool) unsigned SuppressElaboration : 1; + /// Suppress printing parts of scope specifiers that correspond + /// to inline namespaces, even if the name is ambiguous with the specifier + /// removed. + unsigned AlwaysSuppressInlineNamespace : 1; + /// Suppress printing of variable initializers. /// /// This flag is used when printing the loop variable in a for-range diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index a14b1b33d35efc..a3ac12d58ed044 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1737,8 +1737,11 @@ void NamedDecl::printNestedNameSpecifier(raw_ostream &OS, continue; // Suppress inline namespace if it doesn't make the result ambiguous. - if (P.SuppressInlineNamespace && Ctx->isInlineNamespace() && NameInScope && - cast<NamespaceDecl>(Ctx)->isRedundantInlineQualifierFor(NameInScope)) + if (Ctx->isInlineNamespace() && NameInScope && + (P.AlwaysSuppressInlineNamespace || + (P.SuppressInlineNamespace && + cast<NamespaceDecl>(Ctx)->isRedundantInlineQualifierFor( + NameInScope)))) continue; // Skip non-named contexts such as linkage specifications and ExportDecls. diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp index 06309d327896b3..731fc97707eee7 100644 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -656,6 +656,7 @@ bool HasNameMatcher::matchesNodeFullSlow(const NamedDecl &Node) const { PrintingPolicy Policy = Node.getASTContext().getPrintingPolicy(); Policy.SuppressUnwrittenScope = SkipUnwritten; Policy.SuppressInlineNamespace = SkipUnwritten; + Policy.AlwaysSuppressInlineNamespace = SkipUnwritten; Node.printQualifiedName(OS, Policy); const StringRef FullName = OS.str(); diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp index 611e1f9ba5327c..d696375547acce 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -2599,6 +2599,35 @@ TEST_P(ASTMatchersTest, HasName_MatchesInlinedNamespaces) { EXPECT_TRUE(matches(code, recordDecl(hasName("::a::C")))); } +TEST_P(ASTMatchersTest, HasName_MatchesSpecializedInlinedNamespace) { + if (!GetParam().isCXX11OrLater()) { + return; + } + + StringRef code = R"( +namespace a { + inline namespace v1 { + template<typename T> T foo(T); + } +} + +namespace a { + enum Tag{T1, T2}; + + template <Tag, typename T> T foo(T); +} + +auto v1 = a::foo(1); +auto v2 = a::foo<a::T1>(1); +)"; + EXPECT_TRUE(matches( + code, varDecl(hasName("v1"), hasDescendant(callExpr(callee( + functionDecl(hasName("::a::foo")))))))); + EXPECT_TRUE(matches( + code, varDecl(hasName("v2"), hasDescendant(callExpr(callee( + functionDecl(hasName("::a::foo")))))))); +} + TEST_P(ASTMatchersTest, HasName_MatchesAnonymousNamespaces) { if (!GetParam().isCXX()) { return; From bd40141da6702c2cf16b142b223e19d5b864c6e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20=C3=81lvarez=20Ayll=C3=B3n?= <alejandro.alva...@sonarsource.com> Date: Tue, 24 Sep 2024 08:46:45 +0200 Subject: [PATCH 2/3] Add release notes --- clang/docs/ReleaseNotes.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index b47e06cb0c5d68..ccd3bbee1c2060 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -545,6 +545,9 @@ AST Matchers - Fixed a crash when traverse lambda expr with invalid captures. (#GH106444) +- Ensure hasName matches template specializations across inline namespaces, + making `matchesNodeFullSlow` and `matchesNodeFullFast` consistent. + clang-format ------------ From 3bb9d07215e680bc65bb6c96cceed5a3d7c1f269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20=C3=81lvarez=20Ayll=C3=B3n?= <alejandro.alva...@sonarsource.com> Date: Thu, 10 Oct 2024 10:28:45 +0200 Subject: [PATCH 3/3] Use an enum instead of two flags --- clang/include/clang/AST/PrettyPrinter.h | 18 ++++++++---------- clang/lib/AST/Decl.cpp | 17 +++++++++++------ clang/lib/AST/TypePrinter.cpp | 4 +++- clang/lib/ASTMatchers/ASTMatchersInternal.cpp | 4 ++-- clang/lib/CodeGen/CGDebugInfo.cpp | 2 +- clang/lib/CodeGen/CodeGenTypes.cpp | 2 +- 6 files changed, 26 insertions(+), 21 deletions(-) diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h index a671211bf3ef93..e36c72ffad135c 100644 --- a/clang/include/clang/AST/PrettyPrinter.h +++ b/clang/include/clang/AST/PrettyPrinter.h @@ -55,13 +55,15 @@ class PrintingCallbacks { /// This type is intended to be small and suitable for passing by value. /// It is very frequently copied. struct PrintingPolicy { + enum class SupressInlineNamespaceMode : uint8_t { None, Redundant, All }; + /// Create a default printing policy for the specified language. PrintingPolicy(const LangOptions &LO) : Indentation(2), SuppressSpecifiers(false), SuppressTagKeyword(LO.CPlusPlus), IncludeTagDefinition(false), SuppressScope(false), SuppressUnwrittenScope(false), - SuppressInlineNamespace(true), SuppressElaboration(false), - AlwaysSuppressInlineNamespace(false), SuppressInitializers(false), + SuppressInlineNamespace(SupressInlineNamespaceMode::Redundant), + SuppressElaboration(false), SuppressInitializers(false), ConstantArraySizeAsWritten(false), AnonymousTagLocations(true), SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false), SuppressTemplateArgsInCXXConstructors(false), @@ -141,21 +143,17 @@ struct PrintingPolicy { unsigned SuppressUnwrittenScope : 1; /// Suppress printing parts of scope specifiers that correspond - /// to inline namespaces, where the name is unambiguous with the specifier + /// to inline namespaces. + /// If Redudant, where the name is unambiguous with the specifier removed. + /// If All, even if the name is ambiguous with the specifier /// removed. - LLVM_PREFERRED_TYPE(bool) - unsigned SuppressInlineNamespace : 1; + SupressInlineNamespaceMode SuppressInlineNamespace : 2; /// Ignore qualifiers and tag keywords as specified by elaborated type sugar, /// instead letting the underlying type print as normal. LLVM_PREFERRED_TYPE(bool) unsigned SuppressElaboration : 1; - /// Suppress printing parts of scope specifiers that correspond - /// to inline namespaces, even if the name is ambiguous with the specifier - /// removed. - unsigned AlwaysSuppressInlineNamespace : 1; - /// Suppress printing of variable initializers. /// /// This flag is used when printing the loop variable in a for-range diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index e29088ac7a1fea..d10d0be8db4719 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1737,12 +1737,17 @@ void NamedDecl::printNestedNameSpecifier(raw_ostream &OS, continue; // Suppress inline namespace if it doesn't make the result ambiguous. - if (Ctx->isInlineNamespace() && NameInScope && - (P.AlwaysSuppressInlineNamespace || - (P.SuppressInlineNamespace && - cast<NamespaceDecl>(Ctx)->isRedundantInlineQualifierFor( - NameInScope)))) - continue; + if (Ctx->isInlineNamespace() && NameInScope) { + bool const isRedundant = + cast<NamespaceDecl>(Ctx)->isRedundantInlineQualifierFor(NameInScope); + if (P.SuppressInlineNamespace == + PrintingPolicy::SupressInlineNamespaceMode::All || + (P.SuppressInlineNamespace == + PrintingPolicy::SupressInlineNamespaceMode::Redundant && + isRedundant)) { + continue; + } + } // Skip non-named contexts such as linkage specifications and ExportDecls. const NamedDecl *ND = dyn_cast<NamedDecl>(Ctx); diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index ca75bb97c158e1..fb31bd1c552a9c 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1413,7 +1413,9 @@ void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS, // Only suppress an inline namespace if the name has the same lookup // results in the enclosing namespace. - if (Policy.SuppressInlineNamespace && NS->isInline() && NameInScope && + if (Policy.SuppressInlineNamespace != + PrintingPolicy::SupressInlineNamespaceMode::None && + NS->isInline() && NameInScope && NS->isRedundantInlineQualifierFor(NameInScope)) return AppendScope(DC->getParent(), OS, NameInScope); diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp index 731fc97707eee7..45f3ab894d45d8 100644 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -655,8 +655,8 @@ bool HasNameMatcher::matchesNodeFullSlow(const NamedDecl &Node) const { PrintingPolicy Policy = Node.getASTContext().getPrintingPolicy(); Policy.SuppressUnwrittenScope = SkipUnwritten; - Policy.SuppressInlineNamespace = SkipUnwritten; - Policy.AlwaysSuppressInlineNamespace = SkipUnwritten; + Policy.SuppressInlineNamespace = + PrintingPolicy::SupressInlineNamespaceMode::All; Node.printQualifiedName(OS, Policy); const StringRef FullName = OS.str(); diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 609957b75d6e7e..753f94b3a3a07f 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -287,7 +287,7 @@ PrintingPolicy CGDebugInfo::getPrintingPolicy() const { PP.SplitTemplateClosers = true; } - PP.SuppressInlineNamespace = false; + PP.SuppressInlineNamespace = PrintingPolicy::SupressInlineNamespaceMode::None; PP.PrintCanonicalTypes = true; PP.UsePreferredNames = false; PP.AlwaysIncludeTypeForTemplateArgument = true; diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index 0b486a644f57b1..97b5597635baa6 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -60,7 +60,7 @@ void CodeGenTypes::addRecordTypeName(const RecordDecl *RD, // example, we should probably enable PrintCanonicalTypes and // FullyQualifiedNames. PrintingPolicy Policy = RD->getASTContext().getPrintingPolicy(); - Policy.SuppressInlineNamespace = false; + Policy.SuppressInlineNamespace = PrintingPolicy::SupressInlineNamespaceMode::None; // Name the codegen type after the typedef name // if there is no tag type name available _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits