Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
------------

Expand Down
11 changes: 8 additions & 3 deletions clang/include/clang/AST/PrettyPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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
Expand Down
7 changes: 5 additions & 2 deletions clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions clang/lib/ASTMatchers/ASTMatchersInternal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
29 changes: 29 additions & 0 deletions clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down