Skip to content

Commit

Permalink
[clang] Add [is|set]Nested methods to NamespaceDecl
Browse files Browse the repository at this point in the history
Adds support for NamespaceDecl to inform if its part of a nested namespace.
This flag only corresponds to the inner namespaces in a nested namespace declaration.
In this example:
namespace <X>::<Y>::<Z> {}
Only <Y> and <Z> will be classified as nested.

This flag isn't meant for assisting in building the AST, more for static analysis and refactorings.

Reviewed By: aaron.ballman

Differential Revision: https://reviews.llvm.org/D90568
  • Loading branch information
njames93 committed Nov 24, 2022
1 parent 3467f9c commit 15e76ee
Show file tree
Hide file tree
Showing 16 changed files with 111 additions and 54 deletions.
45 changes: 35 additions & 10 deletions clang/include/clang/AST/Decl.h
Expand Up @@ -542,6 +542,9 @@ class LabelDecl : public NamedDecl {
class NamespaceDecl : public NamedDecl, public DeclContext,
public Redeclarable<NamespaceDecl>
{

enum Flags : unsigned { F_Inline = 1 << 0, F_Nested = 1 << 1 };

/// The starting location of the source range, pointing
/// to either the namespace or the inline keyword.
SourceLocation LocStart;
Expand All @@ -553,11 +556,12 @@ class NamespaceDecl : public NamedDecl, public DeclContext,
/// this namespace or to the first namespace in the chain (the latter case
/// only when this is not the first in the chain), along with a
/// boolean value indicating whether this is an inline namespace.
llvm::PointerIntPair<NamespaceDecl *, 1, bool> AnonOrFirstNamespaceAndInline;
llvm::PointerIntPair<NamespaceDecl *, 2, unsigned>
AnonOrFirstNamespaceAndFlags;

NamespaceDecl(ASTContext &C, DeclContext *DC, bool Inline,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, NamespaceDecl *PrevDecl);
IdentifierInfo *Id, NamespaceDecl *PrevDecl, bool Nested);

using redeclarable_base = Redeclarable<NamespaceDecl>;

Expand All @@ -569,10 +573,10 @@ class NamespaceDecl : public NamedDecl, public DeclContext,
friend class ASTDeclReader;
friend class ASTDeclWriter;

static NamespaceDecl *Create(ASTContext &C, DeclContext *DC,
bool Inline, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
NamespaceDecl *PrevDecl);
static NamespaceDecl *Create(ASTContext &C, DeclContext *DC, bool Inline,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, NamespaceDecl *PrevDecl,
bool Nested);

static NamespaceDecl *CreateDeserialized(ASTContext &C, unsigned ID);

Expand Down Expand Up @@ -601,12 +605,33 @@ class NamespaceDecl : public NamedDecl, public DeclContext,

/// Returns true if this is an inline namespace declaration.
bool isInline() const {
return AnonOrFirstNamespaceAndInline.getInt();
return AnonOrFirstNamespaceAndFlags.getInt() & F_Inline;
}

/// Set whether this is an inline namespace declaration.
void setInline(bool Inline) {
AnonOrFirstNamespaceAndInline.setInt(Inline);
unsigned F = AnonOrFirstNamespaceAndFlags.getInt();
if (Inline)
AnonOrFirstNamespaceAndFlags.setInt(F | F_Inline);
else
AnonOrFirstNamespaceAndFlags.setInt(F & ~F_Inline);
}

/// Returns true if this is a nested namespace declaration.
/// \code
/// namespace outer::nested { }
/// \endcode
bool isNested() const {
return AnonOrFirstNamespaceAndFlags.getInt() & F_Nested;
}

/// Set whether this is a nested namespace declaration.
void setNested(bool Nested) {
unsigned F = AnonOrFirstNamespaceAndFlags.getInt();
if (Nested)
AnonOrFirstNamespaceAndFlags.setInt(F | F_Nested);
else
AnonOrFirstNamespaceAndFlags.setInt(F & ~F_Nested);
}

/// Returns true if the inline qualifier for \c Name is redundant.
Expand Down Expand Up @@ -635,11 +660,11 @@ class NamespaceDecl : public NamedDecl, public DeclContext,
/// Retrieve the anonymous namespace nested inside this namespace,
/// if any.
NamespaceDecl *getAnonymousNamespace() const {
return getOriginalNamespace()->AnonOrFirstNamespaceAndInline.getPointer();
return getOriginalNamespace()->AnonOrFirstNamespaceAndFlags.getPointer();
}

void setAnonymousNamespace(NamespaceDecl *D) {
getOriginalNamespace()->AnonOrFirstNamespaceAndInline.setPointer(D);
getOriginalNamespace()->AnonOrFirstNamespaceAndFlags.setPointer(D);
}

/// Retrieves the canonical declaration of this namespace.
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Sema/Sema.h
Expand Up @@ -6041,7 +6041,7 @@ class Sema final {
SourceLocation IdentLoc, IdentifierInfo *Ident,
SourceLocation LBrace,
const ParsedAttributesView &AttrList,
UsingDirectiveDecl *&UsingDecl);
UsingDirectiveDecl *&UsingDecl, bool IsNested);
void ActOnFinishNamespaceDef(Decl *Dcl, SourceLocation RBrace);

NamespaceDecl *getStdNamespace() const;
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/AST/ASTContext.cpp
Expand Up @@ -8765,9 +8765,9 @@ CreateAArch64ABIBuiltinVaListDecl(const ASTContext *Context) {
// namespace std { struct __va_list {
auto *NS = NamespaceDecl::Create(
const_cast<ASTContext &>(*Context), Context->getTranslationUnitDecl(),
/*Inline*/ false, SourceLocation(), SourceLocation(),
/*Inline=*/false, SourceLocation(), SourceLocation(),
&Context->Idents.get("std"),
/*PrevDecl*/ nullptr);
/*PrevDecl=*/nullptr, /*Nested=*/false);
NS->setImplicit();
VaListTagDecl->setDeclContext(NS);
}
Expand Down Expand Up @@ -8954,9 +8954,9 @@ CreateAAPCSABIBuiltinVaListDecl(const ASTContext *Context) {
NamespaceDecl *NS;
NS = NamespaceDecl::Create(const_cast<ASTContext &>(*Context),
Context->getTranslationUnitDecl(),
/*Inline*/false, SourceLocation(),
/*Inline=*/false, SourceLocation(),
SourceLocation(), &Context->Idents.get("std"),
/*PrevDecl*/ nullptr);
/*PrevDecl=*/nullptr, /*Nested=*/false);
NS->setImplicit();
VaListDecl->setDeclContext(NS);
}
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/AST/ASTImporter.cpp
Expand Up @@ -2412,10 +2412,10 @@ ExpectedDecl ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
// Create the "to" namespace, if needed.
NamespaceDecl *ToNamespace = MergeWithNamespace;
if (!ToNamespace) {
if (GetImportedOrCreateDecl(
ToNamespace, D, Importer.getToContext(), DC, D->isInline(),
*BeginLocOrErr, Loc, Name.getAsIdentifierInfo(),
/*PrevDecl=*/nullptr))
if (GetImportedOrCreateDecl(ToNamespace, D, Importer.getToContext(), DC,
D->isInline(), *BeginLocOrErr, Loc,
Name.getAsIdentifierInfo(),
/*PrevDecl=*/nullptr, D->isNested()))
return ToNamespace;
ToNamespace->setRBraceLoc(*RBraceLocOrErr);
ToNamespace->setLexicalDeclContext(LexicalDC);
Expand Down
26 changes: 16 additions & 10 deletions clang/lib/AST/DeclCXX.cpp
Expand Up @@ -2880,41 +2880,47 @@ NamespaceDecl *UsingDirectiveDecl::getNominatedNamespace() {

NamespaceDecl::NamespaceDecl(ASTContext &C, DeclContext *DC, bool Inline,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, NamespaceDecl *PrevDecl)
IdentifierInfo *Id, NamespaceDecl *PrevDecl,
bool Nested)
: NamedDecl(Namespace, DC, IdLoc, Id), DeclContext(Namespace),
redeclarable_base(C), LocStart(StartLoc),
AnonOrFirstNamespaceAndInline(nullptr, Inline) {
redeclarable_base(C), LocStart(StartLoc) {
unsigned Flags = 0;
if (Inline)
Flags |= F_Inline;
if (Nested)
Flags |= F_Nested;
AnonOrFirstNamespaceAndFlags = {nullptr, Flags};
setPreviousDecl(PrevDecl);

if (PrevDecl)
AnonOrFirstNamespaceAndInline.setPointer(PrevDecl->getOriginalNamespace());
AnonOrFirstNamespaceAndFlags.setPointer(PrevDecl->getOriginalNamespace());
}

NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC,
bool Inline, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
NamespaceDecl *PrevDecl) {
return new (C, DC) NamespaceDecl(C, DC, Inline, StartLoc, IdLoc, Id,
PrevDecl);
NamespaceDecl *PrevDecl, bool Nested) {
return new (C, DC)
NamespaceDecl(C, DC, Inline, StartLoc, IdLoc, Id, PrevDecl, Nested);
}

NamespaceDecl *NamespaceDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) NamespaceDecl(C, nullptr, false, SourceLocation(),
SourceLocation(), nullptr, nullptr);
SourceLocation(), nullptr, nullptr, false);
}

NamespaceDecl *NamespaceDecl::getOriginalNamespace() {
if (isFirstDecl())
return this;

return AnonOrFirstNamespaceAndInline.getPointer();
return AnonOrFirstNamespaceAndFlags.getPointer();
}

const NamespaceDecl *NamespaceDecl::getOriginalNamespace() const {
if (isFirstDecl())
return this;

return AnonOrFirstNamespaceAndInline.getPointer();
return AnonOrFirstNamespaceAndFlags.getPointer();
}

bool NamespaceDecl::isOriginalNamespace() const { return isFirstDecl(); }
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/AST/ItaniumMangle.cpp
Expand Up @@ -602,9 +602,9 @@ NamespaceDecl *ItaniumMangleContextImpl::getStdNamespace() {
if (!StdNamespace) {
StdNamespace = NamespaceDecl::Create(
getASTContext(), getASTContext().getTranslationUnitDecl(),
/*Inline*/ false, SourceLocation(), SourceLocation(),
/*Inline=*/false, SourceLocation(), SourceLocation(),
&getASTContext().Idents.get("std"),
/*PrevDecl*/ nullptr);
/*PrevDecl=*/nullptr, /*Nested=*/false);
StdNamespace->setImplicit();
}
return StdNamespace;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/JSONNodeDumper.cpp
Expand Up @@ -794,6 +794,7 @@ void JSONNodeDumper::VisitTypeAliasDecl(const TypeAliasDecl *TAD) {
void JSONNodeDumper::VisitNamespaceDecl(const NamespaceDecl *ND) {
VisitNamedDecl(ND);
attributeOnlyIfTrue("isInline", ND->isInline());
attributeOnlyIfTrue("isNested", ND->isNested());
if (!ND->isOriginalNamespace())
JOS.attribute("originalNamespace",
createBareDeclRef(ND->getOriginalNamespace()));
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/TextNodeDumper.cpp
Expand Up @@ -1931,6 +1931,8 @@ void TextNodeDumper::VisitNamespaceDecl(const NamespaceDecl *D) {
dumpName(D);
if (D->isInline())
OS << " inline";
if (D->isNested())
OS << " nested";
if (!D->isOriginalNamespace())
dumpDeclRef(D->getOriginalNamespace(), "original");
}
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Parse/ParseDeclCXX.cpp
Expand Up @@ -227,7 +227,7 @@ Parser::DeclGroupPtrTy Parser::ParseNamespace(DeclaratorContext Context,
UsingDirectiveDecl *ImplicitUsingDirectiveDecl = nullptr;
Decl *NamespcDecl = Actions.ActOnStartNamespaceDef(
getCurScope(), InlineLoc, NamespaceLoc, IdentLoc, Ident,
T.getOpenLocation(), attrs, ImplicitUsingDirectiveDecl);
T.getOpenLocation(), attrs, ImplicitUsingDirectiveDecl, false);

PrettyDeclStackTraceEntry CrashInfo(Actions.Context, NamespcDecl,
NamespaceLoc, "parsing namespace");
Expand Down Expand Up @@ -275,7 +275,7 @@ void Parser::ParseInnerNamespace(const InnerNamespaceInfoList &InnerNSs,
Decl *NamespcDecl = Actions.ActOnStartNamespaceDef(
getCurScope(), InnerNSs[index].InlineLoc, InnerNSs[index].NamespaceLoc,
InnerNSs[index].IdentLoc, InnerNSs[index].Ident,
Tracker.getOpenLocation(), attrs, ImplicitUsingDirectiveDecl);
Tracker.getOpenLocation(), attrs, ImplicitUsingDirectiveDecl, true);
assert(!ImplicitUsingDirectiveDecl &&
"nested namespace definition cannot define anonymous namespace");

Expand Down
6 changes: 3 additions & 3 deletions clang/lib/Sema/HLSLExternalSemaSource.cpp
Expand Up @@ -385,9 +385,9 @@ void HLSLExternalSemaSource::InitializeSema(Sema &S) {
NamespaceDecl *PrevDecl = nullptr;
if (S.LookupQualifiedName(Result, AST.getTranslationUnitDecl()))
PrevDecl = Result.getAsSingle<NamespaceDecl>();
HLSLNamespace = NamespaceDecl::Create(AST, AST.getTranslationUnitDecl(),
false, SourceLocation(),
SourceLocation(), &HLSL, PrevDecl);
HLSLNamespace = NamespaceDecl::Create(
AST, AST.getTranslationUnitDecl(), /*Inline=*/false, SourceLocation(),
SourceLocation(), &HLSL, PrevDecl, /*Nested=*/false);
HLSLNamespace->setImplicit(true);
HLSLNamespace->setHasExternalLexicalStorage();
AST.getTranslationUnitDecl()->addDecl(HLSLNamespace);
Expand Down
26 changes: 14 additions & 12 deletions clang/lib/Sema/SemaDeclCXX.cpp
Expand Up @@ -11171,10 +11171,13 @@ static void DiagnoseNamespaceInlineMismatch(Sema &S, SourceLocation KeywordLoc,

/// ActOnStartNamespaceDef - This is called at the start of a namespace
/// definition.
Decl *Sema::ActOnStartNamespaceDef(
Scope *NamespcScope, SourceLocation InlineLoc, SourceLocation NamespaceLoc,
SourceLocation IdentLoc, IdentifierInfo *II, SourceLocation LBrace,
const ParsedAttributesView &AttrList, UsingDirectiveDecl *&UD) {
Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
SourceLocation InlineLoc,
SourceLocation NamespaceLoc,
SourceLocation IdentLoc, IdentifierInfo *II,
SourceLocation LBrace,
const ParsedAttributesView &AttrList,
UsingDirectiveDecl *&UD, bool IsNested) {
SourceLocation StartLoc = InlineLoc.isValid() ? InlineLoc : NamespaceLoc;
// For anonymous namespace, take the location of the left brace.
SourceLocation Loc = II ? IdentLoc : LBrace;
Expand Down Expand Up @@ -11244,8 +11247,8 @@ Decl *Sema::ActOnStartNamespaceDef(
&IsInline, PrevNS);
}

NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext, IsInline,
StartLoc, Loc, II, PrevNS);
NamespaceDecl *Namespc = NamespaceDecl::Create(
Context, CurContext, IsInline, StartLoc, Loc, II, PrevNS, IsNested);
if (IsInvalid)
Namespc->setInvalidDecl();

Expand Down Expand Up @@ -11506,12 +11509,11 @@ QualType Sema::CheckComparisonCategoryType(ComparisonCategoryType Kind,
NamespaceDecl *Sema::getOrCreateStdNamespace() {
if (!StdNamespace) {
// The "std" namespace has not yet been defined, so build one implicitly.
StdNamespace = NamespaceDecl::Create(Context,
Context.getTranslationUnitDecl(),
/*Inline=*/false,
SourceLocation(), SourceLocation(),
&PP.getIdentifierTable().get("std"),
/*PrevDecl=*/nullptr);
StdNamespace = NamespaceDecl::Create(
Context, Context.getTranslationUnitDecl(),
/*Inline=*/false, SourceLocation(), SourceLocation(),
&PP.getIdentifierTable().get("std"),
/*PrevDecl=*/nullptr, /*Nested=*/false);
getStdNamespace()->setImplicit(true);
}

Expand Down
7 changes: 4 additions & 3 deletions clang/lib/Serialization/ASTReaderDecl.cpp
Expand Up @@ -1745,6 +1745,7 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
RedeclarableResult Redecl = VisitRedeclarable(D);
VisitNamedDecl(D);
D->setInline(Record.readInt());
D->setNested(Record.readInt());
D->LocStart = readSourceLocation();
D->RBraceLoc = readSourceLocation();

Expand All @@ -1758,7 +1759,7 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
} else {
// Link this namespace back to the first declaration, which has already
// been deserialized.
D->AnonOrFirstNamespaceAndInline.setPointer(D->getFirstDecl());
D->AnonOrFirstNamespaceAndFlags.setPointer(D->getFirstDecl());
}

mergeRedeclarable(D, Redecl);
Expand Down Expand Up @@ -2784,8 +2785,8 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *DBase, T *Existing,
// We cannot have loaded any redeclarations of this declaration yet, so
// there's nothing else that needs to be updated.
if (auto *Namespace = dyn_cast<NamespaceDecl>(D))
Namespace->AnonOrFirstNamespaceAndInline.setPointer(
assert_cast<NamespaceDecl*>(ExistingCanon));
Namespace->AnonOrFirstNamespaceAndFlags.setPointer(
assert_cast<NamespaceDecl *>(ExistingCanon));

// When we merge a template, merge its pattern.
if (auto *DTemplate = dyn_cast<RedeclarableTemplateDecl>(D))
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Serialization/ASTWriterDecl.cpp
Expand Up @@ -1252,6 +1252,7 @@ void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) {
VisitRedeclarable(D);
VisitNamedDecl(D);
Record.push_back(D->isInline());
Record.push_back(D->isNested());
Record.AddSourceLocation(D->getBeginLoc());
Record.AddSourceLocation(D->getRBraceLoc());

Expand Down
17 changes: 17 additions & 0 deletions clang/test/AST/ast-dump-decl.cpp
Expand Up @@ -53,6 +53,23 @@ inline namespace TestNamespaceDeclInline {
}
// CHECK: NamespaceDecl{{.*}} TestNamespaceDeclInline inline

namespace TestNestedNameSpace::Nested {
}
// CHECK: NamespaceDecl{{.*}} TestNestedNameSpace
// CHECK: NamespaceDecl{{.*}} Nested nested{{\s*$}}

namespace TestMultipleNested::SecondLevelNested::Nested {
}
// CHECK: NamespaceDecl{{.*}} TestMultipleNested
// CHECK: NamespaceDecl{{.*}} SecondLevelNested nested
// CHECK: NamespaceDecl{{.*}} Nested nested{{\s*$}}

namespace TestInlineNested::inline SecondLevel::inline Nested {
}
// CHECK: NamespaceDecl{{.*}} TestInlineNested
// CHECK: NamespaceDecl{{.*}} SecondLevel inline nested
// CHECK: NamespaceDecl{{.*}} Nested inline nested{{\s*$}}

namespace testUsingDirectiveDecl {
namespace A {
}
Expand Down
6 changes: 4 additions & 2 deletions clang/test/AST/ast-dump-namespace-json.cpp
Expand Up @@ -170,6 +170,7 @@ namespace quux::inline frobble {
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "name": "quux"
// CHECK-NEXT: "isNested": true
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }
Expand All @@ -195,7 +196,7 @@ namespace quux::inline frobble {
// CHECK-NEXT: "tokLen": 1
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "name": "quux",
// CHECK-NEXT: "name": "quux"
// CHECK-NEXT: "inner": [
// CHECK-NEXT: {
// CHECK-NEXT: "id": "0x{{.*}}",
Expand All @@ -220,7 +221,8 @@ namespace quux::inline frobble {
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "name": "frobble",
// CHECK-NEXT: "isInline": true
// CHECK-NEXT: "isInline": true,
// CHECK-NEXT: "isNested": true
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }
2 changes: 1 addition & 1 deletion clang/unittests/Sema/ExternalSemaSourceTest.cpp
Expand Up @@ -121,7 +121,7 @@ class NamespaceTypoProvider : public clang::ExternalSemaSource {
CurrentSema->getPreprocessor().getIdentifierInfo(CorrectTo);
NamespaceDecl *NewNamespace =
NamespaceDecl::Create(Context, DestContext, false, Typo.getBeginLoc(),
Typo.getLoc(), ToIdent, nullptr);
Typo.getLoc(), ToIdent, nullptr, false);
DestContext->addDecl(NewNamespace);
TypoCorrection Correction(ToIdent);
Correction.addCorrectionDecl(NewNamespace);
Expand Down

0 comments on commit 15e76ee

Please sign in to comment.