[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:
Rintaro Ishizaki
2025-02-11 20:38:28 -08:00
parent 04b2174c52
commit 71b24665fa
18 changed files with 340 additions and 99 deletions

View File

@@ -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.

View File

@@ -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);

View File

@@ -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 {

View File

@@ -42,6 +42,7 @@ add_swift_host_library(swiftAST STATIC
ConformanceLookupTable.cpp
Decl.cpp
DeclContext.cpp
DeclContextDumper.cpp
DeclNameLoc.cpp
DiagnosticBridge.cpp
DiagnosticConsumer.cpp

View File

@@ -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:

View 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 *>> &Map;
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);
}

View File

@@ -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;
}

View File

@@ -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;
}))

View File

@@ -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}}

View File

@@ -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]]
}

View File

@@ -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}}

View File

@@ -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
}

View File

@@ -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"

View File

@@ -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))

View File

@@ -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

View File

@@ -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

View File

@@ -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
View 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="")