llvm-project
2891 строка · 80.5 Кб
1//===--- TextNodeDumper.cpp - Printing of AST nodes -----------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements AST dumping of components of individual AST nodes.
10//
11//===----------------------------------------------------------------------===//
12
13#include "clang/AST/TextNodeDumper.h"
14#include "clang/AST/APValue.h"
15#include "clang/AST/DeclFriend.h"
16#include "clang/AST/DeclOpenMP.h"
17#include "clang/AST/DeclTemplate.h"
18#include "clang/AST/LocInfoType.h"
19#include "clang/AST/NestedNameSpecifier.h"
20#include "clang/AST/Type.h"
21#include "clang/AST/TypeLocVisitor.h"
22#include "clang/Basic/Module.h"
23#include "clang/Basic/SourceManager.h"
24#include "clang/Basic/Specifiers.h"
25#include "clang/Basic/TypeTraits.h"
26#include "llvm/ADT/StringExtras.h"
27
28#include <algorithm>
29#include <utility>
30
31using namespace clang;
32
33static void dumpPreviousDeclImpl(raw_ostream &OS, ...) {}
34
35template <typename T>
36static void dumpPreviousDeclImpl(raw_ostream &OS, const Mergeable<T> *D) {
37const T *First = D->getFirstDecl();
38if (First != D)
39OS << " first " << First;
40}
41
42template <typename T>
43static void dumpPreviousDeclImpl(raw_ostream &OS, const Redeclarable<T> *D) {
44const T *Prev = D->getPreviousDecl();
45if (Prev)
46OS << " prev " << Prev;
47}
48
49/// Dump the previous declaration in the redeclaration chain for a declaration,
50/// if any.
51static void dumpPreviousDecl(raw_ostream &OS, const Decl *D) {
52switch (D->getKind()) {
53#define DECL(DERIVED, BASE) \
54case Decl::DERIVED: \
55return dumpPreviousDeclImpl(OS, cast<DERIVED##Decl>(D));
56#define ABSTRACT_DECL(DECL)
57#include "clang/AST/DeclNodes.inc"
58}
59llvm_unreachable("Decl that isn't part of DeclNodes.inc!");
60}
61
62TextNodeDumper::TextNodeDumper(raw_ostream &OS, const ASTContext &Context,
63bool ShowColors)
64: TextTreeStructure(OS, ShowColors), OS(OS), ShowColors(ShowColors),
65Context(&Context), SM(&Context.getSourceManager()),
66PrintPolicy(Context.getPrintingPolicy()),
67Traits(&Context.getCommentCommandTraits()) {}
68
69TextNodeDumper::TextNodeDumper(raw_ostream &OS, bool ShowColors)
70: TextTreeStructure(OS, ShowColors), OS(OS), ShowColors(ShowColors) {}
71
72void TextNodeDumper::Visit(const comments::Comment *C,
73const comments::FullComment *FC) {
74if (!C) {
75ColorScope Color(OS, ShowColors, NullColor);
76OS << "<<<NULL>>>";
77return;
78}
79
80{
81ColorScope Color(OS, ShowColors, CommentColor);
82OS << C->getCommentKindName();
83}
84dumpPointer(C);
85dumpSourceRange(C->getSourceRange());
86
87ConstCommentVisitor<TextNodeDumper, void,
88const comments::FullComment *>::visit(C, FC);
89}
90
91void TextNodeDumper::Visit(const Attr *A) {
92{
93ColorScope Color(OS, ShowColors, AttrColor);
94
95switch (A->getKind()) {
96#define ATTR(X) \
97case attr::X: \
98OS << #X; \
99break;
100#include "clang/Basic/AttrList.inc"
101}
102OS << "Attr";
103}
104dumpPointer(A);
105dumpSourceRange(A->getRange());
106if (A->isInherited())
107OS << " Inherited";
108if (A->isImplicit())
109OS << " Implicit";
110
111ConstAttrVisitor<TextNodeDumper>::Visit(A);
112}
113
114void TextNodeDumper::Visit(const TemplateArgument &TA, SourceRange R,
115const Decl *From, StringRef Label) {
116OS << "TemplateArgument";
117if (R.isValid())
118dumpSourceRange(R);
119
120if (From)
121dumpDeclRef(From, Label);
122
123ConstTemplateArgumentVisitor<TextNodeDumper>::Visit(TA);
124}
125
126void TextNodeDumper::Visit(const Stmt *Node) {
127if (!Node) {
128ColorScope Color(OS, ShowColors, NullColor);
129OS << "<<<NULL>>>";
130return;
131}
132{
133ColorScope Color(OS, ShowColors, StmtColor);
134OS << Node->getStmtClassName();
135}
136dumpPointer(Node);
137dumpSourceRange(Node->getSourceRange());
138
139if (const auto *E = dyn_cast<Expr>(Node)) {
140dumpType(E->getType());
141
142if (E->containsErrors()) {
143ColorScope Color(OS, ShowColors, ErrorsColor);
144OS << " contains-errors";
145}
146
147{
148ColorScope Color(OS, ShowColors, ValueKindColor);
149switch (E->getValueKind()) {
150case VK_PRValue:
151break;
152case VK_LValue:
153OS << " lvalue";
154break;
155case VK_XValue:
156OS << " xvalue";
157break;
158}
159}
160
161{
162ColorScope Color(OS, ShowColors, ObjectKindColor);
163switch (E->getObjectKind()) {
164case OK_Ordinary:
165break;
166case OK_BitField:
167OS << " bitfield";
168break;
169case OK_ObjCProperty:
170OS << " objcproperty";
171break;
172case OK_ObjCSubscript:
173OS << " objcsubscript";
174break;
175case OK_VectorComponent:
176OS << " vectorcomponent";
177break;
178case OK_MatrixComponent:
179OS << " matrixcomponent";
180break;
181}
182}
183}
184
185ConstStmtVisitor<TextNodeDumper>::Visit(Node);
186}
187
188void TextNodeDumper::Visit(const Type *T) {
189if (!T) {
190ColorScope Color(OS, ShowColors, NullColor);
191OS << "<<<NULL>>>";
192return;
193}
194if (isa<LocInfoType>(T)) {
195{
196ColorScope Color(OS, ShowColors, TypeColor);
197OS << "LocInfo Type";
198}
199dumpPointer(T);
200return;
201}
202
203{
204ColorScope Color(OS, ShowColors, TypeColor);
205OS << T->getTypeClassName() << "Type";
206}
207dumpPointer(T);
208OS << " ";
209dumpBareType(QualType(T, 0), false);
210
211QualType SingleStepDesugar =
212T->getLocallyUnqualifiedSingleStepDesugaredType();
213if (SingleStepDesugar != QualType(T, 0))
214OS << " sugar";
215
216if (T->containsErrors()) {
217ColorScope Color(OS, ShowColors, ErrorsColor);
218OS << " contains-errors";
219}
220
221if (T->isDependentType())
222OS << " dependent";
223else if (T->isInstantiationDependentType())
224OS << " instantiation_dependent";
225
226if (T->isVariablyModifiedType())
227OS << " variably_modified";
228if (T->containsUnexpandedParameterPack())
229OS << " contains_unexpanded_pack";
230if (T->isFromAST())
231OS << " imported";
232
233TypeVisitor<TextNodeDumper>::Visit(T);
234}
235
236void TextNodeDumper::Visit(QualType T) {
237OS << "QualType";
238dumpPointer(T.getAsOpaquePtr());
239OS << " ";
240dumpBareType(T, false);
241OS << " " << T.split().Quals.getAsString();
242}
243
244void TextNodeDumper::Visit(TypeLoc TL) {
245if (!TL) {
246ColorScope Color(OS, ShowColors, NullColor);
247OS << "<<<NULL>>>";
248return;
249}
250
251{
252ColorScope Color(OS, ShowColors, TypeColor);
253OS << (TL.getTypeLocClass() == TypeLoc::Qualified
254? "Qualified"
255: TL.getType()->getTypeClassName())
256<< "TypeLoc";
257}
258dumpSourceRange(TL.getSourceRange());
259OS << ' ';
260dumpBareType(TL.getType(), /*Desugar=*/false);
261
262TypeLocVisitor<TextNodeDumper>::Visit(TL);
263}
264
265void TextNodeDumper::Visit(const Decl *D) {
266if (!D) {
267ColorScope Color(OS, ShowColors, NullColor);
268OS << "<<<NULL>>>";
269return;
270}
271
272{
273ColorScope Color(OS, ShowColors, DeclKindNameColor);
274OS << D->getDeclKindName() << "Decl";
275}
276dumpPointer(D);
277if (D->getLexicalDeclContext() != D->getDeclContext())
278OS << " parent " << cast<Decl>(D->getDeclContext());
279dumpPreviousDecl(OS, D);
280dumpSourceRange(D->getSourceRange());
281OS << ' ';
282dumpLocation(D->getLocation());
283if (D->isFromASTFile())
284OS << " imported";
285if (Module *M = D->getOwningModule())
286OS << " in " << M->getFullModuleName();
287if (auto *ND = dyn_cast<NamedDecl>(D))
288for (Module *M : D->getASTContext().getModulesWithMergedDefinition(
289const_cast<NamedDecl *>(ND)))
290AddChild([=] { OS << "also in " << M->getFullModuleName(); });
291if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
292if (!ND->isUnconditionallyVisible())
293OS << " hidden";
294if (D->isImplicit())
295OS << " implicit";
296
297if (D->isUsed())
298OS << " used";
299else if (D->isThisDeclarationReferenced())
300OS << " referenced";
301
302if (D->isInvalidDecl())
303OS << " invalid";
304if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
305if (FD->isConstexprSpecified())
306OS << " constexpr";
307if (FD->isConsteval())
308OS << " consteval";
309else if (FD->isImmediateFunction())
310OS << " immediate";
311if (FD->isMultiVersion())
312OS << " multiversion";
313}
314
315if (!isa<FunctionDecl>(*D)) {
316const auto *MD = dyn_cast<ObjCMethodDecl>(D);
317if (!MD || !MD->isThisDeclarationADefinition()) {
318const auto *DC = dyn_cast<DeclContext>(D);
319if (DC && DC->hasExternalLexicalStorage()) {
320ColorScope Color(OS, ShowColors, UndeserializedColor);
321OS << " <undeserialized declarations>";
322}
323}
324}
325
326switch (D->getFriendObjectKind()) {
327case Decl::FOK_None:
328break;
329case Decl::FOK_Declared:
330OS << " friend";
331break;
332case Decl::FOK_Undeclared:
333OS << " friend_undeclared";
334break;
335}
336
337ConstDeclVisitor<TextNodeDumper>::Visit(D);
338}
339
340void TextNodeDumper::Visit(const CXXCtorInitializer *Init) {
341OS << "CXXCtorInitializer";
342if (Init->isAnyMemberInitializer()) {
343OS << ' ';
344dumpBareDeclRef(Init->getAnyMember());
345} else if (Init->isBaseInitializer()) {
346dumpType(QualType(Init->getBaseClass(), 0));
347} else if (Init->isDelegatingInitializer()) {
348dumpType(Init->getTypeSourceInfo()->getType());
349} else {
350llvm_unreachable("Unknown initializer type");
351}
352}
353
354void TextNodeDumper::Visit(const BlockDecl::Capture &C) {
355OS << "capture";
356if (C.isByRef())
357OS << " byref";
358if (C.isNested())
359OS << " nested";
360if (C.getVariable()) {
361OS << ' ';
362dumpBareDeclRef(C.getVariable());
363}
364}
365
366void TextNodeDumper::Visit(const OMPClause *C) {
367if (!C) {
368ColorScope Color(OS, ShowColors, NullColor);
369OS << "<<<NULL>>> OMPClause";
370return;
371}
372{
373ColorScope Color(OS, ShowColors, AttrColor);
374StringRef ClauseName(llvm::omp::getOpenMPClauseName(C->getClauseKind()));
375OS << "OMP" << ClauseName.substr(/*Start=*/0, /*N=*/1).upper()
376<< ClauseName.drop_front() << "Clause";
377}
378dumpPointer(C);
379dumpSourceRange(SourceRange(C->getBeginLoc(), C->getEndLoc()));
380if (C->isImplicit())
381OS << " <implicit>";
382}
383
384void TextNodeDumper::Visit(const OpenACCClause *C) {
385if (!C) {
386ColorScope Color(OS, ShowColors, NullColor);
387OS << "<<<NULL>>> OpenACCClause";
388return;
389}
390{
391ColorScope Color(OS, ShowColors, AttrColor);
392OS << C->getClauseKind();
393
394// Handle clauses with parens for types that have no children, likely
395// because there is no sub expression.
396switch (C->getClauseKind()) {
397case OpenACCClauseKind::Default:
398OS << '(' << cast<OpenACCDefaultClause>(C)->getDefaultClauseKind() << ')';
399break;
400case OpenACCClauseKind::Async:
401case OpenACCClauseKind::Auto:
402case OpenACCClauseKind::Attach:
403case OpenACCClauseKind::Copy:
404case OpenACCClauseKind::PCopy:
405case OpenACCClauseKind::PresentOrCopy:
406case OpenACCClauseKind::If:
407case OpenACCClauseKind::Independent:
408case OpenACCClauseKind::DevicePtr:
409case OpenACCClauseKind::FirstPrivate:
410case OpenACCClauseKind::NoCreate:
411case OpenACCClauseKind::NumGangs:
412case OpenACCClauseKind::NumWorkers:
413case OpenACCClauseKind::Present:
414case OpenACCClauseKind::Private:
415case OpenACCClauseKind::Self:
416case OpenACCClauseKind::Seq:
417case OpenACCClauseKind::VectorLength:
418// The condition expression will be printed as a part of the 'children',
419// but print 'clause' here so it is clear what is happening from the dump.
420OS << " clause";
421break;
422case OpenACCClauseKind::CopyIn:
423case OpenACCClauseKind::PCopyIn:
424case OpenACCClauseKind::PresentOrCopyIn:
425OS << " clause";
426if (cast<OpenACCCopyInClause>(C)->isReadOnly())
427OS << " : readonly";
428break;
429case OpenACCClauseKind::CopyOut:
430case OpenACCClauseKind::PCopyOut:
431case OpenACCClauseKind::PresentOrCopyOut:
432OS << " clause";
433if (cast<OpenACCCopyOutClause>(C)->isZero())
434OS << " : zero";
435break;
436case OpenACCClauseKind::Create:
437case OpenACCClauseKind::PCreate:
438case OpenACCClauseKind::PresentOrCreate:
439OS << " clause";
440if (cast<OpenACCCreateClause>(C)->isZero())
441OS << " : zero";
442break;
443case OpenACCClauseKind::Wait:
444OS << " clause";
445if (cast<OpenACCWaitClause>(C)->hasDevNumExpr())
446OS << " has devnum";
447if (cast<OpenACCWaitClause>(C)->hasQueuesTag())
448OS << " has queues tag";
449break;
450case OpenACCClauseKind::DeviceType:
451case OpenACCClauseKind::DType:
452OS << "(";
453llvm::interleaveComma(
454cast<OpenACCDeviceTypeClause>(C)->getArchitectures(), OS,
455[&](const DeviceTypeArgument &Arch) {
456if (Arch.first == nullptr)
457OS << "*";
458else
459OS << Arch.first->getName();
460});
461OS << ")";
462break;
463case OpenACCClauseKind::Reduction:
464OS << " clause Operator: "
465<< cast<OpenACCReductionClause>(C)->getReductionOp();
466break;
467default:
468// Nothing to do here.
469break;
470}
471}
472dumpPointer(C);
473dumpSourceRange(SourceRange(C->getBeginLoc(), C->getEndLoc()));
474}
475
476void TextNodeDumper::Visit(const GenericSelectionExpr::ConstAssociation &A) {
477const TypeSourceInfo *TSI = A.getTypeSourceInfo();
478if (TSI) {
479OS << "case ";
480dumpType(TSI->getType());
481} else {
482OS << "default";
483}
484
485if (A.isSelected())
486OS << " selected";
487}
488
489void TextNodeDumper::Visit(const ConceptReference *R) {
490if (!R) {
491ColorScope Color(OS, ShowColors, NullColor);
492OS << "<<<NULL>>> ConceptReference";
493return;
494}
495
496OS << "ConceptReference";
497dumpPointer(R);
498dumpSourceRange(R->getSourceRange());
499OS << ' ';
500dumpBareDeclRef(R->getNamedConcept());
501}
502
503void TextNodeDumper::Visit(const concepts::Requirement *R) {
504if (!R) {
505ColorScope Color(OS, ShowColors, NullColor);
506OS << "<<<NULL>>> Requirement";
507return;
508}
509
510{
511ColorScope Color(OS, ShowColors, StmtColor);
512switch (R->getKind()) {
513case concepts::Requirement::RK_Type:
514OS << "TypeRequirement";
515break;
516case concepts::Requirement::RK_Simple:
517OS << "SimpleRequirement";
518break;
519case concepts::Requirement::RK_Compound:
520OS << "CompoundRequirement";
521break;
522case concepts::Requirement::RK_Nested:
523OS << "NestedRequirement";
524break;
525}
526}
527
528dumpPointer(R);
529
530if (auto *ER = dyn_cast<concepts::ExprRequirement>(R)) {
531if (ER->hasNoexceptRequirement())
532OS << " noexcept";
533}
534
535if (R->isDependent())
536OS << " dependent";
537else
538OS << (R->isSatisfied() ? " satisfied" : " unsatisfied");
539if (R->containsUnexpandedParameterPack())
540OS << " contains_unexpanded_pack";
541}
542
543static double GetApproxValue(const llvm::APFloat &F) {
544llvm::APFloat V = F;
545bool ignored;
546V.convert(llvm::APFloat::IEEEdouble(), llvm::APFloat::rmNearestTiesToEven,
547&ignored);
548return V.convertToDouble();
549}
550
551/// True if the \p APValue \p Value can be folded onto the current line.
552static bool isSimpleAPValue(const APValue &Value) {
553switch (Value.getKind()) {
554case APValue::None:
555case APValue::Indeterminate:
556case APValue::Int:
557case APValue::Float:
558case APValue::FixedPoint:
559case APValue::ComplexInt:
560case APValue::ComplexFloat:
561case APValue::LValue:
562case APValue::MemberPointer:
563case APValue::AddrLabelDiff:
564return true;
565case APValue::Vector:
566case APValue::Array:
567case APValue::Struct:
568return false;
569case APValue::Union:
570return isSimpleAPValue(Value.getUnionValue());
571}
572llvm_unreachable("unexpected APValue kind!");
573}
574
575/// Dump the children of the \p APValue \p Value.
576///
577/// \param[in] Value The \p APValue to visit
578/// \param[in] Ty The \p QualType passed to \p Visit
579///
580/// \param[in] IdxToChildFun A function mapping an \p APValue and an index
581/// to one of the child of the \p APValue
582///
583/// \param[in] NumChildren \p IdxToChildFun will be called on \p Value with
584/// the indices in the range \p [0,NumChildren(
585///
586/// \param[in] LabelSingular The label to use on a line with a single child
587/// \param[in] LabelPlurial The label to use on a line with multiple children
588void TextNodeDumper::dumpAPValueChildren(
589const APValue &Value, QualType Ty,
590const APValue &(*IdxToChildFun)(const APValue &, unsigned),
591unsigned NumChildren, StringRef LabelSingular, StringRef LabelPlurial) {
592// To save some vertical space we print up to MaxChildrenPerLine APValues
593// considered to be simple (by isSimpleAPValue) on a single line.
594constexpr unsigned MaxChildrenPerLine = 4;
595unsigned I = 0;
596while (I < NumChildren) {
597unsigned J = I;
598while (J < NumChildren) {
599if (isSimpleAPValue(IdxToChildFun(Value, J)) &&
600(J - I < MaxChildrenPerLine)) {
601++J;
602continue;
603}
604break;
605}
606
607J = std::max(I + 1, J);
608
609// Print [I,J) on a single line.
610AddChild(J - I > 1 ? LabelPlurial : LabelSingular, [=]() {
611for (unsigned X = I; X < J; ++X) {
612Visit(IdxToChildFun(Value, X), Ty);
613if (X + 1 != J)
614OS << ", ";
615}
616});
617I = J;
618}
619}
620
621void TextNodeDumper::Visit(const APValue &Value, QualType Ty) {
622ColorScope Color(OS, ShowColors, ValueKindColor);
623switch (Value.getKind()) {
624case APValue::None:
625OS << "None";
626return;
627case APValue::Indeterminate:
628OS << "Indeterminate";
629return;
630case APValue::Int:
631OS << "Int ";
632{
633ColorScope Color(OS, ShowColors, ValueColor);
634OS << Value.getInt();
635}
636return;
637case APValue::Float:
638OS << "Float ";
639{
640ColorScope Color(OS, ShowColors, ValueColor);
641OS << GetApproxValue(Value.getFloat());
642}
643return;
644case APValue::FixedPoint:
645OS << "FixedPoint ";
646{
647ColorScope Color(OS, ShowColors, ValueColor);
648OS << Value.getFixedPoint();
649}
650return;
651case APValue::Vector: {
652unsigned VectorLength = Value.getVectorLength();
653OS << "Vector length=" << VectorLength;
654
655dumpAPValueChildren(
656Value, Ty,
657[](const APValue &Value, unsigned Index) -> const APValue & {
658return Value.getVectorElt(Index);
659},
660VectorLength, "element", "elements");
661return;
662}
663case APValue::ComplexInt:
664OS << "ComplexInt ";
665{
666ColorScope Color(OS, ShowColors, ValueColor);
667OS << Value.getComplexIntReal() << " + " << Value.getComplexIntImag()
668<< 'i';
669}
670return;
671case APValue::ComplexFloat:
672OS << "ComplexFloat ";
673{
674ColorScope Color(OS, ShowColors, ValueColor);
675OS << GetApproxValue(Value.getComplexFloatReal()) << " + "
676<< GetApproxValue(Value.getComplexFloatImag()) << 'i';
677}
678return;
679case APValue::LValue:
680(void)Context;
681OS << "LValue <todo>";
682return;
683case APValue::Array: {
684unsigned ArraySize = Value.getArraySize();
685unsigned NumInitializedElements = Value.getArrayInitializedElts();
686OS << "Array size=" << ArraySize;
687
688dumpAPValueChildren(
689Value, Ty,
690[](const APValue &Value, unsigned Index) -> const APValue & {
691return Value.getArrayInitializedElt(Index);
692},
693NumInitializedElements, "element", "elements");
694
695if (Value.hasArrayFiller()) {
696AddChild("filler", [=] {
697{
698ColorScope Color(OS, ShowColors, ValueColor);
699OS << ArraySize - NumInitializedElements << " x ";
700}
701Visit(Value.getArrayFiller(), Ty);
702});
703}
704
705return;
706}
707case APValue::Struct: {
708OS << "Struct";
709
710dumpAPValueChildren(
711Value, Ty,
712[](const APValue &Value, unsigned Index) -> const APValue & {
713return Value.getStructBase(Index);
714},
715Value.getStructNumBases(), "base", "bases");
716
717dumpAPValueChildren(
718Value, Ty,
719[](const APValue &Value, unsigned Index) -> const APValue & {
720return Value.getStructField(Index);
721},
722Value.getStructNumFields(), "field", "fields");
723
724return;
725}
726case APValue::Union: {
727OS << "Union";
728{
729ColorScope Color(OS, ShowColors, ValueColor);
730if (const FieldDecl *FD = Value.getUnionField())
731OS << " ." << *cast<NamedDecl>(FD);
732}
733// If the union value is considered to be simple, fold it into the
734// current line to save some vertical space.
735const APValue &UnionValue = Value.getUnionValue();
736if (isSimpleAPValue(UnionValue)) {
737OS << ' ';
738Visit(UnionValue, Ty);
739} else {
740AddChild([=] { Visit(UnionValue, Ty); });
741}
742
743return;
744}
745case APValue::MemberPointer:
746OS << "MemberPointer <todo>";
747return;
748case APValue::AddrLabelDiff:
749OS << "AddrLabelDiff <todo>";
750return;
751}
752llvm_unreachable("Unknown APValue kind!");
753}
754
755void TextNodeDumper::dumpPointer(const void *Ptr) {
756ColorScope Color(OS, ShowColors, AddressColor);
757OS << ' ' << Ptr;
758}
759
760void TextNodeDumper::dumpLocation(SourceLocation Loc) {
761if (!SM)
762return;
763
764ColorScope Color(OS, ShowColors, LocationColor);
765SourceLocation SpellingLoc = SM->getSpellingLoc(Loc);
766
767// The general format we print out is filename:line:col, but we drop pieces
768// that haven't changed since the last loc printed.
769PresumedLoc PLoc = SM->getPresumedLoc(SpellingLoc);
770
771if (PLoc.isInvalid()) {
772OS << "<invalid sloc>";
773return;
774}
775
776if (strcmp(PLoc.getFilename(), LastLocFilename) != 0) {
777OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':'
778<< PLoc.getColumn();
779LastLocFilename = PLoc.getFilename();
780LastLocLine = PLoc.getLine();
781} else if (PLoc.getLine() != LastLocLine) {
782OS << "line" << ':' << PLoc.getLine() << ':' << PLoc.getColumn();
783LastLocLine = PLoc.getLine();
784} else {
785OS << "col" << ':' << PLoc.getColumn();
786}
787}
788
789void TextNodeDumper::dumpSourceRange(SourceRange R) {
790// Can't translate locations if a SourceManager isn't available.
791if (!SM)
792return;
793
794OS << " <";
795dumpLocation(R.getBegin());
796if (R.getBegin() != R.getEnd()) {
797OS << ", ";
798dumpLocation(R.getEnd());
799}
800OS << ">";
801
802// <t2.c:123:421[blah], t2.c:412:321>
803}
804
805void TextNodeDumper::dumpBareType(QualType T, bool Desugar) {
806ColorScope Color(OS, ShowColors, TypeColor);
807
808SplitQualType T_split = T.split();
809std::string T_str = QualType::getAsString(T_split, PrintPolicy);
810OS << "'" << T_str << "'";
811
812if (Desugar && !T.isNull()) {
813// If the type is sugared, also dump a (shallow) desugared type when
814// it is visibly different.
815SplitQualType D_split = T.getSplitDesugaredType();
816if (T_split != D_split) {
817std::string D_str = QualType::getAsString(D_split, PrintPolicy);
818if (T_str != D_str)
819OS << ":'" << QualType::getAsString(D_split, PrintPolicy) << "'";
820}
821}
822}
823
824void TextNodeDumper::dumpType(QualType T) {
825OS << ' ';
826dumpBareType(T);
827}
828
829void TextNodeDumper::dumpBareDeclRef(const Decl *D) {
830if (!D) {
831ColorScope Color(OS, ShowColors, NullColor);
832OS << "<<<NULL>>>";
833return;
834}
835
836{
837ColorScope Color(OS, ShowColors, DeclKindNameColor);
838OS << D->getDeclKindName();
839}
840dumpPointer(D);
841
842if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
843ColorScope Color(OS, ShowColors, DeclNameColor);
844OS << " '" << ND->getDeclName() << '\'';
845}
846
847if (const ValueDecl *VD = dyn_cast<ValueDecl>(D))
848dumpType(VD->getType());
849}
850
851void TextNodeDumper::dumpName(const NamedDecl *ND) {
852if (ND->getDeclName()) {
853ColorScope Color(OS, ShowColors, DeclNameColor);
854OS << ' ' << ND->getDeclName();
855}
856}
857
858void TextNodeDumper::dumpAccessSpecifier(AccessSpecifier AS) {
859const auto AccessSpelling = getAccessSpelling(AS);
860if (AccessSpelling.empty())
861return;
862OS << AccessSpelling;
863}
864
865void TextNodeDumper::dumpCleanupObject(
866const ExprWithCleanups::CleanupObject &C) {
867if (auto *BD = C.dyn_cast<BlockDecl *>())
868dumpDeclRef(BD, "cleanup");
869else if (auto *CLE = C.dyn_cast<CompoundLiteralExpr *>())
870AddChild([=] {
871OS << "cleanup ";
872{
873ColorScope Color(OS, ShowColors, StmtColor);
874OS << CLE->getStmtClassName();
875}
876dumpPointer(CLE);
877});
878else
879llvm_unreachable("unexpected cleanup type");
880}
881
882void clang::TextNodeDumper::dumpTemplateSpecializationKind(
883TemplateSpecializationKind TSK) {
884switch (TSK) {
885case TSK_Undeclared:
886break;
887case TSK_ImplicitInstantiation:
888OS << " implicit_instantiation";
889break;
890case TSK_ExplicitSpecialization:
891OS << " explicit_specialization";
892break;
893case TSK_ExplicitInstantiationDeclaration:
894OS << " explicit_instantiation_declaration";
895break;
896case TSK_ExplicitInstantiationDefinition:
897OS << " explicit_instantiation_definition";
898break;
899}
900}
901
902void clang::TextNodeDumper::dumpNestedNameSpecifier(const NestedNameSpecifier *NNS) {
903if (!NNS)
904return;
905
906AddChild([=] {
907OS << "NestedNameSpecifier";
908
909switch (NNS->getKind()) {
910case NestedNameSpecifier::Identifier:
911OS << " Identifier";
912OS << " '" << NNS->getAsIdentifier()->getName() << "'";
913break;
914case NestedNameSpecifier::Namespace:
915OS << " "; // "Namespace" is printed as the decl kind.
916dumpBareDeclRef(NNS->getAsNamespace());
917break;
918case NestedNameSpecifier::NamespaceAlias:
919OS << " "; // "NamespaceAlias" is printed as the decl kind.
920dumpBareDeclRef(NNS->getAsNamespaceAlias());
921break;
922case NestedNameSpecifier::TypeSpec:
923OS << " TypeSpec";
924dumpType(QualType(NNS->getAsType(), 0));
925break;
926case NestedNameSpecifier::TypeSpecWithTemplate:
927OS << " TypeSpecWithTemplate";
928dumpType(QualType(NNS->getAsType(), 0));
929break;
930case NestedNameSpecifier::Global:
931OS << " Global";
932break;
933case NestedNameSpecifier::Super:
934OS << " Super";
935break;
936}
937
938dumpNestedNameSpecifier(NNS->getPrefix());
939});
940}
941
942void TextNodeDumper::dumpDeclRef(const Decl *D, StringRef Label) {
943if (!D)
944return;
945
946AddChild([=] {
947if (!Label.empty())
948OS << Label << ' ';
949dumpBareDeclRef(D);
950});
951}
952
953void TextNodeDumper::dumpTemplateArgument(const TemplateArgument &TA) {
954llvm::SmallString<128> Str;
955{
956llvm::raw_svector_ostream SS(Str);
957TA.print(PrintPolicy, SS, /*IncludeType=*/true);
958}
959OS << " '" << Str << "'";
960
961if (!Context)
962return;
963
964if (TemplateArgument CanonTA = Context->getCanonicalTemplateArgument(TA);
965!CanonTA.structurallyEquals(TA)) {
966llvm::SmallString<128> CanonStr;
967{
968llvm::raw_svector_ostream SS(CanonStr);
969CanonTA.print(PrintPolicy, SS, /*IncludeType=*/true);
970}
971if (CanonStr != Str)
972OS << ":'" << CanonStr << "'";
973}
974}
975
976const char *TextNodeDumper::getCommandName(unsigned CommandID) {
977if (Traits)
978return Traits->getCommandInfo(CommandID)->Name;
979const comments::CommandInfo *Info =
980comments::CommandTraits::getBuiltinCommandInfo(CommandID);
981if (Info)
982return Info->Name;
983return "<not a builtin command>";
984}
985
986void TextNodeDumper::printFPOptions(FPOptionsOverride FPO) {
987#define OPTION(NAME, TYPE, WIDTH, PREVIOUS) \
988if (FPO.has##NAME##Override()) \
989OS << " " #NAME "=" << FPO.get##NAME##Override();
990#include "clang/Basic/FPOptions.def"
991}
992
993void TextNodeDumper::visitTextComment(const comments::TextComment *C,
994const comments::FullComment *) {
995OS << " Text=\"" << C->getText() << "\"";
996}
997
998void TextNodeDumper::visitInlineCommandComment(
999const comments::InlineCommandComment *C, const comments::FullComment *) {
1000OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
1001switch (C->getRenderKind()) {
1002case comments::InlineCommandRenderKind::Normal:
1003OS << " RenderNormal";
1004break;
1005case comments::InlineCommandRenderKind::Bold:
1006OS << " RenderBold";
1007break;
1008case comments::InlineCommandRenderKind::Monospaced:
1009OS << " RenderMonospaced";
1010break;
1011case comments::InlineCommandRenderKind::Emphasized:
1012OS << " RenderEmphasized";
1013break;
1014case comments::InlineCommandRenderKind::Anchor:
1015OS << " RenderAnchor";
1016break;
1017}
1018
1019for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
1020OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
1021}
1022
1023void TextNodeDumper::visitHTMLStartTagComment(
1024const comments::HTMLStartTagComment *C, const comments::FullComment *) {
1025OS << " Name=\"" << C->getTagName() << "\"";
1026if (C->getNumAttrs() != 0) {
1027OS << " Attrs: ";
1028for (unsigned i = 0, e = C->getNumAttrs(); i != e; ++i) {
1029const comments::HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
1030OS << " \"" << Attr.Name << "=\"" << Attr.Value << "\"";
1031}
1032}
1033if (C->isSelfClosing())
1034OS << " SelfClosing";
1035}
1036
1037void TextNodeDumper::visitHTMLEndTagComment(
1038const comments::HTMLEndTagComment *C, const comments::FullComment *) {
1039OS << " Name=\"" << C->getTagName() << "\"";
1040}
1041
1042void TextNodeDumper::visitBlockCommandComment(
1043const comments::BlockCommandComment *C, const comments::FullComment *) {
1044OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
1045for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
1046OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
1047}
1048
1049void TextNodeDumper::visitParamCommandComment(
1050const comments::ParamCommandComment *C, const comments::FullComment *FC) {
1051OS << " "
1052<< comments::ParamCommandComment::getDirectionAsString(C->getDirection());
1053
1054if (C->isDirectionExplicit())
1055OS << " explicitly";
1056else
1057OS << " implicitly";
1058
1059if (C->hasParamName()) {
1060if (C->isParamIndexValid())
1061OS << " Param=\"" << C->getParamName(FC) << "\"";
1062else
1063OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
1064}
1065
1066if (C->isParamIndexValid() && !C->isVarArgParam())
1067OS << " ParamIndex=" << C->getParamIndex();
1068}
1069
1070void TextNodeDumper::visitTParamCommandComment(
1071const comments::TParamCommandComment *C, const comments::FullComment *FC) {
1072if (C->hasParamName()) {
1073if (C->isPositionValid())
1074OS << " Param=\"" << C->getParamName(FC) << "\"";
1075else
1076OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
1077}
1078
1079if (C->isPositionValid()) {
1080OS << " Position=<";
1081for (unsigned i = 0, e = C->getDepth(); i != e; ++i) {
1082OS << C->getIndex(i);
1083if (i != e - 1)
1084OS << ", ";
1085}
1086OS << ">";
1087}
1088}
1089
1090void TextNodeDumper::visitVerbatimBlockComment(
1091const comments::VerbatimBlockComment *C, const comments::FullComment *) {
1092OS << " Name=\"" << getCommandName(C->getCommandID())
1093<< "\""
1094" CloseName=\""
1095<< C->getCloseName() << "\"";
1096}
1097
1098void TextNodeDumper::visitVerbatimBlockLineComment(
1099const comments::VerbatimBlockLineComment *C,
1100const comments::FullComment *) {
1101OS << " Text=\"" << C->getText() << "\"";
1102}
1103
1104void TextNodeDumper::visitVerbatimLineComment(
1105const comments::VerbatimLineComment *C, const comments::FullComment *) {
1106OS << " Text=\"" << C->getText() << "\"";
1107}
1108
1109void TextNodeDumper::VisitNullTemplateArgument(const TemplateArgument &) {
1110OS << " null";
1111}
1112
1113void TextNodeDumper::VisitTypeTemplateArgument(const TemplateArgument &TA) {
1114OS << " type";
1115dumpTemplateArgument(TA);
1116}
1117
1118void TextNodeDumper::VisitDeclarationTemplateArgument(
1119const TemplateArgument &TA) {
1120OS << " decl";
1121dumpTemplateArgument(TA);
1122dumpDeclRef(TA.getAsDecl());
1123}
1124
1125void TextNodeDumper::VisitNullPtrTemplateArgument(const TemplateArgument &TA) {
1126OS << " nullptr";
1127dumpTemplateArgument(TA);
1128}
1129
1130void TextNodeDumper::VisitIntegralTemplateArgument(const TemplateArgument &TA) {
1131OS << " integral";
1132dumpTemplateArgument(TA);
1133}
1134
1135void TextNodeDumper::dumpTemplateName(TemplateName TN, StringRef Label) {
1136AddChild(Label, [=] {
1137{
1138llvm::SmallString<128> Str;
1139{
1140llvm::raw_svector_ostream SS(Str);
1141TN.print(SS, PrintPolicy);
1142}
1143OS << "'" << Str << "'";
1144
1145if (Context) {
1146if (TemplateName CanonTN = Context->getCanonicalTemplateName(TN);
1147CanonTN != TN) {
1148llvm::SmallString<128> CanonStr;
1149{
1150llvm::raw_svector_ostream SS(CanonStr);
1151CanonTN.print(SS, PrintPolicy);
1152}
1153if (CanonStr != Str)
1154OS << ":'" << CanonStr << "'";
1155}
1156}
1157}
1158dumpBareTemplateName(TN);
1159});
1160}
1161
1162void TextNodeDumper::dumpBareTemplateName(TemplateName TN) {
1163switch (TN.getKind()) {
1164case TemplateName::Template:
1165AddChild([=] { Visit(TN.getAsTemplateDecl()); });
1166return;
1167case TemplateName::UsingTemplate: {
1168const UsingShadowDecl *USD = TN.getAsUsingShadowDecl();
1169AddChild([=] { Visit(USD); });
1170AddChild("target", [=] { Visit(USD->getTargetDecl()); });
1171return;
1172}
1173case TemplateName::QualifiedTemplate: {
1174OS << " qualified";
1175const QualifiedTemplateName *QTN = TN.getAsQualifiedTemplateName();
1176if (QTN->hasTemplateKeyword())
1177OS << " keyword";
1178dumpNestedNameSpecifier(QTN->getQualifier());
1179dumpBareTemplateName(QTN->getUnderlyingTemplate());
1180return;
1181}
1182case TemplateName::DependentTemplate: {
1183OS << " dependent";
1184const DependentTemplateName *DTN = TN.getAsDependentTemplateName();
1185dumpNestedNameSpecifier(DTN->getQualifier());
1186return;
1187}
1188case TemplateName::SubstTemplateTemplateParm: {
1189OS << " subst";
1190const SubstTemplateTemplateParmStorage *STS =
1191TN.getAsSubstTemplateTemplateParm();
1192OS << " index " << STS->getIndex();
1193if (std::optional<unsigned int> PackIndex = STS->getPackIndex())
1194OS << " pack_index " << *PackIndex;
1195if (const TemplateTemplateParmDecl *P = STS->getParameter())
1196AddChild("parameter", [=] { Visit(P); });
1197dumpDeclRef(STS->getAssociatedDecl(), "associated");
1198dumpTemplateName(STS->getReplacement(), "replacement");
1199return;
1200}
1201// FIXME: Implement these.
1202case TemplateName::OverloadedTemplate:
1203OS << " overloaded";
1204return;
1205case TemplateName::AssumedTemplate:
1206OS << " assumed";
1207return;
1208case TemplateName::SubstTemplateTemplateParmPack:
1209OS << " subst_pack";
1210return;
1211}
1212llvm_unreachable("Unexpected TemplateName Kind");
1213}
1214
1215void TextNodeDumper::VisitTemplateTemplateArgument(const TemplateArgument &TA) {
1216OS << " template";
1217dumpTemplateArgument(TA);
1218dumpBareTemplateName(TA.getAsTemplate());
1219}
1220
1221void TextNodeDumper::VisitTemplateExpansionTemplateArgument(
1222const TemplateArgument &TA) {
1223OS << " template expansion";
1224dumpTemplateArgument(TA);
1225dumpBareTemplateName(TA.getAsTemplateOrTemplatePattern());
1226}
1227
1228void TextNodeDumper::VisitExpressionTemplateArgument(
1229const TemplateArgument &TA) {
1230OS << " expr";
1231dumpTemplateArgument(TA);
1232}
1233
1234void TextNodeDumper::VisitPackTemplateArgument(const TemplateArgument &TA) {
1235OS << " pack";
1236dumpTemplateArgument(TA);
1237}
1238
1239static void dumpBasePath(raw_ostream &OS, const CastExpr *Node) {
1240if (Node->path_empty())
1241return;
1242
1243OS << " (";
1244bool First = true;
1245for (CastExpr::path_const_iterator I = Node->path_begin(),
1246E = Node->path_end();
1247I != E; ++I) {
1248const CXXBaseSpecifier *Base = *I;
1249if (!First)
1250OS << " -> ";
1251
1252const auto *RD =
1253cast<CXXRecordDecl>(Base->getType()->castAs<RecordType>()->getDecl());
1254
1255if (Base->isVirtual())
1256OS << "virtual ";
1257OS << RD->getName();
1258First = false;
1259}
1260
1261OS << ')';
1262}
1263
1264void TextNodeDumper::VisitIfStmt(const IfStmt *Node) {
1265if (Node->hasInitStorage())
1266OS << " has_init";
1267if (Node->hasVarStorage())
1268OS << " has_var";
1269if (Node->hasElseStorage())
1270OS << " has_else";
1271if (Node->isConstexpr())
1272OS << " constexpr";
1273if (Node->isConsteval()) {
1274OS << " ";
1275if (Node->isNegatedConsteval())
1276OS << "!";
1277OS << "consteval";
1278}
1279}
1280
1281void TextNodeDumper::VisitSwitchStmt(const SwitchStmt *Node) {
1282if (Node->hasInitStorage())
1283OS << " has_init";
1284if (Node->hasVarStorage())
1285OS << " has_var";
1286}
1287
1288void TextNodeDumper::VisitWhileStmt(const WhileStmt *Node) {
1289if (Node->hasVarStorage())
1290OS << " has_var";
1291}
1292
1293void TextNodeDumper::VisitLabelStmt(const LabelStmt *Node) {
1294OS << " '" << Node->getName() << "'";
1295if (Node->isSideEntry())
1296OS << " side_entry";
1297}
1298
1299void TextNodeDumper::VisitGotoStmt(const GotoStmt *Node) {
1300OS << " '" << Node->getLabel()->getName() << "'";
1301dumpPointer(Node->getLabel());
1302}
1303
1304void TextNodeDumper::VisitCaseStmt(const CaseStmt *Node) {
1305if (Node->caseStmtIsGNURange())
1306OS << " gnu_range";
1307}
1308
1309void clang::TextNodeDumper::VisitReturnStmt(const ReturnStmt *Node) {
1310if (const VarDecl *Cand = Node->getNRVOCandidate()) {
1311OS << " nrvo_candidate(";
1312dumpBareDeclRef(Cand);
1313OS << ")";
1314}
1315}
1316
1317void clang::TextNodeDumper::VisitCoawaitExpr(const CoawaitExpr *Node) {
1318if (Node->isImplicit())
1319OS << " implicit";
1320}
1321
1322void clang::TextNodeDumper::VisitCoreturnStmt(const CoreturnStmt *Node) {
1323if (Node->isImplicit())
1324OS << " implicit";
1325}
1326
1327void TextNodeDumper::VisitConstantExpr(const ConstantExpr *Node) {
1328if (Node->hasAPValueResult())
1329AddChild("value",
1330[=] { Visit(Node->getAPValueResult(), Node->getType()); });
1331}
1332
1333void TextNodeDumper::VisitCallExpr(const CallExpr *Node) {
1334if (Node->usesADL())
1335OS << " adl";
1336if (Node->hasStoredFPFeatures())
1337printFPOptions(Node->getFPFeatures());
1338}
1339
1340void TextNodeDumper::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Node) {
1341const char *OperatorSpelling = clang::getOperatorSpelling(Node->getOperator());
1342if (OperatorSpelling)
1343OS << " '" << OperatorSpelling << "'";
1344
1345VisitCallExpr(Node);
1346}
1347
1348void TextNodeDumper::VisitCastExpr(const CastExpr *Node) {
1349OS << " <";
1350{
1351ColorScope Color(OS, ShowColors, CastColor);
1352OS << Node->getCastKindName();
1353}
1354dumpBasePath(OS, Node);
1355OS << ">";
1356if (Node->hasStoredFPFeatures())
1357printFPOptions(Node->getFPFeatures());
1358}
1359
1360void TextNodeDumper::VisitImplicitCastExpr(const ImplicitCastExpr *Node) {
1361VisitCastExpr(Node);
1362if (Node->isPartOfExplicitCast())
1363OS << " part_of_explicit_cast";
1364}
1365
1366void TextNodeDumper::VisitDeclRefExpr(const DeclRefExpr *Node) {
1367OS << " ";
1368dumpBareDeclRef(Node->getDecl());
1369dumpNestedNameSpecifier(Node->getQualifier());
1370if (Node->getDecl() != Node->getFoundDecl()) {
1371OS << " (";
1372dumpBareDeclRef(Node->getFoundDecl());
1373OS << ")";
1374}
1375switch (Node->isNonOdrUse()) {
1376case NOUR_None: break;
1377case NOUR_Unevaluated: OS << " non_odr_use_unevaluated"; break;
1378case NOUR_Constant: OS << " non_odr_use_constant"; break;
1379case NOUR_Discarded: OS << " non_odr_use_discarded"; break;
1380}
1381if (Node->isCapturedByCopyInLambdaWithExplicitObjectParameter())
1382OS << " dependent_capture";
1383else if (Node->refersToEnclosingVariableOrCapture())
1384OS << " refers_to_enclosing_variable_or_capture";
1385
1386if (Node->isImmediateEscalating())
1387OS << " immediate-escalating";
1388}
1389
1390void clang::TextNodeDumper::VisitDependentScopeDeclRefExpr(
1391const DependentScopeDeclRefExpr *Node) {
1392
1393dumpNestedNameSpecifier(Node->getQualifier());
1394}
1395
1396void TextNodeDumper::VisitUnresolvedLookupExpr(
1397const UnresolvedLookupExpr *Node) {
1398OS << " (";
1399if (!Node->requiresADL())
1400OS << "no ";
1401OS << "ADL) = '" << Node->getName() << '\'';
1402
1403UnresolvedLookupExpr::decls_iterator I = Node->decls_begin(),
1404E = Node->decls_end();
1405if (I == E)
1406OS << " empty";
1407for (; I != E; ++I)
1408dumpPointer(*I);
1409}
1410
1411void TextNodeDumper::VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node) {
1412{
1413ColorScope Color(OS, ShowColors, DeclKindNameColor);
1414OS << " " << Node->getDecl()->getDeclKindName() << "Decl";
1415}
1416OS << "='" << *Node->getDecl() << "'";
1417dumpPointer(Node->getDecl());
1418if (Node->isFreeIvar())
1419OS << " isFreeIvar";
1420}
1421
1422void TextNodeDumper::VisitSYCLUniqueStableNameExpr(
1423const SYCLUniqueStableNameExpr *Node) {
1424dumpType(Node->getTypeSourceInfo()->getType());
1425}
1426
1427void TextNodeDumper::VisitPredefinedExpr(const PredefinedExpr *Node) {
1428OS << " " << PredefinedExpr::getIdentKindName(Node->getIdentKind());
1429}
1430
1431void TextNodeDumper::VisitCharacterLiteral(const CharacterLiteral *Node) {
1432ColorScope Color(OS, ShowColors, ValueColor);
1433OS << " " << Node->getValue();
1434}
1435
1436void TextNodeDumper::VisitIntegerLiteral(const IntegerLiteral *Node) {
1437bool isSigned = Node->getType()->isSignedIntegerType();
1438ColorScope Color(OS, ShowColors, ValueColor);
1439OS << " " << toString(Node->getValue(), 10, isSigned);
1440}
1441
1442void TextNodeDumper::VisitFixedPointLiteral(const FixedPointLiteral *Node) {
1443ColorScope Color(OS, ShowColors, ValueColor);
1444OS << " " << Node->getValueAsString(/*Radix=*/10);
1445}
1446
1447void TextNodeDumper::VisitFloatingLiteral(const FloatingLiteral *Node) {
1448ColorScope Color(OS, ShowColors, ValueColor);
1449OS << " " << Node->getValueAsApproximateDouble();
1450}
1451
1452void TextNodeDumper::VisitStringLiteral(const StringLiteral *Str) {
1453ColorScope Color(OS, ShowColors, ValueColor);
1454OS << " ";
1455Str->outputString(OS);
1456}
1457
1458void TextNodeDumper::VisitInitListExpr(const InitListExpr *ILE) {
1459if (auto *Field = ILE->getInitializedFieldInUnion()) {
1460OS << " field ";
1461dumpBareDeclRef(Field);
1462}
1463}
1464
1465void TextNodeDumper::VisitGenericSelectionExpr(const GenericSelectionExpr *E) {
1466if (E->isResultDependent())
1467OS << " result_dependent";
1468}
1469
1470void TextNodeDumper::VisitUnaryOperator(const UnaryOperator *Node) {
1471OS << " " << (Node->isPostfix() ? "postfix" : "prefix") << " '"
1472<< UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
1473if (!Node->canOverflow())
1474OS << " cannot overflow";
1475if (Node->hasStoredFPFeatures())
1476printFPOptions(Node->getStoredFPFeatures());
1477}
1478
1479void TextNodeDumper::VisitUnaryExprOrTypeTraitExpr(
1480const UnaryExprOrTypeTraitExpr *Node) {
1481OS << " " << getTraitSpelling(Node->getKind());
1482
1483if (Node->isArgumentType())
1484dumpType(Node->getArgumentType());
1485}
1486
1487void TextNodeDumper::VisitMemberExpr(const MemberExpr *Node) {
1488OS << " " << (Node->isArrow() ? "->" : ".") << *Node->getMemberDecl();
1489dumpPointer(Node->getMemberDecl());
1490dumpNestedNameSpecifier(Node->getQualifier());
1491switch (Node->isNonOdrUse()) {
1492case NOUR_None: break;
1493case NOUR_Unevaluated: OS << " non_odr_use_unevaluated"; break;
1494case NOUR_Constant: OS << " non_odr_use_constant"; break;
1495case NOUR_Discarded: OS << " non_odr_use_discarded"; break;
1496}
1497}
1498
1499void TextNodeDumper::VisitExtVectorElementExpr(
1500const ExtVectorElementExpr *Node) {
1501OS << " " << Node->getAccessor().getNameStart();
1502}
1503
1504void TextNodeDumper::VisitBinaryOperator(const BinaryOperator *Node) {
1505OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
1506if (Node->hasStoredFPFeatures())
1507printFPOptions(Node->getStoredFPFeatures());
1508}
1509
1510void TextNodeDumper::VisitCompoundAssignOperator(
1511const CompoundAssignOperator *Node) {
1512OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode())
1513<< "' ComputeLHSTy=";
1514dumpBareType(Node->getComputationLHSType());
1515OS << " ComputeResultTy=";
1516dumpBareType(Node->getComputationResultType());
1517if (Node->hasStoredFPFeatures())
1518printFPOptions(Node->getStoredFPFeatures());
1519}
1520
1521void TextNodeDumper::VisitAddrLabelExpr(const AddrLabelExpr *Node) {
1522OS << " " << Node->getLabel()->getName();
1523dumpPointer(Node->getLabel());
1524}
1525
1526void TextNodeDumper::VisitCXXNamedCastExpr(const CXXNamedCastExpr *Node) {
1527OS << " " << Node->getCastName() << "<"
1528<< Node->getTypeAsWritten().getAsString() << ">"
1529<< " <" << Node->getCastKindName();
1530dumpBasePath(OS, Node);
1531OS << ">";
1532}
1533
1534void TextNodeDumper::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node) {
1535OS << " " << (Node->getValue() ? "true" : "false");
1536}
1537
1538void TextNodeDumper::VisitCXXThisExpr(const CXXThisExpr *Node) {
1539if (Node->isImplicit())
1540OS << " implicit";
1541if (Node->isCapturedByCopyInLambdaWithExplicitObjectParameter())
1542OS << " dependent_capture";
1543OS << " this";
1544}
1545
1546void TextNodeDumper::VisitCXXFunctionalCastExpr(
1547const CXXFunctionalCastExpr *Node) {
1548OS << " functional cast to " << Node->getTypeAsWritten().getAsString() << " <"
1549<< Node->getCastKindName() << ">";
1550if (Node->hasStoredFPFeatures())
1551printFPOptions(Node->getFPFeatures());
1552}
1553
1554void TextNodeDumper::VisitCXXStaticCastExpr(const CXXStaticCastExpr *Node) {
1555VisitCXXNamedCastExpr(Node);
1556if (Node->hasStoredFPFeatures())
1557printFPOptions(Node->getFPFeatures());
1558}
1559
1560void TextNodeDumper::VisitCXXUnresolvedConstructExpr(
1561const CXXUnresolvedConstructExpr *Node) {
1562dumpType(Node->getTypeAsWritten());
1563if (Node->isListInitialization())
1564OS << " list";
1565}
1566
1567void TextNodeDumper::VisitCXXConstructExpr(const CXXConstructExpr *Node) {
1568CXXConstructorDecl *Ctor = Node->getConstructor();
1569dumpType(Ctor->getType());
1570if (Node->isElidable())
1571OS << " elidable";
1572if (Node->isListInitialization())
1573OS << " list";
1574if (Node->isStdInitListInitialization())
1575OS << " std::initializer_list";
1576if (Node->requiresZeroInitialization())
1577OS << " zeroing";
1578if (Node->isImmediateEscalating())
1579OS << " immediate-escalating";
1580}
1581
1582void TextNodeDumper::VisitCXXBindTemporaryExpr(
1583const CXXBindTemporaryExpr *Node) {
1584OS << " (CXXTemporary";
1585dumpPointer(Node);
1586OS << ")";
1587}
1588
1589void TextNodeDumper::VisitCXXNewExpr(const CXXNewExpr *Node) {
1590if (Node->isGlobalNew())
1591OS << " global";
1592if (Node->isArray())
1593OS << " array";
1594if (Node->getOperatorNew()) {
1595OS << ' ';
1596dumpBareDeclRef(Node->getOperatorNew());
1597}
1598// We could dump the deallocation function used in case of error, but it's
1599// usually not that interesting.
1600}
1601
1602void TextNodeDumper::VisitCXXDeleteExpr(const CXXDeleteExpr *Node) {
1603if (Node->isGlobalDelete())
1604OS << " global";
1605if (Node->isArrayForm())
1606OS << " array";
1607if (Node->getOperatorDelete()) {
1608OS << ' ';
1609dumpBareDeclRef(Node->getOperatorDelete());
1610}
1611}
1612
1613void TextNodeDumper::VisitTypeTraitExpr(const TypeTraitExpr *Node) {
1614OS << " " << getTraitSpelling(Node->getTrait());
1615}
1616
1617void TextNodeDumper::VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *Node) {
1618OS << " " << getTraitSpelling(Node->getTrait());
1619}
1620
1621void TextNodeDumper::VisitExpressionTraitExpr(const ExpressionTraitExpr *Node) {
1622OS << " " << getTraitSpelling(Node->getTrait());
1623}
1624
1625void TextNodeDumper::VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *Node) {
1626if (Node->hasRewrittenInit())
1627OS << " has rewritten init";
1628}
1629
1630void TextNodeDumper::VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *Node) {
1631if (Node->hasRewrittenInit())
1632OS << " has rewritten init";
1633}
1634
1635void TextNodeDumper::VisitMaterializeTemporaryExpr(
1636const MaterializeTemporaryExpr *Node) {
1637if (const ValueDecl *VD = Node->getExtendingDecl()) {
1638OS << " extended by ";
1639dumpBareDeclRef(VD);
1640}
1641}
1642
1643void TextNodeDumper::VisitExprWithCleanups(const ExprWithCleanups *Node) {
1644for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i)
1645dumpCleanupObject(Node->getObject(i));
1646}
1647
1648void TextNodeDumper::VisitSizeOfPackExpr(const SizeOfPackExpr *Node) {
1649dumpPointer(Node->getPack());
1650dumpName(Node->getPack());
1651}
1652
1653void TextNodeDumper::VisitCXXDependentScopeMemberExpr(
1654const CXXDependentScopeMemberExpr *Node) {
1655OS << " " << (Node->isArrow() ? "->" : ".") << Node->getMember();
1656}
1657
1658void TextNodeDumper::VisitObjCMessageExpr(const ObjCMessageExpr *Node) {
1659OS << " selector=";
1660Node->getSelector().print(OS);
1661switch (Node->getReceiverKind()) {
1662case ObjCMessageExpr::Instance:
1663break;
1664
1665case ObjCMessageExpr::Class:
1666OS << " class=";
1667dumpBareType(Node->getClassReceiver());
1668break;
1669
1670case ObjCMessageExpr::SuperInstance:
1671OS << " super (instance)";
1672break;
1673
1674case ObjCMessageExpr::SuperClass:
1675OS << " super (class)";
1676break;
1677}
1678}
1679
1680void TextNodeDumper::VisitObjCBoxedExpr(const ObjCBoxedExpr *Node) {
1681if (auto *BoxingMethod = Node->getBoxingMethod()) {
1682OS << " selector=";
1683BoxingMethod->getSelector().print(OS);
1684}
1685}
1686
1687void TextNodeDumper::VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node) {
1688if (!Node->getCatchParamDecl())
1689OS << " catch all";
1690}
1691
1692void TextNodeDumper::VisitObjCEncodeExpr(const ObjCEncodeExpr *Node) {
1693dumpType(Node->getEncodedType());
1694}
1695
1696void TextNodeDumper::VisitObjCSelectorExpr(const ObjCSelectorExpr *Node) {
1697OS << " ";
1698Node->getSelector().print(OS);
1699}
1700
1701void TextNodeDumper::VisitObjCProtocolExpr(const ObjCProtocolExpr *Node) {
1702OS << ' ' << *Node->getProtocol();
1703}
1704
1705void TextNodeDumper::VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *Node) {
1706if (Node->isImplicitProperty()) {
1707OS << " Kind=MethodRef Getter=\"";
1708if (Node->getImplicitPropertyGetter())
1709Node->getImplicitPropertyGetter()->getSelector().print(OS);
1710else
1711OS << "(null)";
1712
1713OS << "\" Setter=\"";
1714if (ObjCMethodDecl *Setter = Node->getImplicitPropertySetter())
1715Setter->getSelector().print(OS);
1716else
1717OS << "(null)";
1718OS << "\"";
1719} else {
1720OS << " Kind=PropertyRef Property=\"" << *Node->getExplicitProperty()
1721<< '"';
1722}
1723
1724if (Node->isSuperReceiver())
1725OS << " super";
1726
1727OS << " Messaging=";
1728if (Node->isMessagingGetter() && Node->isMessagingSetter())
1729OS << "Getter&Setter";
1730else if (Node->isMessagingGetter())
1731OS << "Getter";
1732else if (Node->isMessagingSetter())
1733OS << "Setter";
1734}
1735
1736void TextNodeDumper::VisitObjCSubscriptRefExpr(
1737const ObjCSubscriptRefExpr *Node) {
1738if (Node->isArraySubscriptRefExpr())
1739OS << " Kind=ArraySubscript GetterForArray=\"";
1740else
1741OS << " Kind=DictionarySubscript GetterForDictionary=\"";
1742if (Node->getAtIndexMethodDecl())
1743Node->getAtIndexMethodDecl()->getSelector().print(OS);
1744else
1745OS << "(null)";
1746
1747if (Node->isArraySubscriptRefExpr())
1748OS << "\" SetterForArray=\"";
1749else
1750OS << "\" SetterForDictionary=\"";
1751if (Node->setAtIndexMethodDecl())
1752Node->setAtIndexMethodDecl()->getSelector().print(OS);
1753else
1754OS << "(null)";
1755}
1756
1757void TextNodeDumper::VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node) {
1758OS << " " << (Node->getValue() ? "__objc_yes" : "__objc_no");
1759}
1760
1761void TextNodeDumper::VisitOMPIteratorExpr(const OMPIteratorExpr *Node) {
1762OS << " ";
1763for (unsigned I = 0, E = Node->numOfIterators(); I < E; ++I) {
1764Visit(Node->getIteratorDecl(I));
1765OS << " = ";
1766const OMPIteratorExpr::IteratorRange Range = Node->getIteratorRange(I);
1767OS << " begin ";
1768Visit(Range.Begin);
1769OS << " end ";
1770Visit(Range.End);
1771if (Range.Step) {
1772OS << " step ";
1773Visit(Range.Step);
1774}
1775}
1776}
1777
1778void TextNodeDumper::VisitConceptSpecializationExpr(
1779const ConceptSpecializationExpr *Node) {
1780OS << " ";
1781dumpBareDeclRef(Node->getFoundDecl());
1782}
1783
1784void TextNodeDumper::VisitRequiresExpr(
1785const RequiresExpr *Node) {
1786if (!Node->isValueDependent())
1787OS << (Node->isSatisfied() ? " satisfied" : " unsatisfied");
1788}
1789
1790void TextNodeDumper::VisitRValueReferenceType(const ReferenceType *T) {
1791if (T->isSpelledAsLValue())
1792OS << " written as lvalue reference";
1793}
1794
1795void TextNodeDumper::VisitArrayType(const ArrayType *T) {
1796switch (T->getSizeModifier()) {
1797case ArraySizeModifier::Normal:
1798break;
1799case ArraySizeModifier::Static:
1800OS << " static";
1801break;
1802case ArraySizeModifier::Star:
1803OS << " *";
1804break;
1805}
1806OS << " " << T->getIndexTypeQualifiers().getAsString();
1807}
1808
1809void TextNodeDumper::VisitConstantArrayType(const ConstantArrayType *T) {
1810OS << " " << T->getSize();
1811VisitArrayType(T);
1812}
1813
1814void TextNodeDumper::VisitVariableArrayType(const VariableArrayType *T) {
1815OS << " ";
1816dumpSourceRange(T->getBracketsRange());
1817VisitArrayType(T);
1818}
1819
1820void TextNodeDumper::VisitDependentSizedArrayType(
1821const DependentSizedArrayType *T) {
1822VisitArrayType(T);
1823OS << " ";
1824dumpSourceRange(T->getBracketsRange());
1825}
1826
1827void TextNodeDumper::VisitDependentSizedExtVectorType(
1828const DependentSizedExtVectorType *T) {
1829OS << " ";
1830dumpLocation(T->getAttributeLoc());
1831}
1832
1833void TextNodeDumper::VisitVectorType(const VectorType *T) {
1834switch (T->getVectorKind()) {
1835case VectorKind::Generic:
1836break;
1837case VectorKind::AltiVecVector:
1838OS << " altivec";
1839break;
1840case VectorKind::AltiVecPixel:
1841OS << " altivec pixel";
1842break;
1843case VectorKind::AltiVecBool:
1844OS << " altivec bool";
1845break;
1846case VectorKind::Neon:
1847OS << " neon";
1848break;
1849case VectorKind::NeonPoly:
1850OS << " neon poly";
1851break;
1852case VectorKind::SveFixedLengthData:
1853OS << " fixed-length sve data vector";
1854break;
1855case VectorKind::SveFixedLengthPredicate:
1856OS << " fixed-length sve predicate vector";
1857break;
1858case VectorKind::RVVFixedLengthData:
1859OS << " fixed-length rvv data vector";
1860break;
1861case VectorKind::RVVFixedLengthMask:
1862OS << " fixed-length rvv mask vector";
1863break;
1864}
1865OS << " " << T->getNumElements();
1866}
1867
1868void TextNodeDumper::VisitFunctionType(const FunctionType *T) {
1869auto EI = T->getExtInfo();
1870if (EI.getNoReturn())
1871OS << " noreturn";
1872if (EI.getProducesResult())
1873OS << " produces_result";
1874if (EI.getHasRegParm())
1875OS << " regparm " << EI.getRegParm();
1876OS << " " << FunctionType::getNameForCallConv(EI.getCC());
1877}
1878
1879void TextNodeDumper::VisitFunctionProtoType(const FunctionProtoType *T) {
1880auto EPI = T->getExtProtoInfo();
1881if (EPI.HasTrailingReturn)
1882OS << " trailing_return";
1883if (T->isConst())
1884OS << " const";
1885if (T->isVolatile())
1886OS << " volatile";
1887if (T->isRestrict())
1888OS << " restrict";
1889if (T->getExtProtoInfo().Variadic)
1890OS << " variadic";
1891switch (EPI.RefQualifier) {
1892case RQ_None:
1893break;
1894case RQ_LValue:
1895OS << " &";
1896break;
1897case RQ_RValue:
1898OS << " &&";
1899break;
1900}
1901
1902switch (EPI.ExceptionSpec.Type) {
1903case EST_None:
1904break;
1905case EST_DynamicNone:
1906OS << " exceptionspec_dynamic_none";
1907break;
1908case EST_Dynamic:
1909OS << " exceptionspec_dynamic";
1910break;
1911case EST_MSAny:
1912OS << " exceptionspec_ms_any";
1913break;
1914case EST_NoThrow:
1915OS << " exceptionspec_nothrow";
1916break;
1917case EST_BasicNoexcept:
1918OS << " exceptionspec_basic_noexcept";
1919break;
1920case EST_DependentNoexcept:
1921OS << " exceptionspec_dependent_noexcept";
1922break;
1923case EST_NoexceptFalse:
1924OS << " exceptionspec_noexcept_false";
1925break;
1926case EST_NoexceptTrue:
1927OS << " exceptionspec_noexcept_true";
1928break;
1929case EST_Unevaluated:
1930OS << " exceptionspec_unevaluated";
1931break;
1932case EST_Uninstantiated:
1933OS << " exceptionspec_uninstantiated";
1934break;
1935case EST_Unparsed:
1936OS << " exceptionspec_unparsed";
1937break;
1938}
1939if (!EPI.ExceptionSpec.Exceptions.empty()) {
1940AddChild([=] {
1941OS << "Exceptions:";
1942for (unsigned I = 0, N = EPI.ExceptionSpec.Exceptions.size(); I != N;
1943++I) {
1944if (I)
1945OS << ",";
1946dumpType(EPI.ExceptionSpec.Exceptions[I]);
1947}
1948});
1949}
1950if (EPI.ExceptionSpec.NoexceptExpr) {
1951AddChild([=] {
1952OS << "NoexceptExpr: ";
1953Visit(EPI.ExceptionSpec.NoexceptExpr);
1954});
1955}
1956dumpDeclRef(EPI.ExceptionSpec.SourceDecl, "ExceptionSourceDecl");
1957dumpDeclRef(EPI.ExceptionSpec.SourceTemplate, "ExceptionSourceTemplate");
1958
1959// FIXME: Consumed parameters.
1960VisitFunctionType(T);
1961}
1962
1963void TextNodeDumper::VisitUnresolvedUsingType(const UnresolvedUsingType *T) {
1964dumpDeclRef(T->getDecl());
1965}
1966
1967void TextNodeDumper::VisitUsingType(const UsingType *T) {
1968dumpDeclRef(T->getFoundDecl());
1969if (!T->typeMatchesDecl())
1970OS << " divergent";
1971}
1972
1973void TextNodeDumper::VisitTypedefType(const TypedefType *T) {
1974dumpDeclRef(T->getDecl());
1975if (!T->typeMatchesDecl())
1976OS << " divergent";
1977}
1978
1979void TextNodeDumper::VisitUnaryTransformType(const UnaryTransformType *T) {
1980switch (T->getUTTKind()) {
1981#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait) \
1982case UnaryTransformType::Enum: \
1983OS << " " #Trait; \
1984break;
1985#include "clang/Basic/TransformTypeTraits.def"
1986}
1987}
1988
1989void TextNodeDumper::VisitTagType(const TagType *T) {
1990dumpDeclRef(T->getDecl());
1991}
1992
1993void TextNodeDumper::VisitTemplateTypeParmType(const TemplateTypeParmType *T) {
1994OS << " depth " << T->getDepth() << " index " << T->getIndex();
1995if (T->isParameterPack())
1996OS << " pack";
1997dumpDeclRef(T->getDecl());
1998}
1999
2000void TextNodeDumper::VisitSubstTemplateTypeParmType(
2001const SubstTemplateTypeParmType *T) {
2002dumpDeclRef(T->getAssociatedDecl());
2003VisitTemplateTypeParmDecl(T->getReplacedParameter());
2004if (auto PackIndex = T->getPackIndex())
2005OS << " pack_index " << *PackIndex;
2006}
2007
2008void TextNodeDumper::VisitSubstTemplateTypeParmPackType(
2009const SubstTemplateTypeParmPackType *T) {
2010dumpDeclRef(T->getAssociatedDecl());
2011VisitTemplateTypeParmDecl(T->getReplacedParameter());
2012}
2013
2014void TextNodeDumper::VisitAutoType(const AutoType *T) {
2015if (T->isDecltypeAuto())
2016OS << " decltype(auto)";
2017if (!T->isDeduced())
2018OS << " undeduced";
2019if (T->isConstrained())
2020dumpDeclRef(T->getTypeConstraintConcept());
2021}
2022
2023void TextNodeDumper::VisitDeducedTemplateSpecializationType(
2024const DeducedTemplateSpecializationType *T) {
2025dumpTemplateName(T->getTemplateName(), "name");
2026}
2027
2028void TextNodeDumper::VisitTemplateSpecializationType(
2029const TemplateSpecializationType *T) {
2030if (T->isTypeAlias())
2031OS << " alias";
2032dumpTemplateName(T->getTemplateName(), "name");
2033}
2034
2035void TextNodeDumper::VisitInjectedClassNameType(
2036const InjectedClassNameType *T) {
2037dumpDeclRef(T->getDecl());
2038}
2039
2040void TextNodeDumper::VisitObjCInterfaceType(const ObjCInterfaceType *T) {
2041dumpDeclRef(T->getDecl());
2042}
2043
2044void TextNodeDumper::VisitPackExpansionType(const PackExpansionType *T) {
2045if (auto N = T->getNumExpansions())
2046OS << " expansions " << *N;
2047}
2048
2049void TextNodeDumper::VisitTypeLoc(TypeLoc TL) {
2050// By default, add extra Type details with no extra loc info.
2051TypeVisitor<TextNodeDumper>::Visit(TL.getTypePtr());
2052}
2053// FIXME: override behavior for TypeLocs that have interesting location
2054// information, such as the qualifier in ElaboratedTypeLoc.
2055
2056void TextNodeDumper::VisitLabelDecl(const LabelDecl *D) { dumpName(D); }
2057
2058void TextNodeDumper::VisitTypedefDecl(const TypedefDecl *D) {
2059dumpName(D);
2060dumpType(D->getUnderlyingType());
2061if (D->isModulePrivate())
2062OS << " __module_private__";
2063}
2064
2065void TextNodeDumper::VisitEnumDecl(const EnumDecl *D) {
2066if (D->isScoped()) {
2067if (D->isScopedUsingClassTag())
2068OS << " class";
2069else
2070OS << " struct";
2071}
2072dumpName(D);
2073if (D->isModulePrivate())
2074OS << " __module_private__";
2075if (D->isFixed())
2076dumpType(D->getIntegerType());
2077}
2078
2079void TextNodeDumper::VisitRecordDecl(const RecordDecl *D) {
2080OS << ' ' << D->getKindName();
2081dumpName(D);
2082if (D->isModulePrivate())
2083OS << " __module_private__";
2084if (D->isCompleteDefinition())
2085OS << " definition";
2086}
2087
2088void TextNodeDumper::VisitEnumConstantDecl(const EnumConstantDecl *D) {
2089dumpName(D);
2090dumpType(D->getType());
2091}
2092
2093void TextNodeDumper::VisitIndirectFieldDecl(const IndirectFieldDecl *D) {
2094dumpName(D);
2095dumpType(D->getType());
2096
2097for (const auto *Child : D->chain())
2098dumpDeclRef(Child);
2099}
2100
2101void TextNodeDumper::VisitFunctionDecl(const FunctionDecl *D) {
2102dumpName(D);
2103dumpType(D->getType());
2104dumpTemplateSpecializationKind(D->getTemplateSpecializationKind());
2105
2106StorageClass SC = D->getStorageClass();
2107if (SC != SC_None)
2108OS << ' ' << VarDecl::getStorageClassSpecifierString(SC);
2109if (D->isInlineSpecified())
2110OS << " inline";
2111if (D->isVirtualAsWritten())
2112OS << " virtual";
2113if (D->isModulePrivate())
2114OS << " __module_private__";
2115
2116if (D->isPureVirtual())
2117OS << " pure";
2118if (D->isDefaulted()) {
2119OS << " default";
2120if (D->isDeleted())
2121OS << "_delete";
2122}
2123if (D->isDeletedAsWritten())
2124OS << " delete";
2125if (D->isTrivial())
2126OS << " trivial";
2127
2128if (const StringLiteral *M = D->getDeletedMessage())
2129AddChild("delete message", [=] { Visit(M); });
2130
2131if (D->isIneligibleOrNotSelected())
2132OS << (isa<CXXDestructorDecl>(D) ? " not_selected" : " ineligible");
2133
2134if (const auto *FPT = D->getType()->getAs<FunctionProtoType>()) {
2135FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
2136switch (EPI.ExceptionSpec.Type) {
2137default:
2138break;
2139case EST_Unevaluated:
2140OS << " noexcept-unevaluated " << EPI.ExceptionSpec.SourceDecl;
2141break;
2142case EST_Uninstantiated:
2143OS << " noexcept-uninstantiated " << EPI.ExceptionSpec.SourceTemplate;
2144break;
2145}
2146}
2147
2148if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
2149if (MD->size_overridden_methods() != 0) {
2150auto dumpOverride = [=](const CXXMethodDecl *D) {
2151SplitQualType T_split = D->getType().split();
2152OS << D << " " << D->getParent()->getName() << "::" << D->getDeclName()
2153<< " '" << QualType::getAsString(T_split, PrintPolicy) << "'";
2154};
2155
2156AddChild([=] {
2157auto Overrides = MD->overridden_methods();
2158OS << "Overrides: [ ";
2159dumpOverride(*Overrides.begin());
2160for (const auto *Override : llvm::drop_begin(Overrides)) {
2161OS << ", ";
2162dumpOverride(Override);
2163}
2164OS << " ]";
2165});
2166}
2167}
2168
2169if (!D->isInlineSpecified() && D->isInlined()) {
2170OS << " implicit-inline";
2171}
2172// Since NumParams comes from the FunctionProtoType of the FunctionDecl and
2173// the Params are set later, it is possible for a dump during debugging to
2174// encounter a FunctionDecl that has been created but hasn't been assigned
2175// ParmVarDecls yet.
2176if (!D->param_empty() && !D->param_begin())
2177OS << " <<<NULL params x " << D->getNumParams() << ">>>";
2178
2179if (const auto *Instance = D->getInstantiatedFromMemberFunction()) {
2180OS << " instantiated_from";
2181dumpPointer(Instance);
2182}
2183}
2184
2185void TextNodeDumper::VisitCXXDeductionGuideDecl(
2186const CXXDeductionGuideDecl *D) {
2187VisitFunctionDecl(D);
2188switch (D->getDeductionCandidateKind()) {
2189case DeductionCandidate::Normal:
2190case DeductionCandidate::Copy:
2191return;
2192case DeductionCandidate::Aggregate:
2193OS << " aggregate ";
2194break;
2195}
2196}
2197
2198void TextNodeDumper::VisitLifetimeExtendedTemporaryDecl(
2199const LifetimeExtendedTemporaryDecl *D) {
2200OS << " extended by ";
2201dumpBareDeclRef(D->getExtendingDecl());
2202OS << " mangling ";
2203{
2204ColorScope Color(OS, ShowColors, ValueColor);
2205OS << D->getManglingNumber();
2206}
2207}
2208
2209void TextNodeDumper::VisitFieldDecl(const FieldDecl *D) {
2210dumpName(D);
2211dumpType(D->getType());
2212if (D->isMutable())
2213OS << " mutable";
2214if (D->isModulePrivate())
2215OS << " __module_private__";
2216}
2217
2218void TextNodeDumper::VisitVarDecl(const VarDecl *D) {
2219dumpNestedNameSpecifier(D->getQualifier());
2220dumpName(D);
2221if (const auto *P = dyn_cast<ParmVarDecl>(D);
2222P && P->isExplicitObjectParameter())
2223OS << " this";
2224
2225dumpType(D->getType());
2226dumpTemplateSpecializationKind(D->getTemplateSpecializationKind());
2227StorageClass SC = D->getStorageClass();
2228if (SC != SC_None)
2229OS << ' ' << VarDecl::getStorageClassSpecifierString(SC);
2230switch (D->getTLSKind()) {
2231case VarDecl::TLS_None:
2232break;
2233case VarDecl::TLS_Static:
2234OS << " tls";
2235break;
2236case VarDecl::TLS_Dynamic:
2237OS << " tls_dynamic";
2238break;
2239}
2240if (D->isModulePrivate())
2241OS << " __module_private__";
2242if (D->isNRVOVariable())
2243OS << " nrvo";
2244if (D->isInline())
2245OS << " inline";
2246if (D->isConstexpr())
2247OS << " constexpr";
2248if (D->hasInit()) {
2249switch (D->getInitStyle()) {
2250case VarDecl::CInit:
2251OS << " cinit";
2252break;
2253case VarDecl::CallInit:
2254OS << " callinit";
2255break;
2256case VarDecl::ListInit:
2257OS << " listinit";
2258break;
2259case VarDecl::ParenListInit:
2260OS << " parenlistinit";
2261}
2262}
2263if (D->needsDestruction(D->getASTContext()))
2264OS << " destroyed";
2265if (D->isParameterPack())
2266OS << " pack";
2267
2268if (D->hasInit()) {
2269const Expr *E = D->getInit();
2270// Only dump the value of constexpr VarDecls for now.
2271if (E && !E->isValueDependent() && D->isConstexpr() &&
2272!D->getType()->isDependentType()) {
2273const APValue *Value = D->evaluateValue();
2274if (Value)
2275AddChild("value", [=] { Visit(*Value, E->getType()); });
2276}
2277}
2278}
2279
2280void TextNodeDumper::VisitBindingDecl(const BindingDecl *D) {
2281dumpName(D);
2282dumpType(D->getType());
2283}
2284
2285void TextNodeDumper::VisitCapturedDecl(const CapturedDecl *D) {
2286if (D->isNothrow())
2287OS << " nothrow";
2288}
2289
2290void TextNodeDumper::VisitImportDecl(const ImportDecl *D) {
2291OS << ' ' << D->getImportedModule()->getFullModuleName();
2292
2293for (Decl *InitD :
2294D->getASTContext().getModuleInitializers(D->getImportedModule()))
2295dumpDeclRef(InitD, "initializer");
2296}
2297
2298void TextNodeDumper::VisitPragmaCommentDecl(const PragmaCommentDecl *D) {
2299OS << ' ';
2300switch (D->getCommentKind()) {
2301case PCK_Unknown:
2302llvm_unreachable("unexpected pragma comment kind");
2303case PCK_Compiler:
2304OS << "compiler";
2305break;
2306case PCK_ExeStr:
2307OS << "exestr";
2308break;
2309case PCK_Lib:
2310OS << "lib";
2311break;
2312case PCK_Linker:
2313OS << "linker";
2314break;
2315case PCK_User:
2316OS << "user";
2317break;
2318}
2319StringRef Arg = D->getArg();
2320if (!Arg.empty())
2321OS << " \"" << Arg << "\"";
2322}
2323
2324void TextNodeDumper::VisitPragmaDetectMismatchDecl(
2325const PragmaDetectMismatchDecl *D) {
2326OS << " \"" << D->getName() << "\" \"" << D->getValue() << "\"";
2327}
2328
2329void TextNodeDumper::VisitOMPExecutableDirective(
2330const OMPExecutableDirective *D) {
2331if (D->isStandaloneDirective())
2332OS << " openmp_standalone_directive";
2333}
2334
2335void TextNodeDumper::VisitOMPDeclareReductionDecl(
2336const OMPDeclareReductionDecl *D) {
2337dumpName(D);
2338dumpType(D->getType());
2339OS << " combiner";
2340dumpPointer(D->getCombiner());
2341if (const auto *Initializer = D->getInitializer()) {
2342OS << " initializer";
2343dumpPointer(Initializer);
2344switch (D->getInitializerKind()) {
2345case OMPDeclareReductionInitKind::Direct:
2346OS << " omp_priv = ";
2347break;
2348case OMPDeclareReductionInitKind::Copy:
2349OS << " omp_priv ()";
2350break;
2351case OMPDeclareReductionInitKind::Call:
2352break;
2353}
2354}
2355}
2356
2357void TextNodeDumper::VisitOMPRequiresDecl(const OMPRequiresDecl *D) {
2358for (const auto *C : D->clauselists()) {
2359AddChild([=] {
2360if (!C) {
2361ColorScope Color(OS, ShowColors, NullColor);
2362OS << "<<<NULL>>> OMPClause";
2363return;
2364}
2365{
2366ColorScope Color(OS, ShowColors, AttrColor);
2367StringRef ClauseName(
2368llvm::omp::getOpenMPClauseName(C->getClauseKind()));
2369OS << "OMP" << ClauseName.substr(/*Start=*/0, /*N=*/1).upper()
2370<< ClauseName.drop_front() << "Clause";
2371}
2372dumpPointer(C);
2373dumpSourceRange(SourceRange(C->getBeginLoc(), C->getEndLoc()));
2374});
2375}
2376}
2377
2378void TextNodeDumper::VisitOMPCapturedExprDecl(const OMPCapturedExprDecl *D) {
2379dumpName(D);
2380dumpType(D->getType());
2381}
2382
2383void TextNodeDumper::VisitNamespaceDecl(const NamespaceDecl *D) {
2384dumpName(D);
2385if (D->isInline())
2386OS << " inline";
2387if (D->isNested())
2388OS << " nested";
2389if (!D->isOriginalNamespace())
2390dumpDeclRef(D->getOriginalNamespace(), "original");
2391}
2392
2393void TextNodeDumper::VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) {
2394OS << ' ';
2395dumpBareDeclRef(D->getNominatedNamespace());
2396}
2397
2398void TextNodeDumper::VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) {
2399dumpName(D);
2400dumpDeclRef(D->getAliasedNamespace());
2401}
2402
2403void TextNodeDumper::VisitTypeAliasDecl(const TypeAliasDecl *D) {
2404dumpName(D);
2405dumpType(D->getUnderlyingType());
2406}
2407
2408void TextNodeDumper::VisitTypeAliasTemplateDecl(
2409const TypeAliasTemplateDecl *D) {
2410dumpName(D);
2411}
2412
2413void TextNodeDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) {
2414VisitRecordDecl(D);
2415if (const auto *Instance = D->getInstantiatedFromMemberClass()) {
2416OS << " instantiated_from";
2417dumpPointer(Instance);
2418}
2419if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D))
2420dumpTemplateSpecializationKind(CTSD->getSpecializationKind());
2421
2422dumpNestedNameSpecifier(D->getQualifier());
2423
2424if (!D->isCompleteDefinition())
2425return;
2426
2427AddChild([=] {
2428{
2429ColorScope Color(OS, ShowColors, DeclKindNameColor);
2430OS << "DefinitionData";
2431}
2432#define FLAG(fn, name) \
2433if (D->fn()) \
2434OS << " " #name;
2435FLAG(isParsingBaseSpecifiers, parsing_base_specifiers);
2436
2437FLAG(isGenericLambda, generic);
2438FLAG(isLambda, lambda);
2439
2440FLAG(isAnonymousStructOrUnion, is_anonymous);
2441FLAG(canPassInRegisters, pass_in_registers);
2442FLAG(isEmpty, empty);
2443FLAG(isAggregate, aggregate);
2444FLAG(isStandardLayout, standard_layout);
2445FLAG(isTriviallyCopyable, trivially_copyable);
2446FLAG(isPOD, pod);
2447FLAG(isTrivial, trivial);
2448FLAG(isPolymorphic, polymorphic);
2449FLAG(isAbstract, abstract);
2450FLAG(isLiteral, literal);
2451
2452FLAG(hasUserDeclaredConstructor, has_user_declared_ctor);
2453FLAG(hasConstexprNonCopyMoveConstructor, has_constexpr_non_copy_move_ctor);
2454FLAG(hasMutableFields, has_mutable_fields);
2455FLAG(hasVariantMembers, has_variant_members);
2456FLAG(allowConstDefaultInit, can_const_default_init);
2457
2458AddChild([=] {
2459{
2460ColorScope Color(OS, ShowColors, DeclKindNameColor);
2461OS << "DefaultConstructor";
2462}
2463FLAG(hasDefaultConstructor, exists);
2464FLAG(hasTrivialDefaultConstructor, trivial);
2465FLAG(hasNonTrivialDefaultConstructor, non_trivial);
2466FLAG(hasUserProvidedDefaultConstructor, user_provided);
2467FLAG(hasConstexprDefaultConstructor, constexpr);
2468FLAG(needsImplicitDefaultConstructor, needs_implicit);
2469FLAG(defaultedDefaultConstructorIsConstexpr, defaulted_is_constexpr);
2470});
2471
2472AddChild([=] {
2473{
2474ColorScope Color(OS, ShowColors, DeclKindNameColor);
2475OS << "CopyConstructor";
2476}
2477FLAG(hasSimpleCopyConstructor, simple);
2478FLAG(hasTrivialCopyConstructor, trivial);
2479FLAG(hasNonTrivialCopyConstructor, non_trivial);
2480FLAG(hasUserDeclaredCopyConstructor, user_declared);
2481FLAG(hasCopyConstructorWithConstParam, has_const_param);
2482FLAG(needsImplicitCopyConstructor, needs_implicit);
2483FLAG(needsOverloadResolutionForCopyConstructor,
2484needs_overload_resolution);
2485if (!D->needsOverloadResolutionForCopyConstructor())
2486FLAG(defaultedCopyConstructorIsDeleted, defaulted_is_deleted);
2487FLAG(implicitCopyConstructorHasConstParam, implicit_has_const_param);
2488});
2489
2490AddChild([=] {
2491{
2492ColorScope Color(OS, ShowColors, DeclKindNameColor);
2493OS << "MoveConstructor";
2494}
2495FLAG(hasMoveConstructor, exists);
2496FLAG(hasSimpleMoveConstructor, simple);
2497FLAG(hasTrivialMoveConstructor, trivial);
2498FLAG(hasNonTrivialMoveConstructor, non_trivial);
2499FLAG(hasUserDeclaredMoveConstructor, user_declared);
2500FLAG(needsImplicitMoveConstructor, needs_implicit);
2501FLAG(needsOverloadResolutionForMoveConstructor,
2502needs_overload_resolution);
2503if (!D->needsOverloadResolutionForMoveConstructor())
2504FLAG(defaultedMoveConstructorIsDeleted, defaulted_is_deleted);
2505});
2506
2507AddChild([=] {
2508{
2509ColorScope Color(OS, ShowColors, DeclKindNameColor);
2510OS << "CopyAssignment";
2511}
2512FLAG(hasSimpleCopyAssignment, simple);
2513FLAG(hasTrivialCopyAssignment, trivial);
2514FLAG(hasNonTrivialCopyAssignment, non_trivial);
2515FLAG(hasCopyAssignmentWithConstParam, has_const_param);
2516FLAG(hasUserDeclaredCopyAssignment, user_declared);
2517FLAG(needsImplicitCopyAssignment, needs_implicit);
2518FLAG(needsOverloadResolutionForCopyAssignment, needs_overload_resolution);
2519FLAG(implicitCopyAssignmentHasConstParam, implicit_has_const_param);
2520});
2521
2522AddChild([=] {
2523{
2524ColorScope Color(OS, ShowColors, DeclKindNameColor);
2525OS << "MoveAssignment";
2526}
2527FLAG(hasMoveAssignment, exists);
2528FLAG(hasSimpleMoveAssignment, simple);
2529FLAG(hasTrivialMoveAssignment, trivial);
2530FLAG(hasNonTrivialMoveAssignment, non_trivial);
2531FLAG(hasUserDeclaredMoveAssignment, user_declared);
2532FLAG(needsImplicitMoveAssignment, needs_implicit);
2533FLAG(needsOverloadResolutionForMoveAssignment, needs_overload_resolution);
2534});
2535
2536AddChild([=] {
2537{
2538ColorScope Color(OS, ShowColors, DeclKindNameColor);
2539OS << "Destructor";
2540}
2541FLAG(hasSimpleDestructor, simple);
2542FLAG(hasIrrelevantDestructor, irrelevant);
2543FLAG(hasTrivialDestructor, trivial);
2544FLAG(hasNonTrivialDestructor, non_trivial);
2545FLAG(hasUserDeclaredDestructor, user_declared);
2546FLAG(hasConstexprDestructor, constexpr);
2547FLAG(needsImplicitDestructor, needs_implicit);
2548FLAG(needsOverloadResolutionForDestructor, needs_overload_resolution);
2549if (!D->needsOverloadResolutionForDestructor())
2550FLAG(defaultedDestructorIsDeleted, defaulted_is_deleted);
2551});
2552});
2553
2554for (const auto &I : D->bases()) {
2555AddChild([=] {
2556if (I.isVirtual())
2557OS << "virtual ";
2558dumpAccessSpecifier(I.getAccessSpecifier());
2559dumpType(I.getType());
2560if (I.isPackExpansion())
2561OS << "...";
2562});
2563}
2564}
2565
2566void TextNodeDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
2567dumpName(D);
2568}
2569
2570void TextNodeDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) {
2571dumpName(D);
2572}
2573
2574void TextNodeDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) {
2575dumpName(D);
2576}
2577
2578void TextNodeDumper::VisitBuiltinTemplateDecl(const BuiltinTemplateDecl *D) {
2579dumpName(D);
2580}
2581
2582void TextNodeDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
2583if (const auto *TC = D->getTypeConstraint()) {
2584OS << " ";
2585dumpBareDeclRef(TC->getNamedConcept());
2586if (TC->getNamedConcept() != TC->getFoundDecl()) {
2587OS << " (";
2588dumpBareDeclRef(TC->getFoundDecl());
2589OS << ")";
2590}
2591} else if (D->wasDeclaredWithTypename())
2592OS << " typename";
2593else
2594OS << " class";
2595OS << " depth " << D->getDepth() << " index " << D->getIndex();
2596if (D->isParameterPack())
2597OS << " ...";
2598dumpName(D);
2599}
2600
2601void TextNodeDumper::VisitNonTypeTemplateParmDecl(
2602const NonTypeTemplateParmDecl *D) {
2603dumpType(D->getType());
2604OS << " depth " << D->getDepth() << " index " << D->getIndex();
2605if (D->isParameterPack())
2606OS << " ...";
2607dumpName(D);
2608}
2609
2610void TextNodeDumper::VisitTemplateTemplateParmDecl(
2611const TemplateTemplateParmDecl *D) {
2612OS << " depth " << D->getDepth() << " index " << D->getIndex();
2613if (D->isParameterPack())
2614OS << " ...";
2615dumpName(D);
2616}
2617
2618void TextNodeDumper::VisitUsingDecl(const UsingDecl *D) {
2619OS << ' ';
2620if (D->getQualifier())
2621D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
2622OS << D->getDeclName();
2623dumpNestedNameSpecifier(D->getQualifier());
2624}
2625
2626void TextNodeDumper::VisitUsingEnumDecl(const UsingEnumDecl *D) {
2627OS << ' ';
2628dumpBareDeclRef(D->getEnumDecl());
2629}
2630
2631void TextNodeDumper::VisitUnresolvedUsingTypenameDecl(
2632const UnresolvedUsingTypenameDecl *D) {
2633OS << ' ';
2634if (D->getQualifier())
2635D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
2636OS << D->getDeclName();
2637}
2638
2639void TextNodeDumper::VisitUnresolvedUsingValueDecl(
2640const UnresolvedUsingValueDecl *D) {
2641OS << ' ';
2642if (D->getQualifier())
2643D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
2644OS << D->getDeclName();
2645dumpType(D->getType());
2646}
2647
2648void TextNodeDumper::VisitUsingShadowDecl(const UsingShadowDecl *D) {
2649OS << ' ';
2650dumpBareDeclRef(D->getTargetDecl());
2651}
2652
2653void TextNodeDumper::VisitConstructorUsingShadowDecl(
2654const ConstructorUsingShadowDecl *D) {
2655if (D->constructsVirtualBase())
2656OS << " virtual";
2657
2658AddChild([=] {
2659OS << "target ";
2660dumpBareDeclRef(D->getTargetDecl());
2661});
2662
2663AddChild([=] {
2664OS << "nominated ";
2665dumpBareDeclRef(D->getNominatedBaseClass());
2666OS << ' ';
2667dumpBareDeclRef(D->getNominatedBaseClassShadowDecl());
2668});
2669
2670AddChild([=] {
2671OS << "constructed ";
2672dumpBareDeclRef(D->getConstructedBaseClass());
2673OS << ' ';
2674dumpBareDeclRef(D->getConstructedBaseClassShadowDecl());
2675});
2676}
2677
2678void TextNodeDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *D) {
2679switch (D->getLanguage()) {
2680case LinkageSpecLanguageIDs::C:
2681OS << " C";
2682break;
2683case LinkageSpecLanguageIDs::CXX:
2684OS << " C++";
2685break;
2686}
2687}
2688
2689void TextNodeDumper::VisitAccessSpecDecl(const AccessSpecDecl *D) {
2690OS << ' ';
2691dumpAccessSpecifier(D->getAccess());
2692}
2693
2694void TextNodeDumper::VisitFriendDecl(const FriendDecl *D) {
2695if (TypeSourceInfo *T = D->getFriendType())
2696dumpType(T->getType());
2697}
2698
2699void TextNodeDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) {
2700dumpName(D);
2701dumpType(D->getType());
2702if (D->getSynthesize())
2703OS << " synthesize";
2704
2705switch (D->getAccessControl()) {
2706case ObjCIvarDecl::None:
2707OS << " none";
2708break;
2709case ObjCIvarDecl::Private:
2710OS << " private";
2711break;
2712case ObjCIvarDecl::Protected:
2713OS << " protected";
2714break;
2715case ObjCIvarDecl::Public:
2716OS << " public";
2717break;
2718case ObjCIvarDecl::Package:
2719OS << " package";
2720break;
2721}
2722}
2723
2724void TextNodeDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) {
2725if (D->isInstanceMethod())
2726OS << " -";
2727else
2728OS << " +";
2729dumpName(D);
2730dumpType(D->getReturnType());
2731
2732if (D->isVariadic())
2733OS << " variadic";
2734}
2735
2736void TextNodeDumper::VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D) {
2737dumpName(D);
2738switch (D->getVariance()) {
2739case ObjCTypeParamVariance::Invariant:
2740break;
2741
2742case ObjCTypeParamVariance::Covariant:
2743OS << " covariant";
2744break;
2745
2746case ObjCTypeParamVariance::Contravariant:
2747OS << " contravariant";
2748break;
2749}
2750
2751if (D->hasExplicitBound())
2752OS << " bounded";
2753dumpType(D->getUnderlyingType());
2754}
2755
2756void TextNodeDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
2757dumpName(D);
2758dumpDeclRef(D->getClassInterface());
2759dumpDeclRef(D->getImplementation());
2760for (const auto *P : D->protocols())
2761dumpDeclRef(P);
2762}
2763
2764void TextNodeDumper::VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) {
2765dumpName(D);
2766dumpDeclRef(D->getClassInterface());
2767dumpDeclRef(D->getCategoryDecl());
2768}
2769
2770void TextNodeDumper::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
2771dumpName(D);
2772
2773for (const auto *Child : D->protocols())
2774dumpDeclRef(Child);
2775}
2776
2777void TextNodeDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
2778dumpName(D);
2779dumpDeclRef(D->getSuperClass(), "super");
2780
2781dumpDeclRef(D->getImplementation());
2782for (const auto *Child : D->protocols())
2783dumpDeclRef(Child);
2784}
2785
2786void TextNodeDumper::VisitObjCImplementationDecl(
2787const ObjCImplementationDecl *D) {
2788dumpName(D);
2789dumpDeclRef(D->getSuperClass(), "super");
2790dumpDeclRef(D->getClassInterface());
2791}
2792
2793void TextNodeDumper::VisitObjCCompatibleAliasDecl(
2794const ObjCCompatibleAliasDecl *D) {
2795dumpName(D);
2796dumpDeclRef(D->getClassInterface());
2797}
2798
2799void TextNodeDumper::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
2800dumpName(D);
2801dumpType(D->getType());
2802
2803if (D->getPropertyImplementation() == ObjCPropertyDecl::Required)
2804OS << " required";
2805else if (D->getPropertyImplementation() == ObjCPropertyDecl::Optional)
2806OS << " optional";
2807
2808ObjCPropertyAttribute::Kind Attrs = D->getPropertyAttributes();
2809if (Attrs != ObjCPropertyAttribute::kind_noattr) {
2810if (Attrs & ObjCPropertyAttribute::kind_readonly)
2811OS << " readonly";
2812if (Attrs & ObjCPropertyAttribute::kind_assign)
2813OS << " assign";
2814if (Attrs & ObjCPropertyAttribute::kind_readwrite)
2815OS << " readwrite";
2816if (Attrs & ObjCPropertyAttribute::kind_retain)
2817OS << " retain";
2818if (Attrs & ObjCPropertyAttribute::kind_copy)
2819OS << " copy";
2820if (Attrs & ObjCPropertyAttribute::kind_nonatomic)
2821OS << " nonatomic";
2822if (Attrs & ObjCPropertyAttribute::kind_atomic)
2823OS << " atomic";
2824if (Attrs & ObjCPropertyAttribute::kind_weak)
2825OS << " weak";
2826if (Attrs & ObjCPropertyAttribute::kind_strong)
2827OS << " strong";
2828if (Attrs & ObjCPropertyAttribute::kind_unsafe_unretained)
2829OS << " unsafe_unretained";
2830if (Attrs & ObjCPropertyAttribute::kind_class)
2831OS << " class";
2832if (Attrs & ObjCPropertyAttribute::kind_direct)
2833OS << " direct";
2834if (Attrs & ObjCPropertyAttribute::kind_getter)
2835dumpDeclRef(D->getGetterMethodDecl(), "getter");
2836if (Attrs & ObjCPropertyAttribute::kind_setter)
2837dumpDeclRef(D->getSetterMethodDecl(), "setter");
2838}
2839}
2840
2841void TextNodeDumper::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {
2842dumpName(D->getPropertyDecl());
2843if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize)
2844OS << " synthesize";
2845else
2846OS << " dynamic";
2847dumpDeclRef(D->getPropertyDecl());
2848dumpDeclRef(D->getPropertyIvarDecl());
2849}
2850
2851void TextNodeDumper::VisitBlockDecl(const BlockDecl *D) {
2852if (D->isVariadic())
2853OS << " variadic";
2854
2855if (D->capturesCXXThis())
2856OS << " captures_this";
2857}
2858
2859void TextNodeDumper::VisitConceptDecl(const ConceptDecl *D) {
2860dumpName(D);
2861}
2862
2863void TextNodeDumper::VisitCompoundStmt(const CompoundStmt *S) {
2864VisitStmt(S);
2865if (S->hasStoredFPFeatures())
2866printFPOptions(S->getStoredFPFeatures());
2867}
2868
2869void TextNodeDumper::VisitHLSLBufferDecl(const HLSLBufferDecl *D) {
2870if (D->isCBuffer())
2871OS << " cbuffer";
2872else
2873OS << " tbuffer";
2874dumpName(D);
2875}
2876
2877void TextNodeDumper::VisitOpenACCConstructStmt(const OpenACCConstructStmt *S) {
2878OS << " " << S->getDirectiveKind();
2879}
2880void TextNodeDumper::VisitOpenACCLoopConstruct(const OpenACCLoopConstruct *S) {
2881
2882if (S->isOrphanedLoopConstruct())
2883OS << " <orphan>";
2884else
2885OS << " parent: " << S->getParentComputeConstruct();
2886}
2887
2888void TextNodeDumper::VisitEmbedExpr(const EmbedExpr *S) {
2889AddChild("begin", [=] { OS << S->getStartingElementPos(); });
2890AddChild("number of elements", [=] { OS << S->getDataElementCount(); });
2891}
2892