mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[ASTDumper] Dump DeclContext
* Include `DeclContext` of the node where possible * Add 'default-with-decl-contexts' dump style that dumps the dect context hierarchy in addition to the AST * Support `-dump-parse` with `-dump-ast-format json`
This commit is contained in:
@@ -449,9 +449,10 @@ public:
|
||||
|
||||
/// 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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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"));
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
printList(
|
||||
range(PBD->getNumPatternEntries()),
|
||||
[&](auto idx, Label label) {
|
||||
printRecArbitrary(
|
||||
[&](Label label) {
|
||||
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"));
|
||||
}
|
||||
if (PBD->getInitContext(idx))
|
||||
printField(PBD->getInitContext(idx),
|
||||
Label::always("init_context"));
|
||||
|
||||
if (Writer.isParsable())
|
||||
printFoot();
|
||||
}, Label::optional("pattern_entries"));
|
||||
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"));
|
||||
}
|
||||
|
||||
printFoot();
|
||||
},
|
||||
Label::optional("pattern_entry"));
|
||||
},
|
||||
Label::optional("pattern_entries"));
|
||||
printFoot();
|
||||
}
|
||||
|
||||
@@ -3094,14 +3124,17 @@ public:
|
||||
}
|
||||
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) {
|
||||
@@ -3185,6 +3218,7 @@ public:
|
||||
|
||||
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"));
|
||||
@@ -4347,6 +4381,7 @@ public:
|
||||
|
||||
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();
|
||||
@@ -4381,6 +4416,7 @@ public:
|
||||
|
||||
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"),
|
||||
@@ -4482,6 +4518,7 @@ public:
|
||||
printFieldQuoted(T->getNameRef(), Label::always("id"), IdentifierColor);
|
||||
if (T->isBound()) {
|
||||
printReferencedDeclWithContextField(T->getBoundDecl(), Label::always("bind"));
|
||||
printDeclContext(T);
|
||||
} else {
|
||||
printFlag("unbound");
|
||||
}
|
||||
@@ -4974,6 +5011,11 @@ public:
|
||||
}
|
||||
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) {
|
||||
@@ -5050,7 +5092,7 @@ public:
|
||||
}
|
||||
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) {
|
||||
@@ -5212,7 +5254,7 @@ public:
|
||||
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); },
|
||||
@@ -5293,7 +5335,7 @@ public:
|
||||
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 {
|
||||
@@ -5490,7 +5532,7 @@ public:
|
||||
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 {
|
||||
|
||||
@@ -42,6 +42,7 @@ add_swift_host_library(swiftAST STATIC
|
||||
ConformanceLookupTable.cpp
|
||||
Decl.cpp
|
||||
DeclContext.cpp
|
||||
DeclContextDumper.cpp
|
||||
DeclNameLoc.cpp
|
||||
DiagnosticBridge.cpp
|
||||
DiagnosticConsumer.cpp
|
||||
|
||||
@@ -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:
|
||||
|
||||
153
lib/AST/DeclContextDumper.cpp
Normal file
153
lib/AST/DeclContextDumper.cpp
Normal file
@@ -0,0 +1,153 @@
|
||||
//===--- 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<DeclContext *, llvm::SetVector<DeclContext *>> ⤅
|
||||
|
||||
public:
|
||||
DeclContextHierarchyCollector(
|
||||
llvm::DenseMap<DeclContext *, llvm::SetVector<DeclContext *>> &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<DeclContext>(D)) {
|
||||
handle(dc);
|
||||
}
|
||||
|
||||
if (auto *PBD = dyn_cast<PatternBindingDecl>(D)) {
|
||||
for (unsigned i = 0, e = PBD->getNumPatternEntries(); i != e; ++i)
|
||||
handle(PBD->getInitContext(i));
|
||||
}
|
||||
|
||||
for (auto *attr : D->getAttrs().getAttributes<CustomAttr>()) {
|
||||
handle(attr->getInitContext());
|
||||
}
|
||||
|
||||
return Action::Continue();
|
||||
}
|
||||
|
||||
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
|
||||
if (auto *dc = dyn_cast<AbstractClosureExpr>(E)) {
|
||||
handle(dc);
|
||||
}
|
||||
switch (E->getKind()) {
|
||||
case ExprKind::SingleValueStmt:
|
||||
handle(cast<SingleValueStmtExpr>(E)->getDeclContext());
|
||||
break;
|
||||
case ExprKind::MacroExpansion:
|
||||
handle(cast<MacroExpansionExpr>(E)->getDeclContext());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return Action::Continue(E);
|
||||
}
|
||||
|
||||
PreWalkResult<Stmt *> walkToStmtPre(Stmt *S) override {
|
||||
switch (S->getKind()) {
|
||||
case StmtKind::DoCatch:
|
||||
handle(cast<DoCatchStmt>(S)->getDeclContext());
|
||||
break;
|
||||
case StmtKind::Fallthrough:
|
||||
handle(cast<FallthroughStmt>(S)->getDeclContext());
|
||||
break;
|
||||
case StmtKind::Break:
|
||||
handle(cast<BreakStmt>(S)->getDeclContext());
|
||||
break;
|
||||
case StmtKind::Continue:
|
||||
handle(cast<ContinueStmt>(S)->getDeclContext());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return Action::Continue(S);
|
||||
}
|
||||
|
||||
PreWalkResult<Pattern *> walkToPatternPre(Pattern *P) override {
|
||||
switch (P->getKind()) {
|
||||
case PatternKind::EnumElement:
|
||||
handle(cast<EnumElementPattern>(P)->getDeclContext());
|
||||
break;
|
||||
case PatternKind::Expr:
|
||||
handle(cast<ExprPattern>(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<DeclRefTypeRepr>(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<DeclContext *, llvm::SetVector<DeclContext *>> map;
|
||||
|
||||
DeclContextHierarchyCollector collector(map);
|
||||
SF.walk(collector);
|
||||
|
||||
std::function<void(DeclContext *, size_t)> 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);
|
||||
}
|
||||
@@ -212,18 +212,20 @@ bool ArgsToFrontendOptionsConverter::convert(
|
||||
// Ensure that the compiler was built with zlib support if it was the
|
||||
// requested AST format.
|
||||
if (const Arg *A = Args.getLastArg(OPT_dump_ast_format)) {
|
||||
auto format =
|
||||
llvm::StringSwitch<std::optional<FrontendOptions::ASTFormat>>(A->getValue())
|
||||
.Case("json", FrontendOptions::ASTFormat::JSON)
|
||||
.Case("json-zlib", FrontendOptions::ASTFormat::JSONZlib)
|
||||
.Case("default", FrontendOptions::ASTFormat::Default)
|
||||
.Default(std::nullopt);
|
||||
auto format = llvm::StringSwitch<std::optional<FrontendOptions::ASTFormat>>(
|
||||
A->getValue())
|
||||
.Case("json", FrontendOptions::ASTFormat::JSON)
|
||||
.Case("json-zlib", FrontendOptions::ASTFormat::JSONZlib)
|
||||
.Case("default", FrontendOptions::ASTFormat::Default)
|
||||
.Case("default-with-decl-contexts",
|
||||
FrontendOptions::ASTFormat::DefaultWithDeclContext)
|
||||
.Default(std::nullopt);
|
||||
if (!format.has_value()) {
|
||||
Diags.diagnose(SourceLoc(), diag::unknown_dump_ast_format, A->getValue());
|
||||
return true;
|
||||
}
|
||||
if (format != FrontendOptions::ASTFormat::Default &&
|
||||
!Args.hasArg(OPT_dump_ast)) {
|
||||
(!Args.hasArg(OPT_dump_ast) && !Args.hasArg(OPT_dump_parse))) {
|
||||
Diags.diagnose(SourceLoc(), diag::ast_format_requires_dump_ast);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -467,11 +467,15 @@ getPrimaryOrMainSourceFile(const CompilerInstance &Instance) {
|
||||
static bool dumpAST(CompilerInstance &Instance,
|
||||
ASTDumpMemberLoading memberLoading) {
|
||||
const FrontendOptions &opts = Instance.getInvocation().getFrontendOptions();
|
||||
auto dumpAST = [&](SourceFile *SF, raw_ostream &out) {
|
||||
auto dumpAST = [&](SourceFile *SF, llvm::raw_ostream &out) {
|
||||
switch (opts.DumpASTFormat) {
|
||||
case FrontendOptions::ASTFormat::Default:
|
||||
SF->dump(out, memberLoading);
|
||||
break;
|
||||
case FrontendOptions::ASTFormat::DefaultWithDeclContext:
|
||||
swift::dumpDeclContextHierarchy(out, *SF);
|
||||
SF->dump(out, memberLoading);
|
||||
break;
|
||||
case FrontendOptions::ASTFormat::JSON:
|
||||
SF->dumpJSON(out, memberLoading);
|
||||
break;
|
||||
@@ -495,7 +499,7 @@ static bool dumpAST(CompilerInstance &Instance,
|
||||
auto OutputFilename = PSPs.OutputFilename;
|
||||
if (withOutputPath(Instance.getASTContext().Diags,
|
||||
Instance.getOutputBackend(), OutputFilename,
|
||||
[&](raw_ostream &out) -> bool {
|
||||
[&](llvm::raw_ostream &out) -> bool {
|
||||
dumpAST(sourceFile, out);
|
||||
return false;
|
||||
}))
|
||||
|
||||
@@ -63,11 +63,11 @@ extension MainProtocol {
|
||||
#endif
|
||||
|
||||
// CHECK-IS-SYNC-LABEL: "MyMain" interface_type="MyMain.Type"
|
||||
// CHECK-IS-SYNC: (func_decl implicit "$main()" interface_type="(MyMain.Type) -> () -> ()"
|
||||
// CHECK-IS-SYNC: (func_decl {{.*}}implicit "$main()" interface_type="(MyMain.Type) -> () -> ()"
|
||||
// CHECK-IS-SYNC: (declref_expr implicit type="(MyMain.Type) -> () -> ()"
|
||||
|
||||
// CHECK-IS-ASYNC-LABEL: "MyMain" interface_type="MyMain.Type"
|
||||
// CHECK-IS-ASYNC: (func_decl implicit "$main()" interface_type="(MyMain.Type) -> () async -> ()"
|
||||
// CHECK-IS-ASYNC: (func_decl {{.*}}implicit "$main()" interface_type="(MyMain.Type) -> () async -> ()"
|
||||
// CHECK-IS-ASYNC: (declref_expr implicit type="(MyMain.Type) -> () async -> ()"
|
||||
|
||||
// CHECK-IS-ERROR1: error: 'MyMain' is annotated with @main and must provide a main static function of type {{\(\) -> Void or \(\) throws -> Void|\(\) -> Void, \(\) throws -> Void, \(\) async -> Void, or \(\) async throws -> Void}}
|
||||
|
||||
@@ -16,28 +16,28 @@ protocol App {
|
||||
|
||||
// Load in the source file name and grab line numbers for default main funcs
|
||||
// CHECK: (source_file "[[SOURCE_FILE:[^"]+]]"
|
||||
// CHECK: (extension_decl range={{\[}}[[SOURCE_FILE]]:{{[0-9]+}}:{{[0-9]+}} - line:{{[0-9]+}}:{{[0-9]+}}{{\]}} "App" where
|
||||
// CHECK: (extension_decl range={{\[}}[[SOURCE_FILE]]:{{[0-9]+}}:{{[0-9]+}} - line:{{[0-9]+}}:{{[0-9]+}}{{\]}} "App" where
|
||||
// CHECK: (extension_decl range={{\[}}[[SOURCE_FILE]]:{{[0-9]+}}:{{[0-9]+}} - line:{{[0-9]+}}:{{[0-9]+}}{{\]}} "App" where
|
||||
// CHECK: (extension_decl range={{\[}}[[SOURCE_FILE]]:{{[0-9]+}}:{{[0-9]+}} - line:{{[0-9]+}}:{{[0-9]+}}{{\]}}
|
||||
// CHECK: (extension_decl {{.*}} range={{\[}}[[SOURCE_FILE]]:{{[0-9]+}}:{{[0-9]+}} - line:{{[0-9]+}}:{{[0-9]+}}{{\]}} "App" where
|
||||
// CHECK: (extension_decl {{.*}} range={{\[}}[[SOURCE_FILE]]:{{[0-9]+}}:{{[0-9]+}} - line:{{[0-9]+}}:{{[0-9]+}}{{\]}} "App" where
|
||||
// CHECK: (extension_decl {{.*}} range={{\[}}[[SOURCE_FILE]]:{{[0-9]+}}:{{[0-9]+}} - line:{{[0-9]+}}:{{[0-9]+}}{{\]}} "App" where
|
||||
// CHECK: (extension_decl {{.*}} range={{\[}}[[SOURCE_FILE]]:{{[0-9]+}}:{{[0-9]+}} - line:{{[0-9]+}}:{{[0-9]+}}{{\]}}
|
||||
// CHECK-NOT: where
|
||||
// CHECK-NEXT: (func_decl range={{\[}}[[SOURCE_FILE]]:[[DEFAULT_ASYNCHRONOUS_MAIN_LINE:[0-9]+]]:{{[0-9]+}} - line:{{[0-9]+}}:{{[0-9]+}}{{\]}} "main()"
|
||||
// CHECK-NEXT: (func_decl {{.*}} range={{\[}}[[SOURCE_FILE]]:[[DEFAULT_ASYNCHRONOUS_MAIN_LINE:[0-9]+]]:{{[0-9]+}} - line:{{[0-9]+}}:{{[0-9]+}}{{\]}} "main()"
|
||||
// CHECK-SAME: interface_type="<Self where Self : App> (Self.Type) -> () async -> ()"
|
||||
|
||||
extension App where Configuration == Config1 {
|
||||
// CHECK-CONFIG1: (func_decl implicit "$main()" interface_type="(MainType.Type) -> () -> ()"
|
||||
// CHECK-CONFIG1: (func_decl {{.*}}implicit "$main()" interface_type="(MainType.Type) -> () -> ()"
|
||||
// CHECK-CONFIG1: [[SOURCE_FILE]]:[[# @LINE+1 ]]
|
||||
static func main() { }
|
||||
}
|
||||
|
||||
extension App where Configuration == Config2 {
|
||||
// CHECK-CONFIG2: (func_decl implicit "$main()" interface_type="(MainType.Type) -> () async -> ()"
|
||||
// CHECK-CONFIG2: (func_decl {{.*}}implicit "$main()" interface_type="(MainType.Type) -> () async -> ()"
|
||||
// CHECK-CONFIG2: [[SOURCE_FILE]]:[[# @LINE+1 ]]
|
||||
static func main() async { }
|
||||
}
|
||||
|
||||
extension App where Configuration == Config3 {
|
||||
// CHECK-CONFIG3-ASYNC: (func_decl implicit "$main()" interface_type="(MainType.Type) -> () async -> ()"
|
||||
// CHECK-CONFIG3-ASYNC: (func_decl {{.*}}implicit "$main()" interface_type="(MainType.Type) -> () async -> ()"
|
||||
// CHECK-CONFIG3-ASYNC: [[SOURCE_FILE]]:[[DEFAULT_ASYNCHRONOUS_MAIN_LINE]]
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ enum NonBarBaz {
|
||||
let _: Foo<Bar> = Foo<Bar> { (a: Bar) -> Void in
|
||||
switch a {
|
||||
// CHECK: (pattern_is type="any Bar" cast_kind=value_cast cast_to="Baz"
|
||||
// CHECK-NEXT: (pattern_enum_element type="Baz" element="Baz.someCase"
|
||||
// CHECK-NEXT: (pattern_enum_element type="Baz" {{.*}} element="Baz.someCase"
|
||||
case let .someCase(value) as Baz:
|
||||
print(value)
|
||||
// expected-warning@-1 {{cast from 'any Bar' to unrelated type 'NonBarBaz' always fails}}
|
||||
|
||||
@@ -49,9 +49,9 @@ func tuplify<T>(@TupleBuilder body: (E) throws -> T) rethrows {
|
||||
tuplify {
|
||||
switch $0 {
|
||||
// CHECK: (case_body_variables
|
||||
// CHECK-NEXT: (var_decl implicit {{.*}} "a" interface_type="String" let readImpl=stored immutable
|
||||
// CHECK-NEXT: (var_decl {{.*}} implicit {{.*}} "a" interface_type="String" let readImpl=stored immutable
|
||||
// CHECK-NEXT: (has_storage_attr implicit))
|
||||
// CHECK-NEXT: (var_decl implicit {{.*}} "b" interface_type="Int" let readImpl=stored immutable
|
||||
// CHECK-NEXT: (var_decl {{.*}} implicit {{.*}} "b" interface_type="Int" let readImpl=stored immutable
|
||||
// CHECK-NEXT: (has_storage_attr implicit))
|
||||
case let .test(a, b):
|
||||
a
|
||||
@@ -60,9 +60,9 @@ tuplify {
|
||||
|
||||
switch $0 {
|
||||
// CHECK: (case_body_variables
|
||||
// CHECK-NEXT: (var_decl implicit {{.*}} "a" interface_type="String" let readImpl=stored immutable
|
||||
// CHECK-NEXT: (var_decl {{.*}} implicit {{.*}} "a" interface_type="String" let readImpl=stored immutable
|
||||
// CHECK-NEXT: (has_storage_attr implicit))
|
||||
// CHECK-NEXT: (var_decl implicit {{.*}} "b" interface_type="Int" let readImpl=stored immutable
|
||||
// CHECK-NEXT: (var_decl {{.*}} implicit {{.*}} "b" interface_type="Int" let readImpl=stored immutable
|
||||
// CHECK-NEXT: (has_storage_attr implicit))
|
||||
case .test(let a, let b):
|
||||
a
|
||||
@@ -71,21 +71,21 @@ tuplify {
|
||||
|
||||
switch $0 {
|
||||
// CHECK: (case_body_variables
|
||||
// CHECK-NEXT: (var_decl implicit {{.*}} "value" interface_type="(a: String, b: Int)" let readImpl=stored immutable
|
||||
// CHECK-NEXT: (var_decl {{.*}} implicit {{.*}} "value" interface_type="(a: String, b: Int)" let readImpl=stored immutable
|
||||
case let .test((value)):
|
||||
value.a
|
||||
}
|
||||
|
||||
switch $0 {
|
||||
// CHECK: (case_body_variables
|
||||
// CHECK-NEXT: (var_decl implicit {{.*}} "value" interface_type="(a: String, b: Int)" let readImpl=stored immutable
|
||||
// CHECK-NEXT: (var_decl {{.*}} implicit {{.*}} "value" interface_type="(a: String, b: Int)" let readImpl=stored immutable
|
||||
case let .test(value):
|
||||
value.a
|
||||
}
|
||||
|
||||
switch $0 {
|
||||
// CHECK: (case_body_variables
|
||||
// CHECK-NEXT: (var_decl implicit {{.*}} "value" interface_type="(a: String, b: Int)" let readImpl=stored immutable
|
||||
// CHECK-NEXT: (var_decl {{.*}} implicit {{.*}} "value" interface_type="(a: String, b: Int)" let readImpl=stored immutable
|
||||
case .test(let value):
|
||||
value.a
|
||||
}
|
||||
|
||||
@@ -27,10 +27,10 @@ import ObjCModule
|
||||
|
||||
let pureSwift = Int32(42)
|
||||
// FAIL-NOT: var_decl
|
||||
// CHECK: var_decl "pureSwift"{{.*}} interface_type="Int32"
|
||||
// SWIFTONLY: var_decl "pureSwift"{{.*}} interface_type="Int32"
|
||||
// CHECK: var_decl {{.*}} "pureSwift"{{.*}} interface_type="Int32"
|
||||
// SWIFTONLY: var_decl {{.*}} "pureSwift"{{.*}} interface_type="Int32"
|
||||
|
||||
let point = Point(x: 1, y: 2)
|
||||
// CHECK: var_decl "point"{{.*}} interface_type="Point"
|
||||
// SWIFTONLY-NOT: var_decl "point"
|
||||
// CHECK: var_decl {{.*}} "point"{{.*}} interface_type="Point"
|
||||
// SWIFTONLY-NOT: var_decl {{.*}} "point"
|
||||
|
||||
|
||||
@@ -76,25 +76,25 @@ nonescaping({ $0 })
|
||||
// CHECK-AST-NEXT: (argument
|
||||
// CHECK-AST-NEXT: (closure_expr type="(Int) -> Int" {{.*}} discriminator=1 nonisolated single_expression
|
||||
|
||||
// CHECK-LABEL: (struct_decl range=[{{.+}}] "MyStruct")
|
||||
// CHECK-LABEL: (struct_decl decl_context=0x{{[0-9a-z]+}} range=[{{.+}}] "MyStruct")
|
||||
struct MyStruct {}
|
||||
|
||||
// CHECK-LABEL: (enum_decl range=[{{.+}}] "MyEnum"
|
||||
// CHECK-LABEL: (enum_decl decl_context=0x{{[0-9a-z]+}} range=[{{.+}}] "MyEnum"
|
||||
enum MyEnum {
|
||||
|
||||
// CHECK-LABEL: (enum_case_decl range=[{{.+}}]
|
||||
// CHECK-NEXT: (enum_element_decl range=[{{.+}}] "foo(x:)"
|
||||
// CHECK-LABEL: (enum_case_decl decl_context=0x{{[0-9a-z]+}} range=[{{.+}}]
|
||||
// CHECK-NEXT: (enum_element_decl decl_context=0x{{[0-9a-z]+}} range=[{{.+}}] "foo(x:)"
|
||||
// CHECK-NEXT: (parameter_list range=[{{.+}}]
|
||||
// CHECK-NEXT: (parameter "x" apiName="x")))
|
||||
// CHECK-NEXT: (enum_element_decl range=[{{.+}}] "bar"))
|
||||
// CHECK-NEXT: (enum_element_decl range=[{{.+}}] "foo(x:)"
|
||||
// CHECK-NEXT: (parameter "x" decl_context=0x{{[0-9a-z]+}} apiName="x")))
|
||||
// CHECK-NEXT: (enum_element_decl decl_context=0x{{[0-9a-z]+}} range=[{{.+}}] "bar"))
|
||||
// CHECK-NEXT: (enum_element_decl decl_context=0x{{[0-9a-z]+}} range=[{{.+}}] "foo(x:)"
|
||||
// CHECK-NEXT: (parameter_list range=[{{.+}}]
|
||||
// CHECK-NEXT: (parameter "x" apiName="x")))
|
||||
// CHECK-NEXT: (enum_element_decl range=[{{.+}}] "bar"))
|
||||
// CHECK-NEXT: (parameter "x" decl_context=0x{{[0-9a-z]+}} apiName="x")))
|
||||
// CHECK-NEXT: (enum_element_decl decl_context=0x{{[0-9a-z]+}} range=[{{.+}}] "bar"))
|
||||
case foo(x: MyStruct), bar
|
||||
}
|
||||
|
||||
// CHECK-LABEL: (top_level_code_decl range=[{{.+}}]
|
||||
// CHECK-LABEL: (top_level_code_decl decl_context=0x{{[0-9a-z]+}} range=[{{.+}}]
|
||||
// CHECK-NEXT: (brace_stmt implicit range=[{{.+}}]
|
||||
// CHECK-NEXT: (sequence_expr type="<null>"
|
||||
// CHECK-NEXT: (discard_assignment_expr type="<null>")
|
||||
@@ -103,15 +103,15 @@ enum MyEnum {
|
||||
// CHECK-NEXT: (<null expr>))
|
||||
// CHECK-NEXT: (closure_expr type="<null>" discriminator={{[0-9]+}}
|
||||
// CHECK-NEXT: (parameter_list range=[{{.+}}]
|
||||
// CHECK-NEXT: (parameter "v"))
|
||||
// CHECK-NEXT: (parameter "v" decl_context=0x{{[0-9a-z]+}}))
|
||||
// CHECK-NEXT: (brace_stmt range=[{{.+}}])))))
|
||||
_ = { (v: MyEnum) in }
|
||||
|
||||
// CHECK-LABEL: (struct_decl range=[{{.+}}] "SelfParam"
|
||||
// CHECK-LABEL: (struct_decl decl_context=0x{{[0-9a-z]+}} range=[{{.+}}] "SelfParam"
|
||||
struct SelfParam {
|
||||
|
||||
// CHECK-LABEL: (func_decl range=[{{.+}}] "createOptional()" static
|
||||
// CHECK-NEXT: (parameter "self")
|
||||
// CHECK-LABEL: (func_decl decl_context=0x{{[0-9a-z]+}} range=[{{.+}}] "createOptional()" static
|
||||
// CHECK-NEXT: (parameter "self" decl_context=0x{{[0-9a-z]+}})
|
||||
// CHECK-NEXT: (result=type_optional
|
||||
// CHECK-NEXT: (type_unqualified_ident id="SelfParam" unbound))
|
||||
// CHECK-NEXT: (parameter_list range=[{{.+}}])
|
||||
@@ -124,7 +124,7 @@ struct SelfParam {
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK-LABEL: (func_decl range=[{{.+}}] "dumpMemberTypeRepr()"
|
||||
// CHECK-LABEL: (func_decl decl_context=0x{{[0-9a-z]+}} range=[{{.+}}] "dumpMemberTypeRepr()"
|
||||
// CHECK-NEXT: (result=type_qualified_ident id="Element" unbound
|
||||
// CHECK-NEXT: (type_unqualified_ident id="Array" unbound
|
||||
// CHECK-NEXT: (type_unqualified_ident id="Bool" unbound))
|
||||
|
||||
@@ -22,32 +22,32 @@ func test(value: A) {
|
||||
switch value {
|
||||
// CHECK: (case_stmt
|
||||
// CHECK: (case_label_item ownership=borrowing
|
||||
// CHECK: (pattern_expr type="A" ownership=borrowing
|
||||
// CHECK: (pattern_expr type="A" {{.*}} ownership=borrowing
|
||||
case B():
|
||||
break
|
||||
// CHECK: (case_stmt
|
||||
// CHECK: (case_label_item ownership=borrowing
|
||||
// CHECK: (pattern_expr type="A" ownership=borrowing
|
||||
// CHECK: (pattern_expr type="A" {{.*}} ownership=borrowing
|
||||
case C():
|
||||
break
|
||||
// CHECK: (case_stmt
|
||||
// CHECK: (case_label_item ownership=borrowing
|
||||
// CHECK: (pattern_expr type="A" ownership=consuming
|
||||
// CHECK: (pattern_expr type="A" {{.*}} ownership=consuming
|
||||
case D():
|
||||
break
|
||||
// CHECK: (case_stmt
|
||||
// CHECK: (case_label_item ownership=borrowing
|
||||
// CHECK: (pattern_expr type="A" ownership=borrowing
|
||||
// CHECK: (pattern_expr type="A" {{.*}} ownership=borrowing
|
||||
case E():
|
||||
break
|
||||
// CHECK: (case_stmt
|
||||
// CHECK: (case_label_item ownership=borrowing
|
||||
// CHECK: (pattern_expr type="A" ownership=borrowing
|
||||
// CHECK: (pattern_expr type="A" {{.*}} ownership=borrowing
|
||||
case F():
|
||||
break
|
||||
// CHECK: (case_stmt
|
||||
// CHECK: (case_label_item ownership=borrowing
|
||||
// CHECK: (pattern_expr type="A" ownership=consuming
|
||||
// CHECK: (pattern_expr type="A" {{.*}} ownership=consuming
|
||||
case G():
|
||||
break
|
||||
// CHECK: (case_stmt
|
||||
|
||||
@@ -7,8 +7,8 @@ struct MyBase {
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK-AST: (func_decl implicit "$main()" interface_type="(MyBase.Type) -> () throws -> ()" access=internal static
|
||||
// CHECK-AST-NEXT: (parameter "self")
|
||||
// CHECK-AST: (func_decl {{.*}} implicit "$main()" interface_type="(MyBase.Type) -> () throws -> ()" access=internal static
|
||||
// CHECK-AST-NEXT: (parameter "self" {{.*}})
|
||||
// CHECK-AST-NEXT: (parameter_list)
|
||||
// CHECK-AST-NEXT: (brace_stmt implicit
|
||||
// CHECK-AST-NEXT: (return_stmt implicit
|
||||
|
||||
@@ -25,7 +25,8 @@ struct UseWrapper<T: DefaultInit> {
|
||||
@Wrapper
|
||||
var wrapped = T()
|
||||
|
||||
// CHECK: pattern_binding_decl implicit
|
||||
// CHECK: pattern_binding_decl{{.*}} implicit
|
||||
// CHECK-NEXT: pattern_entry
|
||||
// CHECK-NEXT: pattern_typed implicit type="Wrapper<T>"
|
||||
// CHECK-NEXT: pattern_named implicit type="Wrapper<T>" "_wrapped"
|
||||
// CHECK: constructor_ref_call_expr
|
||||
|
||||
33
utils/sanitize-address.py
Executable file
33
utils/sanitize-address.py
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# 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
|
||||
|
||||
"""
|
||||
Replaces hexadecimal addresses (e.g., '0x12f42') with '<addr N>', where N is a
|
||||
sequence number. The same address gets the same replacement.
|
||||
"""
|
||||
|
||||
import re
|
||||
import sys
|
||||
|
||||
pattern = re.compile(r'0x[0-9a-zA-Z]+')
|
||||
|
||||
seen = {}
|
||||
|
||||
|
||||
def replacement(match):
|
||||
addr = match.group()
|
||||
if addr not in seen:
|
||||
seen[addr] = "<addr " + str(len(seen)) + ">"
|
||||
|
||||
return seen[addr]
|
||||
|
||||
|
||||
for line in sys.stdin:
|
||||
print(pattern.sub(replacement, line), end="")
|
||||
Reference in New Issue
Block a user