Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ASTDumper] Dump DeclContext #79311

Merged
merged 1 commit into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions include/swift/Frontend/FrontendOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -449,9 +449,10 @@ class FrontendOptions {

/// The possible output formats supported for dumping ASTs.
enum class ASTFormat {
Default, ///< S-expressions for debugging
JSON, ///< Structured JSON for analysis
JSONZlib, ///< Like JSON, but zlib-compressed
Default, ///< S-expressions for debugging
DefaultWithDeclContext, ///< S-expressions with DeclContext hierarchy
JSON, ///< Structured JSON for analysis
JSONZlib, ///< Like JSON, but zlib-compressed
};

/// The output format generated by the `-dump-ast` flag.
Expand Down
3 changes: 3 additions & 0 deletions include/swift/Subsystems.h
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,9 @@ namespace swift {
/// Dump YAML describing all fixed-size types imported from the given module.
bool performDumpTypeInfo(const IRGenOptions &Opts, SILModule &SILMod);

/// Dump DeclContext hierarchy of the all nodes in \c SF .
void dumpDeclContextHierarchy(llvm::raw_ostream &OS, SourceFile &SF);

/// Creates a TargetMachine from the IRGen opts and AST Context.
std::unique_ptr<llvm::TargetMachine>
createTargetMachine(const IRGenOptions &Opts, ASTContext &Ctx);
Expand Down
124 changes: 83 additions & 41 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1019,6 +1019,10 @@ namespace {
return Writer.hasNonStandardOutput();
}

bool isTypeChecked() const {
return MemberLoading == ASTDumpMemberLoading::TypeChecked;
}

/// Call `Body` in a context where the printer is ready for a child to be
/// printed.
void printRecArbitrary(std::function<void(Label)> body, Label label) {
Expand Down Expand Up @@ -1613,11 +1617,17 @@ namespace {
}
}

template <typename T>
void printDeclContext(const T *D) {
printField(static_cast<void *>(D->getDeclContext()),
Label::always("decl_context"));
}

/// Prints a field containing the name or the USR (based on parsability of
/// the output) of a decl that is being referenced elsewhere.
template <typename T>
void printReferencedDeclField(const T *D, Label label) {
if (Writer.isParsable()) {
if (Writer.isParsable() && isTypeChecked()) {
printFieldQuoted(declUSR(D), label);
} else {
printFieldQuoted(D->getName(), label);
Expand All @@ -1629,7 +1639,7 @@ namespace {
template <typename T>
void printReferencedDeclWithContextField(const T *D, Label label,
TerminalColor Color = DeclColor) {
if (Writer.isParsable()) {
if (Writer.isParsable() && isTypeChecked()) {
printFieldQuoted(declUSR(D), label, Color);
} else {
printFieldQuoted(D->printRef(), label, Color);
Expand All @@ -1639,7 +1649,7 @@ namespace {
/// Print a field containing a concrete reference to a declaration.
void printDeclRefField(ConcreteDeclRef declRef, Label label,
TerminalColor Color = DeclColor) {
if (Writer.isParsable()) {
if (Writer.isParsable() && isTypeChecked()) {
// Just omit the key/value for parsable formats if there's no decl.
if (!declRef.getDecl())
return;
Expand Down Expand Up @@ -1808,6 +1818,7 @@ namespace {
}
void visitExprPattern(ExprPattern *P, Label label) {
printCommon(P, "pattern_expr", label);
printDeclContext(P);
switch (P->getCachedMatchOperandOwnership()) {
case ValueOwnership::Default:
break;
Expand Down Expand Up @@ -1838,6 +1849,7 @@ namespace {
}
void visitEnumElementPattern(EnumElementPattern *P, Label label) {
printCommon(P, "pattern_enum_element", label);
printDeclContext(P);

if (Writer.isParsable()) {
printName(P->getName().getFullName(), Label::always("element"));
Expand Down Expand Up @@ -1894,12 +1906,14 @@ namespace {
// Parsable outputs include the USR for each decl since they can be used
// to cross-reference them (within the AST dump itself and with other data
// sources like indexstore and SourceKit).
if (Writer.isParsable()) {
if (Writer.isParsable() && isTypeChecked()) {
if (auto usr = declUSR(D); !usr.empty()) {
printFieldQuoted(usr, Label::always("usr"));
}
}

printDeclContext(D);

printFlag(D->isImplicit(), "implicit", DeclModifierColor);
printFlag(D->isHoisted(), "hoisted", DeclModifierColor);

Expand All @@ -1918,7 +1932,7 @@ namespace {
printFlag(D->TrailingSemiLoc.isValid(), "trailing_semi",
DeclModifierColor);

if (Writer.isParsable()) {
if (Writer.isParsable() && isTypeChecked()) {
// Print just the USRs of any auxiliary decls associated with this decl,
// which lets us relate macro expansions back to their originating decl
// if desired.
Expand Down Expand Up @@ -2097,13 +2111,15 @@ namespace {

printWhereRequirements(decl);
if (decl->overriddenDeclsComputed()) {
printStringListField(decl->getOverriddenDecls(),
[&](AssociatedTypeDecl *overridden) {
if (Writer.isParsable()) {
return declUSR(overridden->getProtocol());
}
return std::string(overridden->getProtocol()->getName().str());
}, Label::always("overridden"), /*delimiter=*/ ", ");
printStringListField(
decl->getOverriddenDecls(),
[&](AssociatedTypeDecl *overridden) {
if (Writer.isParsable() && isTypeChecked()) {
return declUSR(overridden->getProtocol());
}
return std::string(overridden->getProtocol()->getName().str());
},
Label::always("overridden"), /*delimiter=*/", ");
}

printAttributes(decl);
Expand Down Expand Up @@ -2213,15 +2229,18 @@ namespace {

if (VD->overriddenDeclsComputed()) {
auto overridden = VD->getOverriddenDecls();
printStringListField(overridden, [&](ValueDecl *overridden) {
if (Writer.isParsable()) {
return declUSR(overridden);
}
std::string value;
llvm::raw_string_ostream SOS(value);
overridden->dumpRef(SOS);
return value;
}, Label::always("override"), /*delimiter=*/ ", ", OverrideColor);
printStringListField(
overridden,
[&](ValueDecl *overridden) {
if (Writer.isParsable() && isTypeChecked()) {
return declUSR(overridden);
}
std::string value;
llvm::raw_string_ostream SOS(value);
overridden->dumpRef(SOS);
return value;
},
Label::always("override"), /*delimiter=*/", ", OverrideColor);
}

auto VarD = dyn_cast<VarDecl>(VD);
Expand Down Expand Up @@ -2423,6 +2442,8 @@ namespace {
printHead("parameter", ParameterColor, label);

printDeclName(PD, Label::optional("name"));

printDeclContext(PD);
if (!PD->getArgumentName().empty())
printFieldQuoted(PD->getArgumentName(), Label::always("apiName"),
IdentifierColor);
Expand Down Expand Up @@ -2521,23 +2542,32 @@ namespace {
printCommon(PBD, "pattern_binding_decl", label);
printAttributes(PBD);

printList(range(PBD->getNumPatternEntries()), [&](auto idx, Label label) {
// Ensure that we have an object structure printed in parsable modes
// so that the children aren't directly rendered as array elements.
if (Writer.isParsable())
printHead("pattern_entry", FieldLabelColor, label);

printRec(PBD->getPattern(idx), Label::optional("pattern"));
if (PBD->getOriginalInit(idx)) {
printRec(PBD->getOriginalInit(idx), Label::always("original_init"));
}
if (PBD->getInit(idx)) {
printRec(PBD->getInit(idx), Label::always("processed_init"));
}
printList(
range(PBD->getNumPatternEntries()),
[&](auto idx, Label label) {
printRecArbitrary(
[&](Label label) {
printHead("pattern_entry", FieldLabelColor, label);

if (PBD->getInitContext(idx))
printField(PBD->getInitContext(idx),
Label::always("init_context"));

printRec(PBD->getPattern(idx), Label::optional("pattern"));
if (PBD->getOriginalInit(idx)) {
printRec(PBD->getOriginalInit(idx),
Label::always("original_init"));
}
if (PBD->getInit(idx)) {
printRec(PBD->getInit(idx),
Label::always("processed_init"));
}

if (Writer.isParsable())
printFoot();
}, Label::optional("pattern_entries"));
printFoot();
},
Label::optional("pattern_entry"));
},
Label::optional("pattern_entries"));
printFoot();
}

Expand Down Expand Up @@ -3094,14 +3124,17 @@ class PrintStmt : public StmtVisitor<PrintStmt, void, Label>,
}
void visitBreakStmt(BreakStmt *S, Label label) {
printCommon(S, "break_stmt", label);
printDeclContext(S);
printFoot();
}
void visitContinueStmt(ContinueStmt *S, Label label) {
printCommon(S, "continue_stmt", label);
printDeclContext(S);
printFoot();
}
void visitFallthroughStmt(FallthroughStmt *S, Label label) {
printCommon(S, "fallthrough_stmt", label);
printDeclContext(S);
printFoot();
}
void visitSwitchStmt(SwitchStmt *S, Label label) {
Expand Down Expand Up @@ -3185,6 +3218,7 @@ class PrintStmt : public StmtVisitor<PrintStmt, void, Label>,

void visitDoCatchStmt(DoCatchStmt *S, Label label) {
printCommon(S, "do_catch_stmt", label);
printDeclContext(S);
printThrowDest(S->rethrows(), /*wantNothrow=*/true);
printRec(S->getBody(), Label::always("body"));
printRecRange(S->getCatches(), Ctx, Label::always("catch_stmts"));
Expand Down Expand Up @@ -4347,6 +4381,7 @@ class PrintExpr : public ExprVisitor<PrintExpr, void, Label>,

void visitSingleValueStmtExpr(SingleValueStmtExpr *E, Label label) {
printCommon(E, "single_value_stmt_expr", label);
printDeclContext(E);
printRec(E->getStmt(), &E->getDeclContext()->getASTContext(),
Label::optional("stmt"));
printFoot();
Expand Down Expand Up @@ -4381,6 +4416,7 @@ class PrintExpr : public ExprVisitor<PrintExpr, void, Label>,

void visitMacroExpansionExpr(MacroExpansionExpr *E, Label label) {
printCommon(E, "macro_expansion_expr", label);
printDeclContext(E);

printFieldQuoted(E->getMacroName(), Label::always("name"), IdentifierColor);
printField(E->getRawDiscriminator(), Label::always("discriminator"),
Expand Down Expand Up @@ -4482,6 +4518,7 @@ class PrintTypeRepr : public TypeReprVisitor<PrintTypeRepr, void, Label>,
printFieldQuoted(T->getNameRef(), Label::always("id"), IdentifierColor);
if (T->isBound()) {
printReferencedDeclWithContextField(T->getBoundDecl(), Label::always("bind"));
printDeclContext(T);
} else {
printFlag("unbound");
}
Expand Down Expand Up @@ -4974,6 +5011,11 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, Label>,
}
void visitCustomAttr(CustomAttr *Attr, Label label) {
printCommon(Attr, "custom_attr", label);

printField(
static_cast<void *>(static_cast<DeclContext *>(Attr->getInitContext())),
Label::always("init_context"));

if (Attr->getType()) {
printTypeField(Attr->getType(), Label::always("type"));
} else if (MemberLoading == ASTDumpMemberLoading::TypeChecked) {
Expand Down Expand Up @@ -5050,7 +5092,7 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, Label>,
}
void visitImplementsAttr(ImplementsAttr *Attr, Label label) {
printCommon(Attr, "implements_attr", label);
if (Writer.isParsable()) {
if (Writer.isParsable() && isTypeChecked()) {
// Print the resolved protocol's USR in parsable outputs, not the
// TypeRepr.
if (auto PD = Attr->getCachedProtocol(DC); PD && *PD != nullptr) {
Expand Down Expand Up @@ -5212,7 +5254,7 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, Label>,
Label label) {
printCommon(Attr, "restated_objc_conformance_attr", label);
if (Attr->Proto) {
if (Writer.isParsable()) {
if (Writer.isParsable() && isTypeChecked()) {
printFieldQuoted(declUSR(Attr->Proto), Label::optional("proto"));
} else {
printFieldRaw([&](auto &out) { Attr->Proto->dumpRef(out); },
Expand Down Expand Up @@ -5293,7 +5335,7 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, Label>,
Label label) {
printCommon(Attr, "synthesized_protocol_attr", label);
printFlag(Attr->isUnchecked(), "unchecked");
if (Writer.isParsable()) {
if (Writer.isParsable() && isTypeChecked()) {
printFieldQuoted(declUSR(Attr->getProtocol()),
Label::optional("protocol"));
} else {
Expand Down Expand Up @@ -5490,7 +5532,7 @@ class PrintConformance : public PrintBase {
printFlag("no_witness");
else if (witness.getDecl() == req)
printFlag("dynamic_witness");
else if (Writer.isParsable()) {
else if (Writer.isParsable() && isTypeChecked()) {
printFieldQuoted(declUSR(witness.getDecl()),
Label::always("witness"));
} else {
Expand Down
1 change: 1 addition & 0 deletions lib/AST/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ add_swift_host_library(swiftAST STATIC
ConformanceLookupTable.cpp
Decl.cpp
DeclContext.cpp
DeclContextDumper.cpp
DeclNameLoc.cpp
DiagnosticBridge.cpp
DiagnosticConsumer.cpp
Expand Down
3 changes: 2 additions & 1 deletion lib/AST/DeclContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -760,7 +760,8 @@ unsigned DeclContext::printContext(raw_ostream &OS, const unsigned indent,
case DeclContextKind::EnumElementDecl: Kind = "EnumElementDecl"; break;
case DeclContextKind::MacroDecl: Kind = "MacroDecl"; break;
}
OS.indent(Depth*2 + indent) << (void*)this << " " << Kind;
OS.indent(Depth * 2 + indent)
<< static_cast<const void *>(this) << " " << Kind;

switch (getContextKind()) {
case DeclContextKind::Package:
Expand Down
Loading