Skip to content

Commit bd12729

Browse files
[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`.
1 parent c3a10dc commit bd12729

File tree

8 files changed

+64
-14
lines changed

8 files changed

+64
-14
lines changed

clang/docs/ReleaseNotes.rst

+3
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,9 @@ AST Matchers
647647

648648
- Fixed a crash when traverse lambda expr with invalid captures. (#GH106444)
649649

650+
- Ensure ``hasName`` matches template specializations across inline namespaces,
651+
making `matchesNodeFullSlow` and `matchesNodeFullFast` consistent.
652+
650653
clang-format
651654
------------
652655

clang/include/clang/AST/PrettyPrinter.h

+11-7
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,17 @@ class PrintingCallbacks {
5555
/// This type is intended to be small and suitable for passing by value.
5656
/// It is very frequently copied.
5757
struct PrintingPolicy {
58+
enum SuppressInlineNamespaceMode : uint8_t { None, Redundant, All };
59+
5860
/// Create a default printing policy for the specified language.
5961
PrintingPolicy(const LangOptions &LO)
6062
: Indentation(2), SuppressSpecifiers(false),
6163
SuppressTagKeyword(LO.CPlusPlus), IncludeTagDefinition(false),
6264
SuppressScope(false), SuppressUnwrittenScope(false),
63-
SuppressInlineNamespace(true), SuppressElaboration(false),
64-
SuppressInitializers(false), ConstantArraySizeAsWritten(false),
65-
AnonymousTagLocations(true), SuppressStrongLifetime(false),
66-
SuppressLifetimeQualifiers(false),
65+
SuppressInlineNamespace(SuppressInlineNamespaceMode::Redundant),
66+
SuppressElaboration(false), SuppressInitializers(false),
67+
ConstantArraySizeAsWritten(false), AnonymousTagLocations(true),
68+
SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false),
6769
SuppressTemplateArgsInCXXConstructors(false),
6870
SuppressDefaultTemplateArgs(true), Bool(LO.Bool),
6971
Nullptr(LO.CPlusPlus11 || LO.C23), NullptrTypeInNamespace(LO.CPlusPlus),
@@ -141,10 +143,12 @@ struct PrintingPolicy {
141143
unsigned SuppressUnwrittenScope : 1;
142144

143145
/// Suppress printing parts of scope specifiers that correspond
144-
/// to inline namespaces, where the name is unambiguous with the specifier
146+
/// to inline namespaces.
147+
/// If Redudant, where the name is unambiguous with the specifier removed.
148+
/// If All, even if the name is ambiguous with the specifier
145149
/// removed.
146-
LLVM_PREFERRED_TYPE(bool)
147-
unsigned SuppressInlineNamespace : 1;
150+
LLVM_PREFERRED_TYPE(SuppressInlineNamespaceMode)
151+
unsigned SuppressInlineNamespace : 2;
148152

149153
/// Ignore qualifiers and tag keywords as specified by elaborated type sugar,
150154
/// instead letting the underlying type print as normal.

clang/lib/AST/Decl.cpp

+11-3
Original file line numberDiff line numberDiff line change
@@ -1737,9 +1737,17 @@ void NamedDecl::printNestedNameSpecifier(raw_ostream &OS,
17371737
continue;
17381738

17391739
// Suppress inline namespace if it doesn't make the result ambiguous.
1740-
if (P.SuppressInlineNamespace && Ctx->isInlineNamespace() && NameInScope &&
1741-
cast<NamespaceDecl>(Ctx)->isRedundantInlineQualifierFor(NameInScope))
1742-
continue;
1740+
if (Ctx->isInlineNamespace() && NameInScope) {
1741+
bool isRedundant =
1742+
cast<NamespaceDecl>(Ctx)->isRedundantInlineQualifierFor(NameInScope);
1743+
if (P.SuppressInlineNamespace ==
1744+
PrintingPolicy::SuppressInlineNamespaceMode::All ||
1745+
(P.SuppressInlineNamespace ==
1746+
PrintingPolicy::SuppressInlineNamespaceMode::Redundant &&
1747+
isRedundant)) {
1748+
continue;
1749+
}
1750+
}
17431751

17441752
// Skip non-named contexts such as linkage specifications and ExportDecls.
17451753
const NamedDecl *ND = dyn_cast<NamedDecl>(Ctx);

clang/lib/AST/TypePrinter.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -1413,7 +1413,9 @@ void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS,
14131413

14141414
// Only suppress an inline namespace if the name has the same lookup
14151415
// results in the enclosing namespace.
1416-
if (Policy.SuppressInlineNamespace && NS->isInline() && NameInScope &&
1416+
if (Policy.SuppressInlineNamespace !=
1417+
PrintingPolicy::SuppressInlineNamespaceMode::None &&
1418+
NS->isInline() && NameInScope &&
14171419
NS->isRedundantInlineQualifierFor(NameInScope))
14181420
return AppendScope(DC->getParent(), OS, NameInScope);
14191421

clang/lib/ASTMatchers/ASTMatchersInternal.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,9 @@ bool HasNameMatcher::matchesNodeFullSlow(const NamedDecl &Node) const {
655655

656656
PrintingPolicy Policy = Node.getASTContext().getPrintingPolicy();
657657
Policy.SuppressUnwrittenScope = SkipUnwritten;
658-
Policy.SuppressInlineNamespace = SkipUnwritten;
658+
Policy.SuppressInlineNamespace =
659+
SkipUnwritten ? PrintingPolicy::SuppressInlineNamespaceMode::All
660+
: PrintingPolicy::SuppressInlineNamespaceMode::None;
659661
Node.printQualifiedName(OS, Policy);
660662

661663
const StringRef FullName = OS.str();

clang/lib/CodeGen/CGDebugInfo.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,8 @@ PrintingPolicy CGDebugInfo::getPrintingPolicy() const {
287287
PP.SplitTemplateClosers = true;
288288
}
289289

290-
PP.SuppressInlineNamespace = false;
290+
PP.SuppressInlineNamespace =
291+
PrintingPolicy::SuppressInlineNamespaceMode::None;
291292
PP.PrintCanonicalTypes = true;
292293
PP.UsePreferredNames = false;
293294
PP.AlwaysIncludeTypeForTemplateArgument = true;

clang/lib/CodeGen/CodeGenTypes.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ void CodeGenTypes::addRecordTypeName(const RecordDecl *RD,
6060
// example, we should probably enable PrintCanonicalTypes and
6161
// FullyQualifiedNames.
6262
PrintingPolicy Policy = RD->getASTContext().getPrintingPolicy();
63-
Policy.SuppressInlineNamespace = false;
63+
Policy.SuppressInlineNamespace =
64+
PrintingPolicy::SuppressInlineNamespaceMode::None;
6465

6566
// Name the codegen type after the typedef name
6667
// if there is no tag type name available

clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp

+29
Original file line numberDiff line numberDiff line change
@@ -2599,6 +2599,35 @@ TEST_P(ASTMatchersTest, HasName_MatchesInlinedNamespaces) {
25992599
EXPECT_TRUE(matches(code, recordDecl(hasName("::a::C"))));
26002600
}
26012601

2602+
TEST_P(ASTMatchersTest, HasName_MatchesSpecializedInlinedNamespace) {
2603+
if (!GetParam().isCXX11OrLater()) {
2604+
return;
2605+
}
2606+
2607+
StringRef code = R"(
2608+
namespace a {
2609+
inline namespace v1 {
2610+
template<typename T> T foo(T);
2611+
}
2612+
}
2613+
2614+
namespace a {
2615+
enum Tag{T1, T2};
2616+
2617+
template <Tag, typename T> T foo(T);
2618+
}
2619+
2620+
auto v1 = a::foo(1);
2621+
auto v2 = a::foo<a::T1>(1);
2622+
)";
2623+
EXPECT_TRUE(matches(
2624+
code, varDecl(hasName("v1"), hasDescendant(callExpr(callee(
2625+
functionDecl(hasName("::a::foo"))))))));
2626+
EXPECT_TRUE(matches(
2627+
code, varDecl(hasName("v2"), hasDescendant(callExpr(callee(
2628+
functionDecl(hasName("::a::foo"))))))));
2629+
}
2630+
26022631
TEST_P(ASTMatchersTest, HasName_MatchesAnonymousNamespaces) {
26032632
if (!GetParam().isCXX()) {
26042633
return;

0 commit comments

Comments
 (0)