[clang] bd12729 - [clang] Ignore inline namespace for `hasName` (#109147)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 11 06:23:51 PDT 2024
Author: Alejandro Álvarez Ayllón
Date: 2024-10-11T09:23:47-04:00
New Revision: bd12729a828c653da53f7182dda29982123913db
URL: https://github.com/llvm/llvm-project/commit/bd12729a828c653da53f7182dda29982123913db
DIFF: https://github.com/llvm/llvm-project/commit/bd12729a828c653da53f7182dda29982123913db.diff
LOG: [clang] Ignore inline namespace for `hasName` (#109147)
Add a new enumeration `SuppressInlineNamespaceMode` to `PrintingPolicy` that
is explicit about how to handle inline namespaces. `SuppressInlineNamespace`
uses that enumeration now instead of a Boolean value.
Specializing a template from an inline namespace should be transparent.
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, fixing an assert inside `HasNameMatcher::matchesNode`.
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/AST/PrettyPrinter.h
clang/lib/AST/Decl.cpp
clang/lib/AST/TypePrinter.cpp
clang/lib/ASTMatchers/ASTMatchersInternal.cpp
clang/lib/CodeGen/CGDebugInfo.cpp
clang/lib/CodeGen/CodeGenTypes.cpp
clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 7063fea41efda1..763bc3ac159322 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -647,6 +647,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
------------
diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h
index 332ac3c6a004a9..91818776b770cf 100644
--- a/clang/include/clang/AST/PrettyPrinter.h
+++ b/clang/include/clang/AST/PrettyPrinter.h
@@ -55,15 +55,17 @@ class PrintingCallbacks {
/// This type is intended to be small and suitable for passing by value.
/// It is very frequently copied.
struct PrintingPolicy {
+ enum SuppressInlineNamespaceMode : 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),
- SuppressInitializers(false), ConstantArraySizeAsWritten(false),
- AnonymousTagLocations(true), SuppressStrongLifetime(false),
- SuppressLifetimeQualifiers(false),
+ SuppressInlineNamespace(SuppressInlineNamespaceMode::Redundant),
+ SuppressElaboration(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),
@@ -141,10 +143,12 @@ 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;
+ LLVM_PREFERRED_TYPE(SuppressInlineNamespaceMode)
+ unsigned SuppressInlineNamespace : 2;
/// Ignore qualifiers and tag keywords as specified by elaborated type sugar,
/// instead letting the underlying type print as normal.
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 84ef9f74582ef6..a2f5b4183bbd23 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -1737,9 +1737,17 @@ 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))
- continue;
+ if (Ctx->isInlineNamespace() && NameInScope) {
+ bool isRedundant =
+ cast<NamespaceDecl>(Ctx)->isRedundantInlineQualifierFor(NameInScope);
+ if (P.SuppressInlineNamespace ==
+ PrintingPolicy::SuppressInlineNamespaceMode::All ||
+ (P.SuppressInlineNamespace ==
+ PrintingPolicy::SuppressInlineNamespaceMode::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..008e87e7e5c14b 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::SuppressInlineNamespaceMode::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 06309d327896b3..46dd44e6f2b24f 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -655,7 +655,9 @@ bool HasNameMatcher::matchesNodeFullSlow(const NamedDecl &Node) const {
PrintingPolicy Policy = Node.getASTContext().getPrintingPolicy();
Policy.SuppressUnwrittenScope = SkipUnwritten;
- Policy.SuppressInlineNamespace = SkipUnwritten;
+ Policy.SuppressInlineNamespace =
+ SkipUnwritten ? PrintingPolicy::SuppressInlineNamespaceMode::All
+ : PrintingPolicy::SuppressInlineNamespaceMode::None;
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..06015a9e541ea2 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -287,7 +287,8 @@ PrintingPolicy CGDebugInfo::getPrintingPolicy() const {
PP.SplitTemplateClosers = true;
}
- PP.SuppressInlineNamespace = false;
+ PP.SuppressInlineNamespace =
+ PrintingPolicy::SuppressInlineNamespaceMode::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..339632090a5b71 100644
--- a/clang/lib/CodeGen/CodeGenTypes.cpp
+++ b/clang/lib/CodeGen/CodeGenTypes.cpp
@@ -60,7 +60,8 @@ 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::SuppressInlineNamespaceMode::None;
// Name the codegen type after the typedef name
// if there is no tag type name available
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;
More information about the cfe-commits
mailing list