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