-
Notifications
You must be signed in to change notification settings - Fork 10.4k
/
Copy pathASTDumper.cpp
6671 lines (5828 loc) · 234 KB
/
ASTDumper.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//===--- ASTDumper.cpp - Swift Language AST Dumper ------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 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
//
//===----------------------------------------------------------------------===//
//
// This file implements dumping for the Swift ASTs.
//
//===----------------------------------------------------------------------===//
#include "swift/AST/ASTDumper.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTPrinter.h"
#include "swift/AST/ASTVisitor.h"
#include "swift/AST/Attr.h"
#include "swift/AST/AutoDiff.h"
#include "swift/AST/AvailabilitySpec.h"
#include "swift/AST/ClangModuleLoader.h"
#include "swift/AST/ForeignAsyncConvention.h"
#include "swift/AST/ForeignErrorConvention.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/PackConformance.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/SourceFile.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/AST/TypeVisitor.h"
#include "swift/AST/USRGeneration.h"
#include "swift/Basic/Assertions.h"
#include "swift/Basic/Defer.h"
#include "swift/Basic/QuotedString.h"
#include "swift/Basic/STLExtras.h"
#include "swift/Basic/SourceLoc.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Basic/StringExtras.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/raw_ostream.h"
#include <optional>
//
// AST DUMPING TIPS
// ================
//
// * Pass values before names (because names are often optional and can be
// omitted or empty).
//
// * Put all `printField*()` and `printFlag*()` calls before `printRec()` calls.
// `printRec()` variants print a child node, and all fields of the current
// node need to be printed before any child node is printed.
//
// * `printField()` expects a "simple" argument that will be converted to a
// keyword string by passing it through `getDumpString()`. For values that are
// at all complicated, use `printFieldQuoted()`, which will automatically
// quote and escape the value.
//
// * Confine all direct formatting for the console (e.g. printing quotes or
// parentheses) in `PrintBase`. Eventually we want to allow e.g. JSON dumping;
// limiting the amount of direct I/O helps us with that.
//
using namespace swift;
struct TerminalColor {
llvm::raw_ostream::Colors Color;
bool Bold;
};
#define DEF_COLOR(NAME, COLOR, BOLD) \
static const TerminalColor NAME##Color = { llvm::raw_ostream::COLOR, BOLD };
DEF_COLOR(Func, YELLOW, false)
DEF_COLOR(Range, YELLOW, false)
DEF_COLOR(AccessLevel, YELLOW, false)
DEF_COLOR(ASTNode, YELLOW, true)
DEF_COLOR(Parameter, YELLOW, false)
DEF_COLOR(Extension, MAGENTA, false)
DEF_COLOR(Pattern, RED, true)
DEF_COLOR(Override, RED, false)
DEF_COLOR(Stmt, RED, true)
DEF_COLOR(Captures, RED, false)
DEF_COLOR(Arguments, RED, false)
DEF_COLOR(TypeRepr, GREEN, false)
DEF_COLOR(LiteralValue, GREEN, false)
DEF_COLOR(Decl, GREEN, true)
DEF_COLOR(Parenthesis, BLUE, false)
DEF_COLOR(Type, BLUE, false)
DEF_COLOR(Discriminator, BLUE, false)
DEF_COLOR(InterfaceType, GREEN, false)
DEF_COLOR(Identifier, GREEN, false)
DEF_COLOR(Expr, MAGENTA, true)
DEF_COLOR(ExprModifier, CYAN, false)
DEF_COLOR(DeclModifier, CYAN, false)
DEF_COLOR(ArgModifier, CYAN, false)
DEF_COLOR(ClosureModifier, CYAN, false)
DEF_COLOR(DeclAttribute, CYAN, false)
DEF_COLOR(FieldLabel, CYAN, false)
DEF_COLOR(Location, CYAN, false)
#undef DEF_COLOR
namespace {
/// RAII object that prints with the given color, if color is supported on the
/// given stream.
class PrintWithColorRAII {
raw_ostream &OS;
bool ShowColors;
public:
PrintWithColorRAII(raw_ostream &os, TerminalColor color)
: OS(os), ShowColors(false)
{
ShowColors = os.has_colors();
if (ShowColors)
OS.changeColor(color.Color, color.Bold);
}
~PrintWithColorRAII() {
if (ShowColors) {
OS.resetColor();
}
}
raw_ostream &getOS() const { return OS; }
template<typename T>
friend raw_ostream &operator<<(PrintWithColorRAII &&printer,
const T &value){
printer.OS << value;
return printer.OS;
}
};
/// Wraps a \c raw_ostream so that anything printed through it is automatically
/// escaped appropriately for a double-quoted string.
class escaping_ostream : public raw_ostream {
raw_ostream &base_os;
public:
escaping_ostream(raw_ostream &base_os)
: raw_ostream(/*unbuffered=*/true), base_os(base_os)
{}
virtual ~escaping_ostream() {}
virtual void reserveExtraSpace(uint64_t ExtraSize) override {
base_os.reserveExtraSpace(ExtraSize);
}
virtual raw_ostream &changeColor(enum Colors Color, bool Bold = false,
bool BG = false) override {
return base_os.changeColor(Color, Bold, BG);
}
virtual raw_ostream &resetColor() override {
return base_os.resetColor();
}
virtual raw_ostream &reverseColor() override {
return base_os.reverseColor();
}
virtual bool is_displayed() const override {
return base_os.is_displayed();
}
virtual bool has_colors() const override {
return base_os.has_colors();
}
virtual void enable_colors(bool enable) override {
base_os.enable_colors(enable);
}
private:
virtual void write_impl(const char *Ptr, size_t Size) override {
writeEscaped(StringRef(Ptr, Size), base_os);
}
virtual uint64_t current_pos() const override {
return base_os.tell();
}
virtual void anchor() override {}
};
/// Returns the USR of the given declaration. Gracefully returns an empty
/// string if D is null or invalid.
std::string declUSR(const Decl *D) {
if (!D)
return "";
// Certain local synthesized declarations won't be assigned a local
// discriminator, later causing an assertion if we try to generate a USR
// for them. Avoid these.
// FIXME: USR generation should probably do a better job of avoiding the
// asserting code path?
if (auto VD = dyn_cast<ValueDecl>(D);
VD && VD->getDeclContext()->isLocalContext() &&
(!VD->getLoc().isValid() ||
(VD->getModuleContext()
->getSourceFileContainingLocation(VD->getLoc())
->getFulfilledMacroRole() == std::nullopt))) {
return "";
}
std::string usr;
llvm::raw_string_ostream os(usr);
if (swift::ide::printDeclUSR(D, os))
return "";
return usr;
}
/// Returns the USR of the given type. Gracefully returns an empty string
/// if the type is invalid.
std::string typeUSR(Type type) {
if (!type)
return "";
if (type->hasArchetype()) {
// We can't generate USRs for types that contain archetypes. Replace them
// with their interface types.
type = type.transformRec([&](TypeBase *t) -> std::optional<Type> {
if (auto AT = dyn_cast<ArchetypeType>(t)) {
return AT->getInterfaceType();
}
return std::nullopt;
});
}
std::string usr;
llvm::raw_string_ostream os(usr);
if (swift::ide::printTypeUSR(type, os))
return "";
return usr;
}
/// Returns the USR of the given value declaration's type. Gracefully returns
/// the empty string if D is null.
std::string declTypeUSR(const ValueDecl *D) {
if (!D)
return "";
std::string usr;
llvm::raw_string_ostream os(usr);
if (swift::ide::printDeclTypeUSR(D, os))
return "";
return usr;
}
} // end anonymous namespace
static StringRef getDumpString(SILFunctionType::Representation value) {
switch (value) {
case SILFunctionType::Representation::Thick: return "thick";
case SILFunctionType::Representation::Block: return "block";
case SILFunctionType::Representation::CFunctionPointer: return "c";
case SILFunctionType::Representation::CXXMethod:
return "cxx_method";
case SILFunctionType::Representation::Thin: return "thin";
case SILFunctionType::Representation::Method: return "method";
case SILFunctionType::Representation::ObjCMethod: return "objc_method";
case SILFunctionType::Representation::WitnessMethod: return "witness_method";
case SILFunctionType::Representation::Closure: return "closure";
case SILFunctionType::Representation::KeyPathAccessorGetter:
return "keypath_accessor_getter";
case SILFunctionType::Representation::KeyPathAccessorSetter:
return "keypath_accessor_setter";
case SILFunctionType::Representation::KeyPathAccessorEquals:
return "keypath_accessor_equals";
case SILFunctionType::Representation::KeyPathAccessorHash:
return "keypath_accessor_hash";
}
llvm_unreachable("Unhandled SILFunctionTypeRepresentation in switch.");
}
static StringRef getDumpString(ReadImplKind kind) {
switch (kind) {
case ReadImplKind::Stored:
return "stored";
case ReadImplKind::Inherited:
return "inherited";
case ReadImplKind::Get:
return "getter";
case ReadImplKind::Address:
return "addressor";
case ReadImplKind::Read:
return "read_coroutine";
case ReadImplKind::Read2:
return "read2_coroutine";
}
llvm_unreachable("bad kind");
}
static StringRef getDumpString(WriteImplKind kind) {
switch (kind) {
case WriteImplKind::Immutable:
return "immutable";
case WriteImplKind::Stored:
return "stored";
case WriteImplKind::StoredWithObservers:
return "stored_with_observers";
case WriteImplKind::InheritedWithObservers:
return "inherited_with_observers";
case WriteImplKind::Set:
return "setter";
case WriteImplKind::MutableAddress:
return "mutable_addressor";
case WriteImplKind::Modify:
return "modify_coroutine";
case WriteImplKind::Modify2:
return "modify2_coroutine";
}
llvm_unreachable("bad kind");
}
static StringRef getDumpString(ReadWriteImplKind kind) {
switch (kind) {
case ReadWriteImplKind::Immutable:
return "immutable";
case ReadWriteImplKind::Stored:
return "stored";
case ReadWriteImplKind::MutableAddress:
return "mutable_addressor";
case ReadWriteImplKind::MaterializeToTemporary:
return "materialize_to_temporary";
case ReadWriteImplKind::Modify:
return "modify_coroutine";
case ReadWriteImplKind::Modify2:
return "modify2_coroutine";
case ReadWriteImplKind::StoredWithDidSet:
return "stored_with_didset";
case ReadWriteImplKind::InheritedWithDidSet:
return "inherited_with_didset";
}
llvm_unreachable("bad kind");
}
static StringRef getDumpString(ImportKind value) {
switch (value) {
case ImportKind::Module: return "module";
case ImportKind::Type: return "type";
case ImportKind::Struct: return "struct";
case ImportKind::Class: return "class";
case ImportKind::Enum: return "enum";
case ImportKind::Protocol: return "protocol";
case ImportKind::Var: return "var";
case ImportKind::Func: return "func";
}
llvm_unreachable("Unhandled ImportKind in switch.");
}
static StringRef getDumpString(ForeignErrorConvention::Kind value) {
switch (value) {
case ForeignErrorConvention::ZeroResult: return "ZeroResult";
case ForeignErrorConvention::NonZeroResult: return "NonZeroResult";
case ForeignErrorConvention::ZeroPreservedResult: return "ZeroPreservedResult";
case ForeignErrorConvention::NilResult: return "NilResult";
case ForeignErrorConvention::NonNilError: return "NonNilError";
}
llvm_unreachable("Unhandled ForeignErrorConvention in switch.");
}
static StringRef getDumpString(DefaultArgumentKind value) {
switch (value) {
case DefaultArgumentKind::None: return "none";
#define MAGIC_IDENTIFIER(NAME, STRING) \
case DefaultArgumentKind::NAME: return STRING;
#include "swift/AST/MagicIdentifierKinds.def"
case DefaultArgumentKind::Inherited: return "inherited";
case DefaultArgumentKind::NilLiteral: return "nil";
case DefaultArgumentKind::EmptyArray: return "[]";
case DefaultArgumentKind::EmptyDictionary: return "[:]";
case DefaultArgumentKind::Normal: return "normal";
case DefaultArgumentKind::StoredProperty: return "stored property";
case DefaultArgumentKind::ExpressionMacro:
return "expression macro";
}
llvm_unreachable("Unhandled DefaultArgumentKind in switch.");
}
static StringRef getDumpString(ObjCSelectorExpr::ObjCSelectorKind value) {
switch (value) {
case ObjCSelectorExpr::Method: return "method";
case ObjCSelectorExpr::Getter: return "getter";
case ObjCSelectorExpr::Setter: return "setter";
}
llvm_unreachable("Unhandled ObjCSelectorExpr in switch.");
}
static StringRef getDumpString(AccessSemantics value) {
switch (value) {
case AccessSemantics::Ordinary: return "ordinary";
case AccessSemantics::DirectToStorage: return "direct_to_storage";
case AccessSemantics::DirectToImplementation: return "direct_to_impl";
case AccessSemantics::DistributedThunk: return "distributed_thunk";
}
llvm_unreachable("Unhandled AccessSemantics in switch.");
}
static StringRef getDumpString(MetatypeRepresentation value) {
switch (value) {
case MetatypeRepresentation::Thin: return "thin";
case MetatypeRepresentation::Thick: return "thick";
case MetatypeRepresentation::ObjC: return "@objc";
}
llvm_unreachable("Unhandled MetatypeRepresentation in switch.");
}
static StringRef getDumpString(StringLiteralExpr::Encoding value) {
switch (value) {
case StringLiteralExpr::UTF8: return "utf8";
case StringLiteralExpr::OneUnicodeScalar: return "unicodeScalar";
}
llvm_unreachable("Unhandled StringLiteral in switch.");
}
static StringRef getDumpString(CtorInitializerKind value) {
switch (value) {
case CtorInitializerKind::Designated: return "designated";
case CtorInitializerKind::Convenience: return "convenience";
case CtorInitializerKind::ConvenienceFactory: return "convenience_factory";
case CtorInitializerKind::Factory: return "factory";
}
llvm_unreachable("Unhandled CtorInitializerKind in switch.");
}
static StringRef getDumpString(Associativity value) {
switch (value) {
case Associativity::None: return "none";
case Associativity::Left: return "left";
case Associativity::Right: return "right";
}
llvm_unreachable("Unhandled Associativity in switch.");
}
static StringRef getDumpString(CheckedCastKind kind) {
return getCheckedCastKindName(kind);
}
static StringRef getDumpString(bool value) {
return value ? "true" : "false";
}
static StringRef getDumpString(AccessLevel level) {
return getAccessLevelSpelling(level);
}
static StringRef getDumpString(LifetimeAnnotation lifetime) {
switch (lifetime) {
case LifetimeAnnotation::EagerMove:
return "_eagerMove";
case LifetimeAnnotation::Lexical:
return "_lexical";
case LifetimeAnnotation::None:
return "";
}
llvm_unreachable("Unhandled LifetimeAnnotation in switch.");
}
static StringRef getDumpString(AccessorKind kind) {
return getAccessorKindString(kind);
}
static StringRef getDumpString(MagicIdentifierLiteralExpr::Kind kind) {
return MagicIdentifierLiteralExpr::getKindString(kind);
}
static StringRef getDumpString(ObjectLiteralExpr::LiteralKind kind) {
return ObjectLiteralExpr::getLiteralKindPlainName(kind);
}
static StringRef getDumpString(ParamSpecifier specifier) {
return ParamDecl::getSpecifierSpelling(specifier);
}
static StringRef getDumpString(ValueOwnership ownership) {
switch (ownership) {
case ValueOwnership::Default:
return "";
case ValueOwnership::Owned:
return "owned";
case ValueOwnership::Shared:
return "shared";
case ValueOwnership::InOut:
return "inout";
}
llvm_unreachable("Unhandled ValueOwnership in switch.");
}
static StringRef getDumpString(PlatformKind kind) {
return platformString(kind);
}
static StringRef getDumpString(ForeignErrorConvention::IsOwned_t owned) {
switch (owned) {
case swift::ForeignErrorConvention::IsNotOwned:
return "unowned";
case swift::ForeignErrorConvention::IsOwned:
return "owned";
}
llvm_unreachable("Unhandled ForeignErrorConvention::IsOwned_t in switch.");
}
static StringRef getDumpString(RequirementKind kind) {
switch (kind) {
case RequirementKind::SameShape: return "same_shape";
case RequirementKind::Conformance: return "conforms_to";
case RequirementKind::Layout: return "has_layout";
case RequirementKind::Superclass: return "subclass_of";
case RequirementKind::SameType: return "same_type";
}
llvm_unreachable("Unhandled RequirementKind in switch.");
}
static StringRef getDumpString(RequirementReprKind kind) {
switch (kind) {
case RequirementReprKind::TypeConstraint: return "type_constraint";
case RequirementReprKind::SameType: return "same_type";
case RequirementReprKind::LayoutConstraint: return "layout_constraint";
}
llvm_unreachable("Unhandled RequirementKind in switch.");
}
static StringRef getDumpString(ClangImporterSynthesizedTypeAttr::Kind kind) {
switch (kind) {
case ClangImporterSynthesizedTypeAttr::Kind::NSErrorWrapper:
return "NSErrorWrapper";
case ClangImporterSynthesizedTypeAttr::Kind::NSErrorWrapperAnon:
return "NSErrorWrapperAnon";
}
llvm_unreachable("unhandled ClangImporterSynthesizedTypeAttr::Kind");
}
static StringRef getDumpString(ExternKind kind) {
switch (kind) {
case ExternKind::C:
return "C";
case ExternKind::Wasm:
return "Wasm";
}
llvm_unreachable("unhandled ExternKind");
}
static StringRef getDumpString(InlineKind kind) {
switch (kind) {
case InlineKind::Always:
return "always";
case InlineKind::Never:
return "never";
}
llvm_unreachable("unhandled InlineKind");
}
static StringRef getDumpString(MacroRole role) {
return getMacroRoleString(role);
}
static StringRef getDumpString(EffectsKind kind) {
switch (kind) {
case EffectsKind::ReadNone:
return "ReadNone";
case EffectsKind::ReadOnly:
return "ReadOnly";
case EffectsKind::ReleaseNone:
return "ReleaseNone";
case EffectsKind::ReadWrite:
return "ReadWrite";
case EffectsKind::Unspecified:
return "Unspecified";
case EffectsKind::Custom:
return "Custom";
}
llvm_unreachable("unhandled EffectsKind");
}
static StringRef getDumpString(ExclusivityAttr::Mode mode) {
switch (mode) {
case ExclusivityAttr::Mode::Checked:
return "checked";
case ExclusivityAttr::Mode::Unchecked:
return "unchecked";
}
llvm_unreachable("unhandled ExclusivityAttr::Mode");
}
static StringRef getDumpString(OptimizationMode mode) {
switch (mode) {
case OptimizationMode::NotSet:
return "<not set>";
case OptimizationMode::NoOptimization:
return "NoOptimization";
case OptimizationMode::ForSpeed:
return "ForSpeed";
case OptimizationMode::ForSize:
return "ForSize";
}
}
static StringRef getDumpString(NonSendableKind kind) {
switch (kind) {
case NonSendableKind::Assumed:
return "Assumed";
case NonSendableKind::Specific:
return "Specific";
}
}
static StringRef getDumpString(FunctionRefInfo::ApplyLevel applyLevel) {
switch (applyLevel) {
case FunctionRefInfo::ApplyLevel::Unapplied:
return "unapplied";
case FunctionRefInfo::ApplyLevel::SingleApply:
return "single_apply";
case FunctionRefInfo::ApplyLevel::DoubleApply:
return "double_apply";
}
}
static StringRef getDumpString(ExecutionKind kind) {
switch (kind) {
case ExecutionKind::Concurrent:
return "concurrent";
case ExecutionKind::Caller:
return "caller";
}
}
static StringRef getDumpString(ExplicitSafety safety) {
switch (safety) {
case ExplicitSafety::Unspecified:
return "unspecified";
case ExplicitSafety::Safe:
return "safe";
case ExplicitSafety::Unsafe:
return "unsafe";
}
}
static StringRef getDumpString(StringRef s) {
return s;
}
static unsigned getDumpString(unsigned value) {
return value;
}
static size_t getDumpString(size_t value) {
return value;
}
static void *getDumpString(void *value) { return value; }
static StringRef getDumpString(Identifier ident) { return ident.str(); }
//===----------------------------------------------------------------------===//
// Decl printing.
//===----------------------------------------------------------------------===//
// Print a name.
static void printName(raw_ostream &os, DeclName name) {
if (!name)
os << "<anonymous>";
else
os << name;
}
static Type defaultGetTypeOfExpr(Expr *E) { return E->getType(); }
static Type defaultGetTypeOfKeyPathComponent(KeyPathExpr *E, unsigned index) {
return E->getComponents()[index].getComponentType();
}
using VisitedConformances = llvm::SmallPtrSetImpl<const ProtocolConformance *>;
namespace {
/// Represents a label attached to some data in the AST being dumped.
///
/// This type exists to balance the simplified S-expression output with
/// the need for additional structure in more complex data formats like
/// JSON. The S-expression output, in most cases, prints nested data as
/// unlabeled children (indented one more step) and allows fields to be
/// printed without explicit names, but this isn't compatible with JSON where
/// each value needs its own unique label/key (or it needs to be an element
/// of an array).
class Label {
StringRef Text;
bool IsOptional;
Label(StringRef text, bool isOptional)
: Text(text), IsOptional(isOptional) {}
public:
/// Returns a new label that is always printed, even in the default
/// (S-expression) output.
static Label always(StringRef text) {
return Label(text, /*isOptional=*/ false);
}
/// Returns a new label that is optional on output formats that allow
/// labels to be omitted.
static Label optional(StringRef text) {
return Label(text, /*isOptional=*/ true);
}
/// Returns true if the label's text is empty.
bool empty() const { return Text.empty(); }
/// Returns true if the label can be omitted by output formats that support
/// optional labels.
bool isOptional() const { return IsOptional; }
/// Returns the label's text.
StringRef text() const { return Text; }
};
/// Defines the interface for low-level printing operations that take place
/// when dumping a Swift AST.
class PrintWriterBase {
protected:
/// Only used by the S-expression writer to change the dumper to use
/// single quotes when printing substitution maps in full.
char Quote = '\"';
/// Tracks the source buffer ID of the main source file, which subclasses
/// can use to distinguish ranges/locations in that file vs. ranges in other
/// buffers, like macro expansions.
unsigned MainBufferID;
public:
virtual ~PrintWriterBase() {}
char quote() const { return Quote; }
void setQuote(char quote) { Quote = quote; }
void setMainBufferID(unsigned bufferID) { MainBufferID = bufferID; }
/// Call `body` in a context where the printer is ready for a child to be
/// printed.
virtual void printRecArbitrary(std::function<void(Label)> body,
Label label) = 0;
/// Print a range of nodes as a single "array" child node.
virtual void printRecRange(std::function<void()> body,
Label label) = 0;
/// Call `body` in a context where the printer is ready for a list of
/// children to be printed.
virtual void printListArbitrary(std::function<void()> body, Label label) = 0;
/// Print the beginning of a new node, including its type and an optional
/// label for it.
virtual void printHead(StringRef name, TerminalColor color, Label label) = 0;
/// Print the end of a new node.
virtual void printFoot() = 0;
/// Print a field with a short keyword-style value, printing the value by
/// passing a closure that takes a \c raw_ostream.
virtual void printFieldRaw(std::function<void(llvm::raw_ostream &)> body,
Label label, TerminalColor color) = 0;
/// Print a field with a long value that will be automatically quoted and
/// escaped, printing the value by passing a closure that takes a
/// \c raw_ostream.
virtual void printFieldQuotedRaw(
std::function<void(llvm::raw_ostream &)> body, Label name,
TerminalColor color) = 0;
/// Print a simple boolean value, printing the value by passing a closure
/// that takes a \c raw_ostream.
virtual void printFlagRaw(std::function<void(llvm::raw_ostream &)> body,
TerminalColor color) = 0;
/// Print a field containing a node's source location.
virtual void printSourceLoc(const SourceLoc L, const ASTContext *Ctx,
Label label) = 0;
/// Print a field containing a node's source range.
virtual void printSourceRange(const SourceRange R, const ASTContext *Ctx,
Label label) = 0;
virtual bool hasNonStandardOutput() const = 0;
/// Indicates whether the output format is meant to be parsable. Parsable
/// output should use structure rather than stringification to convey
/// detailed information, and generally provides more information than the
/// non-parsable formats, which are usually meant for human debugging.
virtual bool isParsable() const = 0;
};
/// Implements the default (pseudo-S-expression) output format for `-dump-ast`.
class DefaultWriter : public PrintWriterBase {
raw_ostream &OS;
unsigned Indent;
public:
DefaultWriter(raw_ostream &os, unsigned indent) : OS(os), Indent(indent) {}
void printRecArbitrary(std::function<void(Label)> body,
Label label) override {
Indent += 2;
OS << '\n';
body(label);
Indent -= 2;
}
void printRecRange(std::function<void()> body,
Label label) override {
printRecArbitrary([&](Label label) {
printHead("array", ASTNodeColor, label);
body();
printFoot();
}, label);
}
void printListArbitrary(std::function<void()> body, Label label) override {
// This writer ignores the label and simply prints the list directly
// underneath its parent.
body();
}
void printHead(StringRef name, TerminalColor color, Label label) override {
OS.indent(Indent);
PrintWithColorRAII(OS, ParenthesisColor) << '(';
if (!label.isOptional() && !label.empty()) {
PrintWithColorRAII(OS, FieldLabelColor) << label.text();
OS << "=";
}
PrintWithColorRAII(OS, color) << name;
}
void printFoot() override {
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}
void printFieldRaw(std::function<void(llvm::raw_ostream &)> body,
Label label, TerminalColor color) override {
OS << " ";
if (!label.isOptional() && !label.empty())
PrintWithColorRAII(OS, color) << label.text() << "=";
std::string value;
llvm::raw_string_ostream SOS(value);
body(SOS);
PrintWithColorRAII(OS, color) << value;
}
void printFieldQuotedRaw(std::function<void(llvm::raw_ostream &)> body,
Label name, TerminalColor color) override {
printFieldRaw([&](raw_ostream &OS) {
OS << Quote;
{ escaping_ostream escOS(OS); body(escOS); }
OS << Quote;
}, name, color);
}
void printFlagRaw(std::function<void(llvm::raw_ostream &)> body,
TerminalColor color) override {
printFieldRaw(body, Label::always(""), color);
}
void printSourceLoc(const SourceLoc L, const ASTContext *Ctx,
Label label) override {
printFieldRaw([&](raw_ostream &OS) {
escaping_ostream escOS(OS);
L.print(escOS, Ctx->SourceMgr);
}, label, LocationColor);
}
void printSourceRange(const SourceRange R, const ASTContext *Ctx,
Label label) override {
printFieldRaw([&](raw_ostream &OS) {
escaping_ostream escOS(OS);
R.print(escOS, Ctx->SourceMgr, /*PrintText=*/false);
}, label, RangeColor);
}
bool hasNonStandardOutput() const override {
return &OS != &llvm::errs() && &OS != &llvm::dbgs();
}
bool isParsable() const override { return false; }
};
/// Implements JSON formatted output for `-ast-dump`.
class JSONWriter : public PrintWriterBase {
llvm::json::OStream OS;
std::vector<bool> InObjectStack;
public:
JSONWriter(raw_ostream &os, unsigned indent = 0) : OS(os, indent) {}
void printRecArbitrary(std::function<void(Label)> body,
Label label) override {
// The label is ignored if we're not printing inside an object (meaning
// we must be in an array).
assert(!InObjectStack.empty() && "printHead or printListArbitrary not called before printRecArbitrary");
if (InObjectStack.back()) {
OS.attributeBegin(label.text());
body(Label::optional(""));
OS.attributeEnd();
} else {
body(Label::optional(""));
}
}
void printRecRange(std::function<void()> body, Label label) override {
printListArbitrary([&]{ body(); }, label);
}
void printListArbitrary(std::function<void()> body, Label label) override {
OS.attributeBegin(label.text());
OS.arrayBegin();
InObjectStack.push_back(false);
body();
InObjectStack.pop_back();
OS.arrayEnd();
OS.attributeEnd();
}
void printHead(StringRef name, TerminalColor color, Label label) override {
OS.objectBegin();
InObjectStack.push_back(true);
OS.attribute(label.empty() ? "_kind" : label.text(), name);
}
void printFoot() override {
InObjectStack.pop_back();
OS.objectEnd();
}
void printFieldRaw(std::function<void(llvm::raw_ostream &)> body,
Label label, TerminalColor color) override {
std::string value;
llvm::raw_string_ostream SOS(value);
body(SOS);
// The label is ignored if we're not printing inside an object (meaning
// we must be in an array).
if (InObjectStack.back()) {
OS.attribute(label.text(), value);
} else {
OS.value(value);
}
}
void printFieldQuotedRaw(std::function<void(llvm::raw_ostream &)> body,
Label label, TerminalColor color) override {
// No need to do special quoting for complex values; the JSON output
// stream will do this for us.
printFieldRaw(body, label, color);
}
void printFlagRaw(std::function<void(llvm::raw_ostream &)> body,
TerminalColor color) override {
std::string flag;
llvm::raw_string_ostream SOS(flag);
body(SOS);
OS.attribute(flag, true);
}
void printSourceLoc(const SourceLoc L, const ASTContext *Ctx,
Label label) override {
// For compactness, we only print source ranges in JSON, since they
// provide a superset of this information.
}
void printSourceRange(const SourceRange R, const ASTContext *Ctx,
Label label) override {
OS.attributeBegin(label.text());
OS.objectBegin();
SourceManager &srcMgr = Ctx->SourceMgr;
unsigned startBufferID = srcMgr.findBufferContainingLoc(R.Start);
unsigned startOffset = srcMgr.getLocOffsetInBuffer(R.Start,
startBufferID);
OS.attribute("start", startOffset);
unsigned endBufferID = srcMgr.findBufferContainingLoc(R.End);
unsigned endOffset = srcMgr.getLocOffsetInBuffer(R.End, endBufferID);
OS.attribute("end", endOffset);
// Only print the buffer ID when it doesn't match the main ID, so that we
// distinguish macro expansions but don't bloat the output with the main
// file name repeated over and over.
if (startBufferID != MainBufferID)
OS.attribute("buffer_id", srcMgr.getIdentifierForBuffer(startBufferID));
OS.objectEnd();
OS.attributeEnd();
}
bool hasNonStandardOutput() const override { return true; }
bool isParsable() const override { return true; }
};
/// PrintBase - Base type for recursive structured dumps of AST nodes.
///
/// Please keep direct I/O, especially of structural elements like
/// parentheses and quote marks, confined to this base class. This will help
/// if we eventually support alternate output formats for AST dumps.
class PrintBase {
protected:
PrintWriterBase &Writer;
public: