Skip to content

[Clang][AST][NFC] Introduce NamespaceBaseDecl #149123

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 18, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ static void replaceMoveWithForward(const UnresolvedLookupExpr *Callee,
// We still conservatively put a "std::" in front of the forward because
// we don't know whether the code also had a "using std::forward;".
Diag << FixItHint::CreateReplacement(CallRange, "std::" + ForwardName);
} else if (const NamespaceDecl *Namespace = NNS->getAsNamespace()) {
} else if (const NamespaceBaseDecl *Namespace = NNS->getAsNamespace()) {
if (Namespace->getName() == "std") {
if (!NNS->getPrefix()) {
// Called as "std::move".
Expand Down
3 changes: 2 additions & 1 deletion clang-tools-extra/clang-tidy/misc/UnusedAliasDeclsCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ void UnusedAliasDeclsCheck::check(const MatchFinder::MatchResult &Result) {

if (const auto *NestedName =
Result.Nodes.getNodeAs<NestedNameSpecifier>("nns")) {
if (const auto *AliasDecl = NestedName->getAsNamespaceAlias()) {
if (const auto *AliasDecl = dyn_cast_if_present<NamespaceAliasDecl>(
NestedName->getAsNamespace())) {
FoundDecls[AliasDecl] = CharSourceRange();
}
}
Expand Down
3 changes: 2 additions & 1 deletion clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,8 @@ class RenamerClangTidyVisitor

bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc Loc) {
if (const NestedNameSpecifier *Spec = Loc.getNestedNameSpecifier()) {
if (const NamespaceDecl *Decl = Spec->getAsNamespace())
if (const auto *Decl =
dyn_cast_if_present<NamespaceDecl>(Spec->getAsNamespace()))
Check->addUsage(Decl, Loc.getLocalSourceRange(), SM);
}

Expand Down
10 changes: 6 additions & 4 deletions clang-tools-extra/clangd/AST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -666,12 +666,14 @@ std::string getQualification(ASTContext &Context,
return getQualification(
Context, DestContext, ND->getDeclContext(),
[&](NestedNameSpecifier *NNS) {
if (NNS->getKind() != NestedNameSpecifier::Namespace)
const NamespaceDecl *NS =
dyn_cast_if_present<NamespaceDecl>(NNS->getAsNamespace());
if (!NS)
return false;
const auto *CanonNSD = NNS->getAsNamespace()->getCanonicalDecl();
NS = NS->getCanonicalDecl();
return llvm::any_of(VisibleNamespaceDecls,
[CanonNSD](const NamespaceDecl *NSD) {
return NSD->getCanonicalDecl() == CanonNSD;
[NS](const NamespaceDecl *NSD) {
return NSD->getCanonicalDecl() == NS;
});
});
}
Expand Down
1 change: 0 additions & 1 deletion clang-tools-extra/clangd/CodeComplete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1470,7 +1470,6 @@ bool allowIndex(CodeCompletionContext &CC) {
switch (NameSpec->getKind()) {
case NestedNameSpecifier::Global:
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::NamespaceAlias:
return true;
case NestedNameSpecifier::Super:
case NestedNameSpecifier::TypeSpec:
Expand Down
3 changes: 0 additions & 3 deletions clang-tools-extra/clangd/DumpAST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,6 @@ class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> {
NNS_KIND(TypeSpec);
NNS_KIND(Global);
NNS_KIND(Super);
NNS_KIND(NamespaceAlias);
#undef NNS_KIND
}
llvm_unreachable("Unhandled SpecifierKind enum");
Expand Down Expand Up @@ -281,8 +280,6 @@ class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> {
return NNS.getAsIdentifier()->getName().str() + "::";
case NestedNameSpecifier::Namespace:
return NNS.getAsNamespace()->getNameAsString() + "::";
case NestedNameSpecifier::NamespaceAlias:
return NNS.getAsNamespaceAlias()->getNameAsString() + "::";
default:
return "";
}
Expand Down
3 changes: 0 additions & 3 deletions clang-tools-extra/clangd/FindTarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -491,9 +491,6 @@ struct TargetFinder {
case NestedNameSpecifier::Namespace:
add(NNS->getAsNamespace(), Flags);
return;
case NestedNameSpecifier::NamespaceAlias:
add(NNS->getAsNamespaceAlias(), Flags);
return;
case NestedNameSpecifier::Identifier:
if (Resolver) {
add(Resolver->resolveNestedNameSpecifierToType(NNS), Flags);
Expand Down
36 changes: 19 additions & 17 deletions clang-tools-extra/clangd/IncludeFixer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -403,25 +403,27 @@ std::optional<CheapUnresolvedName> extractUnresolvedNameCheaply(
if (auto *Nested = SS->getScopeRep()) {
if (Nested->getKind() == NestedNameSpecifier::Global) {
Result.ResolvedScope = "";
} else if (const auto *NS = Nested->getAsNamespace()) {
std::string SpecifiedNS = printNamespaceScope(*NS);
std::optional<std::string> Spelling = getSpelledSpecifier(*SS, SM);

// Check the specifier spelled in the source.
// If the resolved scope doesn't end with the spelled scope, the
// resolved scope may come from a sema typo correction. For example,
// sema assumes that "clangd::" is a typo of "clang::" and uses
// "clang::" as the specified scope in:
// namespace clang { clangd::X; }
// In this case, we use the "typo" specifier as extra scope instead
// of using the scope assumed by sema.
if (!Spelling || llvm::StringRef(SpecifiedNS).ends_with(*Spelling)) {
Result.ResolvedScope = std::move(SpecifiedNS);
} else if (const NamespaceBaseDecl *NSB = Nested->getAsNamespace()) {
if (const auto *NS = dyn_cast<NamespaceDecl>(NSB)) {
std::string SpecifiedNS = printNamespaceScope(*NS);
std::optional<std::string> Spelling = getSpelledSpecifier(*SS, SM);

// Check the specifier spelled in the source.
// If the resolved scope doesn't end with the spelled scope, the
// resolved scope may come from a sema typo correction. For example,
// sema assumes that "clangd::" is a typo of "clang::" and uses
// "clang::" as the specified scope in:
// namespace clang { clangd::X; }
// In this case, we use the "typo" specifier as extra scope instead
// of using the scope assumed by sema.
if (!Spelling || llvm::StringRef(SpecifiedNS).ends_with(*Spelling)) {
Result.ResolvedScope = std::move(SpecifiedNS);
} else {
Result.UnresolvedScope = std::move(*Spelling);
}
} else {
Result.UnresolvedScope = std::move(*Spelling);
Result.ResolvedScope = printNamespaceScope(*cast<NamespaceAliasDecl>(NSB)->getNamespace());
}
} else if (const auto *ANS = Nested->getAsNamespaceAlias()) {
Result.ResolvedScope = printNamespaceScope(*ANS->getNamespace());
} else {
// We don't fix symbols in scopes that are not top-level e.g. class
// members, as we don't collect includes for them.
Expand Down
8 changes: 6 additions & 2 deletions clang-tools-extra/clangd/refactor/tweaks/AddUsing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@ findInsertionPoint(const Tweak::Selection &Inputs,
if (SM.isBeforeInTranslationUnit(Inputs.Cursor, U->getUsingLoc()))
// "Usings" is sorted, so we're done.
break;
if (const auto *Namespace = U->getQualifier()->getAsNamespace()) {
if (const auto *Namespace = dyn_cast_if_present<NamespaceDecl>(
U->getQualifier()->getAsNamespace())) {
if (Namespace->getCanonicalDecl() ==
QualifierToRemove.getNestedNameSpecifier()
->getAsNamespace()
Expand Down Expand Up @@ -232,7 +233,10 @@ findInsertionPoint(const Tweak::Selection &Inputs,

bool isNamespaceForbidden(const Tweak::Selection &Inputs,
const NestedNameSpecifier &Namespace) {
std::string NamespaceStr = printNamespaceScope(*Namespace.getAsNamespace());
const auto *NS = dyn_cast<NamespaceDecl>(Namespace.getAsNamespace());
if (!NS)
return true;
std::string NamespaceStr = printNamespaceScope(*NS);

for (StringRef Banned : Config::current().Style.FullyQualifiedNamespaces) {
StringRef PrefixMatch = NamespaceStr;
Expand Down
1 change: 0 additions & 1 deletion clang-tools-extra/include-cleaner/lib/WalkAST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@ class ASTWalker : public RecursiveASTVisitor<ASTWalker> {
return true;
switch (Qual->getKind()) {
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::NamespaceAlias:
case NestedNameSpecifier::Global:
return true;
case NestedNameSpecifier::TypeSpec:
Expand Down
7 changes: 1 addition & 6 deletions clang/include/clang/AST/AbstractBasicReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,12 +269,7 @@ class DataStreamBasicReader : public BasicReaderBase<Impl> {

case NestedNameSpecifier::Namespace:
cur = NestedNameSpecifier::Create(ctx, cur,
asImpl().readNamespaceDeclRef());
continue;

case NestedNameSpecifier::NamespaceAlias:
cur = NestedNameSpecifier::Create(ctx, cur,
asImpl().readNamespaceAliasDeclRef());
asImpl().readNamespaceBaseDeclRef());
continue;

case NestedNameSpecifier::TypeSpec:
Expand Down
6 changes: 1 addition & 5 deletions clang/include/clang/AST/AbstractBasicWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,11 +251,7 @@ class DataStreamBasicWriter : public BasicWriterBase<Impl> {
continue;

case NestedNameSpecifier::Namespace:
asImpl().writeNamespaceDeclRef(NNS->getAsNamespace());
continue;

case NestedNameSpecifier::NamespaceAlias:
asImpl().writeNamespaceAliasDeclRef(NNS->getAsNamespaceAlias());
asImpl().writeNamespaceBaseDeclRef(NNS->getAsNamespace());
continue;

case NestedNameSpecifier::TypeSpec:
Expand Down
22 changes: 21 additions & 1 deletion clang/include/clang/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -565,8 +565,28 @@ class LabelDecl : public NamedDecl {
static bool classofKind(Kind K) { return K == Label; }
};

/// Represents C++ namespaces and their aliases.
///
/// FIXME: Move `NamespaceBaseDecl` and `NamespaceDecl` to "DeclCXX.h" or
/// explain why not moving.
class NamespaceBaseDecl : public NamedDecl {
protected:
using NamedDecl::NamedDecl;

public:
NamespaceDecl *getNamespace();
const NamespaceDecl *getNamespace() const {
return const_cast<NamespaceBaseDecl *>(this)->getNamespace();
}

static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) {
return K >= firstNamespaceBase && K <= lastNamespaceBase;
}
};

/// Represent a C++ namespace.
class NamespaceDecl : public NamedDecl,
class NamespaceDecl : public NamespaceBaseDecl,
public DeclContext,
public Redeclarable<NamespaceDecl> {
/// The starting location of the source range, pointing
Expand Down
24 changes: 11 additions & 13 deletions clang/include/clang/AST/DeclCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -3186,7 +3186,7 @@ class UsingDirectiveDecl : public NamedDecl {
/// \code
/// namespace Foo = Bar;
/// \endcode
class NamespaceAliasDecl : public NamedDecl,
class NamespaceAliasDecl : public NamespaceBaseDecl,
public Redeclarable<NamespaceAliasDecl> {
friend class ASTDeclReader;

Expand All @@ -3203,14 +3203,14 @@ class NamespaceAliasDecl : public NamedDecl,

/// The Decl that this alias points to, either a NamespaceDecl or
/// a NamespaceAliasDecl.
NamedDecl *Namespace;
NamespaceBaseDecl *Namespace;

NamespaceAliasDecl(ASTContext &C, DeclContext *DC,
SourceLocation NamespaceLoc, SourceLocation AliasLoc,
IdentifierInfo *Alias, NestedNameSpecifierLoc QualifierLoc,
SourceLocation IdentLoc, NamedDecl *Namespace)
: NamedDecl(NamespaceAlias, DC, AliasLoc, Alias), redeclarable_base(C),
NamespaceLoc(NamespaceLoc), IdentLoc(IdentLoc),
SourceLocation IdentLoc, NamespaceBaseDecl *Namespace)
: NamespaceBaseDecl(NamespaceAlias, DC, AliasLoc, Alias),
redeclarable_base(C), NamespaceLoc(NamespaceLoc), IdentLoc(IdentLoc),
QualifierLoc(QualifierLoc), Namespace(Namespace) {}

void anchor() override;
Expand All @@ -3222,13 +3222,11 @@ class NamespaceAliasDecl : public NamedDecl,
NamespaceAliasDecl *getMostRecentDeclImpl() override;

public:
static NamespaceAliasDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation NamespaceLoc,
SourceLocation AliasLoc,
IdentifierInfo *Alias,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation IdentLoc,
NamedDecl *Namespace);
static NamespaceAliasDecl *
Create(ASTContext &C, DeclContext *DC, SourceLocation NamespaceLoc,
SourceLocation AliasLoc, IdentifierInfo *Alias,
NestedNameSpecifierLoc QualifierLoc, SourceLocation IdentLoc,
NamespaceBaseDecl *Namespace);

static NamespaceAliasDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);

Expand Down Expand Up @@ -3282,7 +3280,7 @@ class NamespaceAliasDecl : public NamedDecl,

/// Retrieve the namespace that this alias refers to, which
/// may either be a NamespaceDecl or a NamespaceAliasDecl.
NamedDecl *getAliasedNamespace() const { return Namespace; }
NamespaceBaseDecl *getAliasedNamespace() const { return Namespace; }

SourceRange getSourceRange() const override LLVM_READONLY {
return SourceRange(NamespaceLoc, IdentLoc);
Expand Down
47 changes: 10 additions & 37 deletions clang/include/clang/AST/NestedNameSpecifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ class ASTContext;
class CXXRecordDecl;
class IdentifierInfo;
class LangOptions;
class NamespaceAliasDecl;
class NamespaceDecl;
class NamespaceBaseDecl;
struct PrintingPolicy;
class Type;
class TypeLoc;
Expand Down Expand Up @@ -79,12 +78,9 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
/// An identifier, stored as an IdentifierInfo*.
Identifier,

/// A namespace, stored as a NamespaceDecl*.
/// A namespace-like entity, stored as a NamespaceBaseDecl*.
Namespace,

/// A namespace alias, stored as a NamespaceAliasDecl*.
NamespaceAlias,

/// A type, stored as a Type*.
TypeSpec,

Expand Down Expand Up @@ -121,15 +117,10 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
NestedNameSpecifier *Prefix,
const IdentifierInfo *II);

/// Builds a nested name specifier that names a namespace.
static NestedNameSpecifier *Create(const ASTContext &Context,
NestedNameSpecifier *Prefix,
const NamespaceDecl *NS);

/// Builds a nested name specifier that names a namespace alias.
/// Builds a nested name specifier that names a namespace or namespace alias.
static NestedNameSpecifier *Create(const ASTContext &Context,
NestedNameSpecifier *Prefix,
const NamespaceAliasDecl *Alias);
const NamespaceBaseDecl *NS);

/// Builds a nested name specifier that names a type.
static NestedNameSpecifier *
Expand Down Expand Up @@ -174,13 +165,9 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
return nullptr;
}

/// Retrieve the namespace stored in this nested name
/// Retrieve the namespace or namespace alias stored in this nested name
/// specifier.
NamespaceDecl *getAsNamespace() const;

/// Retrieve the namespace alias stored in this nested name
/// specifier.
NamespaceAliasDecl *getAsNamespaceAlias() const;
NamespaceBaseDecl *getAsNamespace() const;

/// Retrieve the record declaration stored in this nested name
/// specifier.
Expand Down Expand Up @@ -425,29 +412,15 @@ class NestedNameSpecifierLocBuilder {
/// \param Context The AST context in which this nested-name-specifier
/// resides.
///
/// \param Namespace The namespace.
/// \param Namespace The namespace or namespace alias.
///
/// \param NamespaceLoc The location of the namespace name.
/// \param NamespaceLoc The location of the namespace name or the namespace
// alias.
///
/// \param ColonColonLoc The location of the trailing '::'.
void Extend(ASTContext &Context, NamespaceDecl *Namespace,
void Extend(ASTContext &Context, NamespaceBaseDecl *Namespace,
SourceLocation NamespaceLoc, SourceLocation ColonColonLoc);

/// Extend the current nested-name-specifier by another
/// nested-name-specifier component of the form 'namespace-alias::'.
///
/// \param Context The AST context in which this nested-name-specifier
/// resides.
///
/// \param Alias The namespace alias.
///
/// \param AliasLoc The location of the namespace alias
/// name.
///
/// \param ColonColonLoc The location of the trailing '::'.
void Extend(ASTContext &Context, NamespaceAliasDecl *Alias,
SourceLocation AliasLoc, SourceLocation ColonColonLoc);

/// Turn this (empty) nested-name-specifier into the global
/// nested-name-specifier '::'.
void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc);
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/AST/PropertiesBase.td
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ def DeclRef : RefPropertyType<"Decl"> { let ConstWhenWriting = 1; }
SubclassPropertyType<"FunctionDecl", DeclRef>;
def NamedDeclRef :
SubclassPropertyType<"NamedDecl", DeclRef>;
def NamespaceBaseDeclRef : SubclassPropertyType<"NamespaceBaseDecl", DeclRef>;
def NamespaceDeclRef :
SubclassPropertyType<"NamespaceDecl", DeclRef>;
def NamespaceAliasDeclRef :
Expand Down
2 changes: 0 additions & 2 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -789,7 +789,6 @@ bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifier(
switch (NNS->getKind()) {
case NestedNameSpecifier::Identifier:
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::NamespaceAlias:
case NestedNameSpecifier::Global:
case NestedNameSpecifier::Super:
return true;
Expand All @@ -813,7 +812,6 @@ bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifierLoc(
switch (NNS.getNestedNameSpecifier()->getKind()) {
case NestedNameSpecifier::Identifier:
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::NamespaceAlias:
case NestedNameSpecifier::Global:
case NestedNameSpecifier::Super:
return true;
Expand Down
6 changes: 3 additions & 3 deletions clang/include/clang/ASTMatchers/ASTMatchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -7894,9 +7894,9 @@ AST_MATCHER_P_OVERLOAD(NestedNameSpecifierLoc, hasPrefix,
/// matches "ns::"
AST_MATCHER_P(NestedNameSpecifier, specifiesNamespace,
internal::Matcher<NamespaceDecl>, InnerMatcher) {
if (!Node.getAsNamespace())
return false;
return InnerMatcher.matches(*Node.getAsNamespace(), Finder, Builder);
if (auto *NS = dyn_cast_if_present<NamespaceDecl>(Node.getAsNamespace()))
return InnerMatcher.matches(*NS, Finder, Builder);
return false;
}

/// Matches attributes.
Expand Down
Loading
Loading