Author: Tom Honermann Date: 2022-10-03T17:25:44-04:00 New Revision: 4247cdb568eca4c31b14d91105fe5ee140225036
URL: https://github.com/llvm/llvm-project/commit/4247cdb568eca4c31b14d91105fe5ee140225036 DIFF: https://github.com/llvm/llvm-project/commit/4247cdb568eca4c31b14d91105fe5ee140225036.diff LOG: [clang]: Add DeclContext::dumpAsDecl(). This change enables a declaration to be conveniently displayed within a debugger when only a pointer to its DeclContext is available. For example, in gdb: (gdb) p Ctx $1 = (const clang::DeclContext *) 0x14c1a580 (gdb) p Ctx->dumpAsDecl() ClassTemplateSpecializationDecl 0x14c1a540 <t.cpp:1:1, line:7:1> line:2:8 struct ct `-TemplateArgument type 'int' `-BuiltinType 0x14bac420 'int' $2 = void In the event that the pointed to DeclContext is invalid (that it has an invalid DeclKind as a result of a dangling pointer, memory corruption, etc...) it is not possible to dump its associated declaration. In this case, the DeclContext will be reported as invalid. For example, in gdb: (gdb) p Ctx->dumpAsDecl() DeclContext 0x14c1a580 <unrecognized Decl kind 127> $3 = void Added: Modified: clang/include/clang/AST/ASTDumper.h clang/include/clang/AST/DeclBase.h clang/lib/AST/ASTDumper.cpp clang/lib/AST/DeclBase.cpp Removed: ################################################################################ diff --git a/clang/include/clang/AST/ASTDumper.h b/clang/include/clang/AST/ASTDumper.h index a154bc2db3a7..71ac467e5104 100644 --- a/clang/include/clang/AST/ASTDumper.h +++ b/clang/include/clang/AST/ASTDumper.h @@ -32,6 +32,7 @@ class ASTDumper : public ASTNodeTraverser<ASTDumper, TextNodeDumper> { TextNodeDumper &doGetNodeDelegate() { return NodeDumper; } + void dumpInvalidDeclContext(const DeclContext *DC); void dumpLookups(const DeclContext *DC, bool DumpDecls); template <typename SpecializationDecl> diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 1332b00232be..8a5f75573095 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -1909,6 +1909,10 @@ class DeclContext { public: ~DeclContext(); + // For use when debugging; hasValidDeclKind() will always return true for + // a correctly constructed object within its lifetime. + bool hasValidDeclKind() const; + Decl::Kind getDeclKind() const { return static_cast<Decl::Kind>(DeclContextBits.DeclKind); } @@ -2530,6 +2534,8 @@ class DeclContext { static bool classof(const Decl *D); static bool classof(const DeclContext *D) { return true; } + void dumpAsDecl() const; + void dumpAsDecl(const ASTContext *Ctx) const; void dumpDeclContext() const; void dumpLookups() const; void dumpLookups(llvm::raw_ostream &OS, bool DumpDecls = false, diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp index 60700f71c4b9..9900efb5a48d 100644 --- a/clang/lib/AST/ASTDumper.cpp +++ b/clang/lib/AST/ASTDumper.cpp @@ -19,9 +19,37 @@ #include "clang/Basic/Module.h" #include "clang/Basic/SourceManager.h" #include "llvm/Support/raw_ostream.h" + using namespace clang; using namespace clang::comments; +void ASTDumper::dumpInvalidDeclContext(const DeclContext *DC) { + NodeDumper.AddChild([=] { + if (!DC) { + ColorScope Color(OS, ShowColors, NullColor); + OS << "<<<NULL>>>"; + return; + } + // An invalid DeclContext is one for which a dyn_cast() from a DeclContext + // pointer to a Decl pointer would fail an assertion or otherwise fall prey + // to undefined behavior as a result of an invalid associated DeclKind. + // Such invalidity is not supposed to happen of course, but, when it does, + // the information provided below is intended to provide some hints about + // what might have gone awry. + { + ColorScope Color(OS, ShowColors, DeclKindNameColor); + OS << "DeclContext"; + } + NodeDumper.dumpPointer(DC); + OS << " <"; + { + ColorScope Color(OS, ShowColors, DeclNameColor); + OS << "unrecognized Decl kind " << (unsigned)DC->getDeclKind(); + } + OS << ">"; + }); +} + void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) { NodeDumper.AddChild([=] { OS << "StoredDeclsMap "; @@ -200,6 +228,31 @@ LLVM_DUMP_METHOD void Decl::dumpColor() const { P.Visit(this); } +LLVM_DUMP_METHOD void DeclContext::dumpAsDecl() const { + dumpAsDecl(nullptr); +} + +LLVM_DUMP_METHOD void DeclContext::dumpAsDecl(const ASTContext *Ctx) const { + // By design, DeclContext is required to be a base class of some class that + // derives from Decl. Thus, it should always be possible to dyn_cast() from + // a DeclContext pointer to a Decl pointer and Decl::castFromDeclContext() + // asserts that to be the case. Since this function is intended for use in a + // debugger, it performs an additional check in order to prevent a failed + // cast and assertion. If that check fails, then the (invalid) DeclContext + // is dumped with an indication of its invalidity. + if (hasValidDeclKind()) { + const auto *D = cast<Decl>(this); + D->dump(); + } else { + // If an ASTContext is not available, a less capable ASTDumper is + // constructed for which color diagnostics are, regrettably, disabled. + ASTDumper P = Ctx ? ASTDumper(llvm::errs(), *Ctx, + Ctx->getDiagnostics().getShowColors()) + : ASTDumper(llvm::errs(), /*ShowColors*/ false); + P.dumpInvalidDeclContext(this); + } +} + LLVM_DUMP_METHOD void DeclContext::dumpLookups() const { dumpLookups(llvm::errs()); } diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index e06235392af8..a9ac441092be 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -152,6 +152,15 @@ void Decl::setInvalidDecl(bool Invalid) { } } +bool DeclContext::hasValidDeclKind() const { + switch (getDeclKind()) { +#define DECL(DERIVED, BASE) case Decl::DERIVED: return true; +#define ABSTRACT_DECL(DECL) +#include "clang/AST/DeclNodes.inc" + } + return false; +} + const char *DeclContext::getDeclKindName() const { switch (getDeclKind()) { #define DECL(DERIVED, BASE) case Decl::DERIVED: return #DERIVED; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits