//===--- DeclContextDumper.cpp --------------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include "swift/AST/ASTContext.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/Attr.h" #include "swift/AST/Decl.h" #include "swift/AST/DeclContext.h" #include "swift/AST/Expr.h" #include "swift/AST/Pattern.h" #include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/AST/TypeRepr.h" #include "swift/Subsystems.h" #include "llvm/ADT/SetVector.h" using namespace swift; namespace { /// Collect 'DeclContext' hierarchy from AST. class DeclContextHierarchyCollector : public ASTWalker { llvm::DenseMap> ⤅ public: DeclContextHierarchyCollector( llvm::DenseMap> &Map) : Map(Map) {} // Insert DC and its ascendants into the map. void handle(DeclContext *DC) { if (!DC) return; auto *parentDC = DC->getParent(); if (Map[parentDC].insert(DC)) handle(parentDC); } PreWalkAction walkToDeclPre(Decl *D) override { handle(D->getDeclContext()); if (auto *dc = dyn_cast(D)) { handle(dc); } if (auto *PBD = dyn_cast(D)) { for (unsigned i = 0, e = PBD->getNumPatternEntries(); i != e; ++i) handle(PBD->getInitContext(i)); } for (auto *attr : D->getAttrs().getAttributes()) { handle(attr->getInitContext()); } return Action::Continue(); } PreWalkResult walkToExprPre(Expr *E) override { if (auto *dc = dyn_cast(E)) { handle(dc); } switch (E->getKind()) { case ExprKind::SingleValueStmt: handle(cast(E)->getDeclContext()); break; case ExprKind::MacroExpansion: handle(cast(E)->getDeclContext()); break; default: break; } return Action::Continue(E); } PreWalkResult walkToStmtPre(Stmt *S) override { switch (S->getKind()) { case StmtKind::DoCatch: handle(cast(S)->getDeclContext()); break; case StmtKind::Fallthrough: handle(cast(S)->getDeclContext()); break; case StmtKind::Break: handle(cast(S)->getDeclContext()); break; case StmtKind::Continue: handle(cast(S)->getDeclContext()); break; default: break; } return Action::Continue(S); } PreWalkResult walkToPatternPre(Pattern *P) override { switch (P->getKind()) { case PatternKind::EnumElement: handle(cast(P)->getDeclContext()); break; case PatternKind::Expr: handle(cast(P)->getDeclContext()); break; default: break; } return Action::Continue(P); } PreWalkAction walkToTypeReprPre(TypeRepr *T) override { switch (T->getKind()) { case TypeReprKind::QualifiedIdent: case TypeReprKind::UnqualifiedIdent: { auto *tyR = cast(T); if (tyR->isBound()) handle(tyR->getDeclContext()); break; } default: break; } return Action::Continue(); } }; } // namespace void swift::dumpDeclContextHierarchy(llvm::raw_ostream &OS, SourceFile &SF) { llvm::DenseMap> map; DeclContextHierarchyCollector collector(map); SF.walk(collector); std::function printChildrenDC = [&](DeclContext *parentDC, size_t indent) -> void { for (auto *DC : map[parentDC]) { DC->printContext(OS, indent, /*onlyAPartialLine=*/true); OS << "\n"; printChildrenDC(DC, indent + 2); } }; printChildrenDC(nullptr, 0); }