tahonermann updated this revision to Diff 464487.
tahonermann retitled this revision from "[clang]: Add DeclContext::dumpDecl() 
in order to conveniently dump an AST from a DeclContext." to "[clang]: Add 
DeclContext::dumpAsDecl().".
tahonermann edited the summary of this revision.
tahonermann added a comment.
Addressed review feedback; when presented with an invalid `DeclContext`, output 
will not be produced that explains why it is invalid.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D133499/new/

https://reviews.llvm.org/D133499

Files:
  clang/include/clang/AST/ASTDumper.h
  clang/include/clang/AST/DeclBase.h
  clang/lib/AST/ASTDumper.cpp
  clang/lib/AST/DeclBase.cpp

Index: clang/lib/AST/DeclBase.cpp
===================================================================
--- clang/lib/AST/DeclBase.cpp
+++ clang/lib/AST/DeclBase.cpp
@@ -152,6 +152,15 @@
   }
 }
 
+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;
Index: clang/lib/AST/ASTDumper.cpp
===================================================================
--- clang/lib/AST/ASTDumper.cpp
+++ 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,37 @@
   P.Visit(this);
 }
 
+LLVM_DUMP_METHOD void DeclContext::dumpAsDecl() const {
+  dumpAsDecl(nullptr);
+}
+
+LLVM_DUMP_METHOD void DeclContext::dumpAsDecl(const ASTContext *Ctx) const {
+  // By design, every DeclContext instance 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, indeed,
+  // the innerworkings of dyn_cast() do assert that to be the case! Alas,
+  // strange and unfortunate things do occasionally occur that lead to folk
+  // like yourself, dear reader, running a debugger and feeling extraordinarily
+  // curious about the origin of a DeclContext instance for which you have
+  // little knowledge. This function has been carefully designed to provide you,
+  // yes you, the answers you desperately seek and deserve with minimal risk
+  // that simply asking the question will upend your debugging experience. The
+  // call to dyn_cast() below is guarded by a validity check that ensures its
+  // success, thus preventing an otherwise potentially volatile (no, not that
+  // kind of volatile) situation.
+  if (hasValidDeclKind()) {
+    const Decl *D = dyn_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());
 }
Index: clang/include/clang/AST/DeclBase.h
===================================================================
--- clang/include/clang/AST/DeclBase.h
+++ clang/include/clang/AST/DeclBase.h
@@ -1906,6 +1906,10 @@
 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);
   }
@@ -2527,6 +2531,8 @@
   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,
Index: clang/include/clang/AST/ASTDumper.h
===================================================================
--- clang/include/clang/AST/ASTDumper.h
+++ clang/include/clang/AST/ASTDumper.h
@@ -32,6 +32,7 @@
 
   TextNodeDumper &doGetNodeDelegate() { return NodeDumper; }
 
+  void dumpInvalidDeclContext(const DeclContext *DC);
   void dumpLookups(const DeclContext *DC, bool DumpDecls);
 
   template <typename SpecializationDecl>
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to