From 3775d811ff6dc1ed844aee7d15263a447ee18d52 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Mon, 22 Mar 2021 17:45:39 -0700 Subject: [PATCH] Improve module dumping for debugging. * List inferred lists of imports in `#pragma clang __debug module_map`. * Add `#pragma clang __debug modules {all,visible,building}` to dump lists of known / visible module names or the building modules stack. --- clang/include/clang/Basic/Module.h | 2 +- clang/include/clang/Lex/ModuleMap.h | 3 ++ clang/include/clang/Lex/Preprocessor.h | 5 ++++ clang/lib/Basic/Module.cpp | 13 +++++++-- clang/lib/Lex/Pragma.cpp | 51 ++++++++++++++++++++++++++++++++++ 5 files changed, 70 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/Basic/Module.h b/clang/include/clang/Basic/Module.h index 82ea1f4..16f34d1 100644 --- a/clang/include/clang/Basic/Module.h +++ b/clang/include/clang/Basic/Module.h @@ -637,7 +637,7 @@ public: } /// Print the module map for this module to the given stream. - void print(raw_ostream &OS, unsigned Indent = 0) const; + void print(raw_ostream &OS, unsigned Indent = 0, bool Dump = false) const; /// Dump the contents of this module to the given output stream. void dump() const; diff --git a/clang/include/clang/Lex/ModuleMap.h b/clang/include/clang/Lex/ModuleMap.h index f6423e5..64562e6 100644 --- a/clang/include/clang/Lex/ModuleMap.h +++ b/clang/include/clang/Lex/ModuleMap.h @@ -696,6 +696,9 @@ public: module_iterator module_begin() const { return Modules.begin(); } module_iterator module_end() const { return Modules.end(); } + llvm::iterator_range modules() const { + return {module_begin(), module_end()}; + } /// Cache a module load. M might be nullptr. void cacheModuleLoad(const IdentifierInfo &II, Module *M) { diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 68139cb..e34e35b 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -1163,6 +1163,11 @@ public: return None; } + /// Get the list of submodules that we're currently building. + ArrayRef getBuildingSubmodules() const { + return BuildingSubmoduleStack; + } + /// \{ /// Iterators for the macro history table. Currently defined macros have /// IdentifierInfo::hasMacroDefinition() set and an empty diff --git a/clang/lib/Basic/Module.cpp b/clang/lib/Basic/Module.cpp index 8730a5d..8d26149 100644 --- a/clang/lib/Basic/Module.cpp +++ b/clang/lib/Basic/Module.cpp @@ -429,7 +429,7 @@ void Module::buildVisibleModulesCache() const { } } -void Module::print(raw_ostream &OS, unsigned Indent) const { +void Module::print(raw_ostream &OS, unsigned Indent, bool Dump) const { OS.indent(Indent); if (IsFramework) OS << "framework "; @@ -535,7 +535,7 @@ void Module::print(raw_ostream &OS, unsigned Indent) const { // the module. Regular inferred submodules are OK, as we need to look at all // those header files anyway. if (!(*MI)->IsInferred || (*MI)->IsFramework) - (*MI)->print(OS, Indent + 2); + (*MI)->print(OS, Indent + 2, Dump); for (unsigned I = 0, N = Exports.size(); I != N; ++I) { OS.indent(Indent + 2); @@ -559,6 +559,13 @@ void Module::print(raw_ostream &OS, unsigned Indent) const { OS << "\n"; } + if (Dump) { + for (Module *M : Imports) { + OS.indent(Indent + 2); + llvm::errs() << "import " << M->getFullModuleName() << "\n"; + } + } + for (unsigned I = 0, N = DirectUses.size(); I != N; ++I) { OS.indent(Indent + 2); OS << "use "; @@ -619,7 +626,7 @@ void Module::print(raw_ostream &OS, unsigned Indent) const { } LLVM_DUMP_METHOD void Module::dump() const { - print(llvm::errs()); + print(llvm::errs(), 0, true); } void VisibleModuleSet::setVisible(Module *M, SourceLocation Loc, diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp index a05df06..5b42241 100644 --- a/clang/lib/Lex/Pragma.cpp +++ b/clang/lib/Lex/Pragma.cpp @@ -1122,6 +1122,57 @@ struct PragmaDebugHandler : public PragmaHandler { DebugOverflowStack(); } else if (II->isStr("captured")) { HandleCaptured(PP); + } else if (II->isStr("modules")) { + struct ModuleVisitor { + Preprocessor &PP; + void visit(Module *M, bool VisibleOnly) { + SourceLocation ImportLoc = PP.getModuleImportLoc(M); + if (!VisibleOnly || ImportLoc.isValid()) { + llvm::errs() << M->getFullModuleName() << " "; + if (ImportLoc.isValid()) { + llvm::errs() << M << " visible "; + ImportLoc.print(llvm::errs(), PP.getSourceManager()); + } + llvm::errs() << "\n"; + } + for (Module *Sub : M->submodules()) { + if (!VisibleOnly || ImportLoc.isInvalid() || Sub->IsExplicit) + visit(Sub, VisibleOnly); + } + } + void visitAll(bool VisibleOnly) { + for (auto &NameAndMod : + PP.getHeaderSearchInfo().getModuleMap().modules()) + visit(NameAndMod.second, VisibleOnly); + } + } Visitor{PP}; + + Token Kind; + PP.LexUnexpandedToken(Kind); + auto *DumpII = Kind.getIdentifierInfo(); + if (!DumpII) { + PP.Diag(Kind, diag::warn_pragma_debug_missing_argument) + << II->getName(); + } else if (DumpII->isStr("all")) { + Visitor.visitAll(false); + } else if (DumpII->isStr("visible")) { + Visitor.visitAll(true); + } else if (DumpII->isStr("building")) { + for (auto &Building : PP.getBuildingSubmodules()) { + llvm::errs() << "in " << Building.M->getFullModuleName(); + if (Building.ImportLoc.isValid()) { + llvm::errs() << " imported "; + if (Building.IsPragma) + llvm::errs() << "via pragma "; + llvm::errs() << "at "; + Building.ImportLoc.print(llvm::errs(), PP.getSourceManager()); + llvm::errs() << "\n"; + } + } + } else { + PP.Diag(Tok, diag::warn_pragma_debug_unexpected_command) + << DumpII->getName(); + } } else { PP.Diag(Tok, diag::warn_pragma_debug_unexpected_command) << II->getName(); -- 2.7.4