1e5dd7070Spatrick #include "clang/AST/JSONNodeDumper.h"
2*12c85518Srobert #include "clang/AST/Type.h"
3ec727ea7Spatrick #include "clang/Basic/SourceManager.h"
4ec727ea7Spatrick #include "clang/Basic/Specifiers.h"
5e5dd7070Spatrick #include "clang/Lex/Lexer.h"
6*12c85518Srobert #include <optional>
7e5dd7070Spatrick 
8e5dd7070Spatrick using namespace clang;
9e5dd7070Spatrick 
addPreviousDeclaration(const Decl * D)10e5dd7070Spatrick void JSONNodeDumper::addPreviousDeclaration(const Decl *D) {
11e5dd7070Spatrick   switch (D->getKind()) {
12e5dd7070Spatrick #define DECL(DERIVED, BASE)                                                    \
13e5dd7070Spatrick   case Decl::DERIVED:                                                          \
14e5dd7070Spatrick     return writePreviousDeclImpl(cast<DERIVED##Decl>(D));
15e5dd7070Spatrick #define ABSTRACT_DECL(DECL)
16e5dd7070Spatrick #include "clang/AST/DeclNodes.inc"
17e5dd7070Spatrick #undef ABSTRACT_DECL
18e5dd7070Spatrick #undef DECL
19e5dd7070Spatrick   }
20e5dd7070Spatrick   llvm_unreachable("Decl that isn't part of DeclNodes.inc!");
21e5dd7070Spatrick }
22e5dd7070Spatrick 
Visit(const Attr * A)23e5dd7070Spatrick void JSONNodeDumper::Visit(const Attr *A) {
24e5dd7070Spatrick   const char *AttrName = nullptr;
25e5dd7070Spatrick   switch (A->getKind()) {
26e5dd7070Spatrick #define ATTR(X)                                                                \
27e5dd7070Spatrick   case attr::X:                                                                \
28e5dd7070Spatrick     AttrName = #X"Attr";                                                       \
29e5dd7070Spatrick     break;
30e5dd7070Spatrick #include "clang/Basic/AttrList.inc"
31e5dd7070Spatrick #undef ATTR
32e5dd7070Spatrick   }
33e5dd7070Spatrick   JOS.attribute("id", createPointerRepresentation(A));
34e5dd7070Spatrick   JOS.attribute("kind", AttrName);
35e5dd7070Spatrick   JOS.attributeObject("range", [A, this] { writeSourceRange(A->getRange()); });
36e5dd7070Spatrick   attributeOnlyIfTrue("inherited", A->isInherited());
37e5dd7070Spatrick   attributeOnlyIfTrue("implicit", A->isImplicit());
38e5dd7070Spatrick 
39e5dd7070Spatrick   // FIXME: it would be useful for us to output the spelling kind as well as
40e5dd7070Spatrick   // the actual spelling. This would allow us to distinguish between the
41e5dd7070Spatrick   // various attribute syntaxes, but we don't currently track that information
42e5dd7070Spatrick   // within the AST.
43e5dd7070Spatrick   //JOS.attribute("spelling", A->getSpelling());
44e5dd7070Spatrick 
45e5dd7070Spatrick   InnerAttrVisitor::Visit(A);
46e5dd7070Spatrick }
47e5dd7070Spatrick 
Visit(const Stmt * S)48e5dd7070Spatrick void JSONNodeDumper::Visit(const Stmt *S) {
49e5dd7070Spatrick   if (!S)
50e5dd7070Spatrick     return;
51e5dd7070Spatrick 
52e5dd7070Spatrick   JOS.attribute("id", createPointerRepresentation(S));
53e5dd7070Spatrick   JOS.attribute("kind", S->getStmtClassName());
54e5dd7070Spatrick   JOS.attributeObject("range",
55e5dd7070Spatrick                       [S, this] { writeSourceRange(S->getSourceRange()); });
56e5dd7070Spatrick 
57e5dd7070Spatrick   if (const auto *E = dyn_cast<Expr>(S)) {
58e5dd7070Spatrick     JOS.attribute("type", createQualType(E->getType()));
59e5dd7070Spatrick     const char *Category = nullptr;
60e5dd7070Spatrick     switch (E->getValueKind()) {
61e5dd7070Spatrick     case VK_LValue: Category = "lvalue"; break;
62e5dd7070Spatrick     case VK_XValue: Category = "xvalue"; break;
63a9ac8606Spatrick     case VK_PRValue:
64a9ac8606Spatrick       Category = "prvalue";
65a9ac8606Spatrick       break;
66e5dd7070Spatrick     }
67e5dd7070Spatrick     JOS.attribute("valueCategory", Category);
68e5dd7070Spatrick   }
69e5dd7070Spatrick   InnerStmtVisitor::Visit(S);
70e5dd7070Spatrick }
71e5dd7070Spatrick 
Visit(const Type * T)72e5dd7070Spatrick void JSONNodeDumper::Visit(const Type *T) {
73e5dd7070Spatrick   JOS.attribute("id", createPointerRepresentation(T));
74e5dd7070Spatrick 
75e5dd7070Spatrick   if (!T)
76e5dd7070Spatrick     return;
77e5dd7070Spatrick 
78e5dd7070Spatrick   JOS.attribute("kind", (llvm::Twine(T->getTypeClassName()) + "Type").str());
79e5dd7070Spatrick   JOS.attribute("type", createQualType(QualType(T, 0), /*Desugar*/ false));
80ec727ea7Spatrick   attributeOnlyIfTrue("containsErrors", T->containsErrors());
81e5dd7070Spatrick   attributeOnlyIfTrue("isDependent", T->isDependentType());
82e5dd7070Spatrick   attributeOnlyIfTrue("isInstantiationDependent",
83e5dd7070Spatrick                       T->isInstantiationDependentType());
84e5dd7070Spatrick   attributeOnlyIfTrue("isVariablyModified", T->isVariablyModifiedType());
85e5dd7070Spatrick   attributeOnlyIfTrue("containsUnexpandedPack",
86e5dd7070Spatrick                       T->containsUnexpandedParameterPack());
87e5dd7070Spatrick   attributeOnlyIfTrue("isImported", T->isFromAST());
88e5dd7070Spatrick   InnerTypeVisitor::Visit(T);
89e5dd7070Spatrick }
90e5dd7070Spatrick 
Visit(QualType T)91e5dd7070Spatrick void JSONNodeDumper::Visit(QualType T) {
92e5dd7070Spatrick   JOS.attribute("id", createPointerRepresentation(T.getAsOpaquePtr()));
93e5dd7070Spatrick   JOS.attribute("kind", "QualType");
94e5dd7070Spatrick   JOS.attribute("type", createQualType(T));
95e5dd7070Spatrick   JOS.attribute("qualifiers", T.split().Quals.getAsString());
96e5dd7070Spatrick }
97e5dd7070Spatrick 
Visit(const Decl * D)98e5dd7070Spatrick void JSONNodeDumper::Visit(const Decl *D) {
99e5dd7070Spatrick   JOS.attribute("id", createPointerRepresentation(D));
100e5dd7070Spatrick 
101e5dd7070Spatrick   if (!D)
102e5dd7070Spatrick     return;
103e5dd7070Spatrick 
104e5dd7070Spatrick   JOS.attribute("kind", (llvm::Twine(D->getDeclKindName()) + "Decl").str());
105e5dd7070Spatrick   JOS.attributeObject("loc",
106e5dd7070Spatrick                       [D, this] { writeSourceLocation(D->getLocation()); });
107e5dd7070Spatrick   JOS.attributeObject("range",
108e5dd7070Spatrick                       [D, this] { writeSourceRange(D->getSourceRange()); });
109e5dd7070Spatrick   attributeOnlyIfTrue("isImplicit", D->isImplicit());
110e5dd7070Spatrick   attributeOnlyIfTrue("isInvalid", D->isInvalidDecl());
111e5dd7070Spatrick 
112e5dd7070Spatrick   if (D->isUsed())
113e5dd7070Spatrick     JOS.attribute("isUsed", true);
114e5dd7070Spatrick   else if (D->isThisDeclarationReferenced())
115e5dd7070Spatrick     JOS.attribute("isReferenced", true);
116e5dd7070Spatrick 
117e5dd7070Spatrick   if (const auto *ND = dyn_cast<NamedDecl>(D))
118ec727ea7Spatrick     attributeOnlyIfTrue("isHidden", !ND->isUnconditionallyVisible());
119e5dd7070Spatrick 
120e5dd7070Spatrick   if (D->getLexicalDeclContext() != D->getDeclContext()) {
121e5dd7070Spatrick     // Because of multiple inheritance, a DeclContext pointer does not produce
122e5dd7070Spatrick     // the same pointer representation as a Decl pointer that references the
123e5dd7070Spatrick     // same AST Node.
124e5dd7070Spatrick     const auto *ParentDeclContextDecl = dyn_cast<Decl>(D->getDeclContext());
125e5dd7070Spatrick     JOS.attribute("parentDeclContextId",
126e5dd7070Spatrick                   createPointerRepresentation(ParentDeclContextDecl));
127e5dd7070Spatrick   }
128e5dd7070Spatrick 
129e5dd7070Spatrick   addPreviousDeclaration(D);
130e5dd7070Spatrick   InnerDeclVisitor::Visit(D);
131e5dd7070Spatrick }
132e5dd7070Spatrick 
Visit(const comments::Comment * C,const comments::FullComment * FC)133e5dd7070Spatrick void JSONNodeDumper::Visit(const comments::Comment *C,
134e5dd7070Spatrick                            const comments::FullComment *FC) {
135e5dd7070Spatrick   if (!C)
136e5dd7070Spatrick     return;
137e5dd7070Spatrick 
138e5dd7070Spatrick   JOS.attribute("id", createPointerRepresentation(C));
139e5dd7070Spatrick   JOS.attribute("kind", C->getCommentKindName());
140e5dd7070Spatrick   JOS.attributeObject("loc",
141e5dd7070Spatrick                       [C, this] { writeSourceLocation(C->getLocation()); });
142e5dd7070Spatrick   JOS.attributeObject("range",
143e5dd7070Spatrick                       [C, this] { writeSourceRange(C->getSourceRange()); });
144e5dd7070Spatrick 
145e5dd7070Spatrick   InnerCommentVisitor::visit(C, FC);
146e5dd7070Spatrick }
147e5dd7070Spatrick 
Visit(const TemplateArgument & TA,SourceRange R,const Decl * From,StringRef Label)148e5dd7070Spatrick void JSONNodeDumper::Visit(const TemplateArgument &TA, SourceRange R,
149e5dd7070Spatrick                            const Decl *From, StringRef Label) {
150e5dd7070Spatrick   JOS.attribute("kind", "TemplateArgument");
151e5dd7070Spatrick   if (R.isValid())
152e5dd7070Spatrick     JOS.attributeObject("range", [R, this] { writeSourceRange(R); });
153e5dd7070Spatrick 
154e5dd7070Spatrick   if (From)
155e5dd7070Spatrick     JOS.attribute(Label.empty() ? "fromDecl" : Label, createBareDeclRef(From));
156e5dd7070Spatrick 
157e5dd7070Spatrick   InnerTemplateArgVisitor::Visit(TA);
158e5dd7070Spatrick }
159e5dd7070Spatrick 
Visit(const CXXCtorInitializer * Init)160e5dd7070Spatrick void JSONNodeDumper::Visit(const CXXCtorInitializer *Init) {
161e5dd7070Spatrick   JOS.attribute("kind", "CXXCtorInitializer");
162e5dd7070Spatrick   if (Init->isAnyMemberInitializer())
163e5dd7070Spatrick     JOS.attribute("anyInit", createBareDeclRef(Init->getAnyMember()));
164e5dd7070Spatrick   else if (Init->isBaseInitializer())
165e5dd7070Spatrick     JOS.attribute("baseInit",
166e5dd7070Spatrick                   createQualType(QualType(Init->getBaseClass(), 0)));
167e5dd7070Spatrick   else if (Init->isDelegatingInitializer())
168e5dd7070Spatrick     JOS.attribute("delegatingInit",
169e5dd7070Spatrick                   createQualType(Init->getTypeSourceInfo()->getType()));
170e5dd7070Spatrick   else
171e5dd7070Spatrick     llvm_unreachable("Unknown initializer type");
172e5dd7070Spatrick }
173e5dd7070Spatrick 
Visit(const OMPClause * C)174e5dd7070Spatrick void JSONNodeDumper::Visit(const OMPClause *C) {}
175e5dd7070Spatrick 
Visit(const BlockDecl::Capture & C)176e5dd7070Spatrick void JSONNodeDumper::Visit(const BlockDecl::Capture &C) {
177e5dd7070Spatrick   JOS.attribute("kind", "Capture");
178e5dd7070Spatrick   attributeOnlyIfTrue("byref", C.isByRef());
179e5dd7070Spatrick   attributeOnlyIfTrue("nested", C.isNested());
180e5dd7070Spatrick   if (C.getVariable())
181e5dd7070Spatrick     JOS.attribute("var", createBareDeclRef(C.getVariable()));
182e5dd7070Spatrick }
183e5dd7070Spatrick 
Visit(const GenericSelectionExpr::ConstAssociation & A)184e5dd7070Spatrick void JSONNodeDumper::Visit(const GenericSelectionExpr::ConstAssociation &A) {
185e5dd7070Spatrick   JOS.attribute("associationKind", A.getTypeSourceInfo() ? "case" : "default");
186e5dd7070Spatrick   attributeOnlyIfTrue("selected", A.isSelected());
187e5dd7070Spatrick }
188e5dd7070Spatrick 
Visit(const concepts::Requirement * R)189a9ac8606Spatrick void JSONNodeDumper::Visit(const concepts::Requirement *R) {
190a9ac8606Spatrick   if (!R)
191a9ac8606Spatrick     return;
192a9ac8606Spatrick 
193a9ac8606Spatrick   switch (R->getKind()) {
194a9ac8606Spatrick   case concepts::Requirement::RK_Type:
195a9ac8606Spatrick     JOS.attribute("kind", "TypeRequirement");
196a9ac8606Spatrick     break;
197a9ac8606Spatrick   case concepts::Requirement::RK_Simple:
198a9ac8606Spatrick     JOS.attribute("kind", "SimpleRequirement");
199a9ac8606Spatrick     break;
200a9ac8606Spatrick   case concepts::Requirement::RK_Compound:
201a9ac8606Spatrick     JOS.attribute("kind", "CompoundRequirement");
202a9ac8606Spatrick     break;
203a9ac8606Spatrick   case concepts::Requirement::RK_Nested:
204a9ac8606Spatrick     JOS.attribute("kind", "NestedRequirement");
205a9ac8606Spatrick     break;
206a9ac8606Spatrick   }
207a9ac8606Spatrick 
208a9ac8606Spatrick   if (auto *ER = dyn_cast<concepts::ExprRequirement>(R))
209a9ac8606Spatrick     attributeOnlyIfTrue("noexcept", ER->hasNoexceptRequirement());
210a9ac8606Spatrick 
211a9ac8606Spatrick   attributeOnlyIfTrue("isDependent", R->isDependent());
212a9ac8606Spatrick   if (!R->isDependent())
213a9ac8606Spatrick     JOS.attribute("satisfied", R->isSatisfied());
214a9ac8606Spatrick   attributeOnlyIfTrue("containsUnexpandedPack",
215a9ac8606Spatrick                       R->containsUnexpandedParameterPack());
216a9ac8606Spatrick }
217a9ac8606Spatrick 
Visit(const APValue & Value,QualType Ty)218ec727ea7Spatrick void JSONNodeDumper::Visit(const APValue &Value, QualType Ty) {
219ec727ea7Spatrick   std::string Str;
220ec727ea7Spatrick   llvm::raw_string_ostream OS(Str);
221ec727ea7Spatrick   Value.printPretty(OS, Ctx, Ty);
222ec727ea7Spatrick   JOS.attribute("value", OS.str());
223ec727ea7Spatrick }
224ec727ea7Spatrick 
writeIncludeStack(PresumedLoc Loc,bool JustFirst)225e5dd7070Spatrick void JSONNodeDumper::writeIncludeStack(PresumedLoc Loc, bool JustFirst) {
226e5dd7070Spatrick   if (Loc.isInvalid())
227e5dd7070Spatrick     return;
228e5dd7070Spatrick 
229e5dd7070Spatrick   JOS.attributeBegin("includedFrom");
230e5dd7070Spatrick   JOS.objectBegin();
231e5dd7070Spatrick 
232e5dd7070Spatrick   if (!JustFirst) {
233e5dd7070Spatrick     // Walk the stack recursively, then print out the presumed location.
234e5dd7070Spatrick     writeIncludeStack(SM.getPresumedLoc(Loc.getIncludeLoc()));
235e5dd7070Spatrick   }
236e5dd7070Spatrick 
237e5dd7070Spatrick   JOS.attribute("file", Loc.getFilename());
238e5dd7070Spatrick   JOS.objectEnd();
239e5dd7070Spatrick   JOS.attributeEnd();
240e5dd7070Spatrick }
241e5dd7070Spatrick 
writeBareSourceLocation(SourceLocation Loc,bool IsSpelling)242e5dd7070Spatrick void JSONNodeDumper::writeBareSourceLocation(SourceLocation Loc,
243e5dd7070Spatrick                                              bool IsSpelling) {
244e5dd7070Spatrick   PresumedLoc Presumed = SM.getPresumedLoc(Loc);
245e5dd7070Spatrick   unsigned ActualLine = IsSpelling ? SM.getSpellingLineNumber(Loc)
246e5dd7070Spatrick                                    : SM.getExpansionLineNumber(Loc);
247e5dd7070Spatrick   StringRef ActualFile = SM.getBufferName(Loc);
248e5dd7070Spatrick 
249e5dd7070Spatrick   if (Presumed.isValid()) {
250e5dd7070Spatrick     JOS.attribute("offset", SM.getDecomposedLoc(Loc).second);
251e5dd7070Spatrick     if (LastLocFilename != ActualFile) {
252e5dd7070Spatrick       JOS.attribute("file", ActualFile);
253e5dd7070Spatrick       JOS.attribute("line", ActualLine);
254e5dd7070Spatrick     } else if (LastLocLine != ActualLine)
255e5dd7070Spatrick       JOS.attribute("line", ActualLine);
256e5dd7070Spatrick 
257e5dd7070Spatrick     StringRef PresumedFile = Presumed.getFilename();
258e5dd7070Spatrick     if (PresumedFile != ActualFile && LastLocPresumedFilename != PresumedFile)
259e5dd7070Spatrick       JOS.attribute("presumedFile", PresumedFile);
260e5dd7070Spatrick 
261e5dd7070Spatrick     unsigned PresumedLine = Presumed.getLine();
262e5dd7070Spatrick     if (ActualLine != PresumedLine && LastLocPresumedLine != PresumedLine)
263e5dd7070Spatrick       JOS.attribute("presumedLine", PresumedLine);
264e5dd7070Spatrick 
265e5dd7070Spatrick     JOS.attribute("col", Presumed.getColumn());
266e5dd7070Spatrick     JOS.attribute("tokLen",
267e5dd7070Spatrick                   Lexer::MeasureTokenLength(Loc, SM, Ctx.getLangOpts()));
268e5dd7070Spatrick     LastLocFilename = ActualFile;
269e5dd7070Spatrick     LastLocPresumedFilename = PresumedFile;
270e5dd7070Spatrick     LastLocPresumedLine = PresumedLine;
271e5dd7070Spatrick     LastLocLine = ActualLine;
272e5dd7070Spatrick 
273e5dd7070Spatrick     // Orthogonal to the file, line, and column de-duplication is whether the
274e5dd7070Spatrick     // given location was a result of an include. If so, print where the
275e5dd7070Spatrick     // include location came from.
276e5dd7070Spatrick     writeIncludeStack(SM.getPresumedLoc(Presumed.getIncludeLoc()),
277e5dd7070Spatrick                       /*JustFirst*/ true);
278e5dd7070Spatrick   }
279e5dd7070Spatrick }
280e5dd7070Spatrick 
writeSourceLocation(SourceLocation Loc)281e5dd7070Spatrick void JSONNodeDumper::writeSourceLocation(SourceLocation Loc) {
282e5dd7070Spatrick   SourceLocation Spelling = SM.getSpellingLoc(Loc);
283e5dd7070Spatrick   SourceLocation Expansion = SM.getExpansionLoc(Loc);
284e5dd7070Spatrick 
285e5dd7070Spatrick   if (Expansion != Spelling) {
286e5dd7070Spatrick     // If the expansion and the spelling are different, output subobjects
287e5dd7070Spatrick     // describing both locations.
288e5dd7070Spatrick     JOS.attributeObject("spellingLoc", [Spelling, this] {
289e5dd7070Spatrick       writeBareSourceLocation(Spelling, /*IsSpelling*/ true);
290e5dd7070Spatrick     });
291e5dd7070Spatrick     JOS.attributeObject("expansionLoc", [Expansion, Loc, this] {
292e5dd7070Spatrick       writeBareSourceLocation(Expansion, /*IsSpelling*/ false);
293e5dd7070Spatrick       // If there is a macro expansion, add extra information if the interesting
294e5dd7070Spatrick       // bit is the macro arg expansion.
295e5dd7070Spatrick       if (SM.isMacroArgExpansion(Loc))
296e5dd7070Spatrick         JOS.attribute("isMacroArgExpansion", true);
297e5dd7070Spatrick     });
298e5dd7070Spatrick   } else
299e5dd7070Spatrick     writeBareSourceLocation(Spelling, /*IsSpelling*/ true);
300e5dd7070Spatrick }
301e5dd7070Spatrick 
writeSourceRange(SourceRange R)302e5dd7070Spatrick void JSONNodeDumper::writeSourceRange(SourceRange R) {
303e5dd7070Spatrick   JOS.attributeObject("begin",
304e5dd7070Spatrick                       [R, this] { writeSourceLocation(R.getBegin()); });
305e5dd7070Spatrick   JOS.attributeObject("end", [R, this] { writeSourceLocation(R.getEnd()); });
306e5dd7070Spatrick }
307e5dd7070Spatrick 
createPointerRepresentation(const void * Ptr)308e5dd7070Spatrick std::string JSONNodeDumper::createPointerRepresentation(const void *Ptr) {
309e5dd7070Spatrick   // Because JSON stores integer values as signed 64-bit integers, trying to
310e5dd7070Spatrick   // represent them as such makes for very ugly pointer values in the resulting
311e5dd7070Spatrick   // output. Instead, we convert the value to hex and treat it as a string.
312e5dd7070Spatrick   return "0x" + llvm::utohexstr(reinterpret_cast<uint64_t>(Ptr), true);
313e5dd7070Spatrick }
314e5dd7070Spatrick 
createQualType(QualType QT,bool Desugar)315e5dd7070Spatrick llvm::json::Object JSONNodeDumper::createQualType(QualType QT, bool Desugar) {
316e5dd7070Spatrick   SplitQualType SQT = QT.split();
317e5dd7070Spatrick   llvm::json::Object Ret{{"qualType", QualType::getAsString(SQT, PrintPolicy)}};
318e5dd7070Spatrick 
319e5dd7070Spatrick   if (Desugar && !QT.isNull()) {
320e5dd7070Spatrick     SplitQualType DSQT = QT.getSplitDesugaredType();
321e5dd7070Spatrick     if (DSQT != SQT)
322e5dd7070Spatrick       Ret["desugaredQualType"] = QualType::getAsString(DSQT, PrintPolicy);
323e5dd7070Spatrick     if (const auto *TT = QT->getAs<TypedefType>())
324e5dd7070Spatrick       Ret["typeAliasDeclId"] = createPointerRepresentation(TT->getDecl());
325e5dd7070Spatrick   }
326e5dd7070Spatrick   return Ret;
327e5dd7070Spatrick }
328e5dd7070Spatrick 
writeBareDeclRef(const Decl * D)329e5dd7070Spatrick void JSONNodeDumper::writeBareDeclRef(const Decl *D) {
330e5dd7070Spatrick   JOS.attribute("id", createPointerRepresentation(D));
331e5dd7070Spatrick   if (!D)
332e5dd7070Spatrick     return;
333e5dd7070Spatrick 
334e5dd7070Spatrick   JOS.attribute("kind", (llvm::Twine(D->getDeclKindName()) + "Decl").str());
335e5dd7070Spatrick   if (const auto *ND = dyn_cast<NamedDecl>(D))
336e5dd7070Spatrick     JOS.attribute("name", ND->getDeclName().getAsString());
337e5dd7070Spatrick   if (const auto *VD = dyn_cast<ValueDecl>(D))
338e5dd7070Spatrick     JOS.attribute("type", createQualType(VD->getType()));
339e5dd7070Spatrick }
340e5dd7070Spatrick 
createBareDeclRef(const Decl * D)341e5dd7070Spatrick llvm::json::Object JSONNodeDumper::createBareDeclRef(const Decl *D) {
342e5dd7070Spatrick   llvm::json::Object Ret{{"id", createPointerRepresentation(D)}};
343e5dd7070Spatrick   if (!D)
344e5dd7070Spatrick     return Ret;
345e5dd7070Spatrick 
346e5dd7070Spatrick   Ret["kind"] = (llvm::Twine(D->getDeclKindName()) + "Decl").str();
347e5dd7070Spatrick   if (const auto *ND = dyn_cast<NamedDecl>(D))
348e5dd7070Spatrick     Ret["name"] = ND->getDeclName().getAsString();
349e5dd7070Spatrick   if (const auto *VD = dyn_cast<ValueDecl>(D))
350e5dd7070Spatrick     Ret["type"] = createQualType(VD->getType());
351e5dd7070Spatrick   return Ret;
352e5dd7070Spatrick }
353e5dd7070Spatrick 
createCastPath(const CastExpr * C)354e5dd7070Spatrick llvm::json::Array JSONNodeDumper::createCastPath(const CastExpr *C) {
355e5dd7070Spatrick   llvm::json::Array Ret;
356e5dd7070Spatrick   if (C->path_empty())
357e5dd7070Spatrick     return Ret;
358e5dd7070Spatrick 
359e5dd7070Spatrick   for (auto I = C->path_begin(), E = C->path_end(); I != E; ++I) {
360e5dd7070Spatrick     const CXXBaseSpecifier *Base = *I;
361e5dd7070Spatrick     const auto *RD =
362e5dd7070Spatrick         cast<CXXRecordDecl>(Base->getType()->castAs<RecordType>()->getDecl());
363e5dd7070Spatrick 
364e5dd7070Spatrick     llvm::json::Object Val{{"name", RD->getName()}};
365e5dd7070Spatrick     if (Base->isVirtual())
366e5dd7070Spatrick       Val["isVirtual"] = true;
367e5dd7070Spatrick     Ret.push_back(std::move(Val));
368e5dd7070Spatrick   }
369e5dd7070Spatrick   return Ret;
370e5dd7070Spatrick }
371e5dd7070Spatrick 
372e5dd7070Spatrick #define FIELD2(Name, Flag)  if (RD->Flag()) Ret[Name] = true
373e5dd7070Spatrick #define FIELD1(Flag)        FIELD2(#Flag, Flag)
374e5dd7070Spatrick 
375e5dd7070Spatrick static llvm::json::Object
createDefaultConstructorDefinitionData(const CXXRecordDecl * RD)376e5dd7070Spatrick createDefaultConstructorDefinitionData(const CXXRecordDecl *RD) {
377e5dd7070Spatrick   llvm::json::Object Ret;
378e5dd7070Spatrick 
379e5dd7070Spatrick   FIELD2("exists", hasDefaultConstructor);
380e5dd7070Spatrick   FIELD2("trivial", hasTrivialDefaultConstructor);
381e5dd7070Spatrick   FIELD2("nonTrivial", hasNonTrivialDefaultConstructor);
382e5dd7070Spatrick   FIELD2("userProvided", hasUserProvidedDefaultConstructor);
383e5dd7070Spatrick   FIELD2("isConstexpr", hasConstexprDefaultConstructor);
384e5dd7070Spatrick   FIELD2("needsImplicit", needsImplicitDefaultConstructor);
385e5dd7070Spatrick   FIELD2("defaultedIsConstexpr", defaultedDefaultConstructorIsConstexpr);
386e5dd7070Spatrick 
387e5dd7070Spatrick   return Ret;
388e5dd7070Spatrick }
389e5dd7070Spatrick 
390e5dd7070Spatrick static llvm::json::Object
createCopyConstructorDefinitionData(const CXXRecordDecl * RD)391e5dd7070Spatrick createCopyConstructorDefinitionData(const CXXRecordDecl *RD) {
392e5dd7070Spatrick   llvm::json::Object Ret;
393e5dd7070Spatrick 
394e5dd7070Spatrick   FIELD2("simple", hasSimpleCopyConstructor);
395e5dd7070Spatrick   FIELD2("trivial", hasTrivialCopyConstructor);
396e5dd7070Spatrick   FIELD2("nonTrivial", hasNonTrivialCopyConstructor);
397e5dd7070Spatrick   FIELD2("userDeclared", hasUserDeclaredCopyConstructor);
398e5dd7070Spatrick   FIELD2("hasConstParam", hasCopyConstructorWithConstParam);
399e5dd7070Spatrick   FIELD2("implicitHasConstParam", implicitCopyConstructorHasConstParam);
400e5dd7070Spatrick   FIELD2("needsImplicit", needsImplicitCopyConstructor);
401e5dd7070Spatrick   FIELD2("needsOverloadResolution", needsOverloadResolutionForCopyConstructor);
402e5dd7070Spatrick   if (!RD->needsOverloadResolutionForCopyConstructor())
403e5dd7070Spatrick     FIELD2("defaultedIsDeleted", defaultedCopyConstructorIsDeleted);
404e5dd7070Spatrick 
405e5dd7070Spatrick   return Ret;
406e5dd7070Spatrick }
407e5dd7070Spatrick 
408e5dd7070Spatrick static llvm::json::Object
createMoveConstructorDefinitionData(const CXXRecordDecl * RD)409e5dd7070Spatrick createMoveConstructorDefinitionData(const CXXRecordDecl *RD) {
410e5dd7070Spatrick   llvm::json::Object Ret;
411e5dd7070Spatrick 
412e5dd7070Spatrick   FIELD2("exists", hasMoveConstructor);
413e5dd7070Spatrick   FIELD2("simple", hasSimpleMoveConstructor);
414e5dd7070Spatrick   FIELD2("trivial", hasTrivialMoveConstructor);
415e5dd7070Spatrick   FIELD2("nonTrivial", hasNonTrivialMoveConstructor);
416e5dd7070Spatrick   FIELD2("userDeclared", hasUserDeclaredMoveConstructor);
417e5dd7070Spatrick   FIELD2("needsImplicit", needsImplicitMoveConstructor);
418e5dd7070Spatrick   FIELD2("needsOverloadResolution", needsOverloadResolutionForMoveConstructor);
419e5dd7070Spatrick   if (!RD->needsOverloadResolutionForMoveConstructor())
420e5dd7070Spatrick     FIELD2("defaultedIsDeleted", defaultedMoveConstructorIsDeleted);
421e5dd7070Spatrick 
422e5dd7070Spatrick   return Ret;
423e5dd7070Spatrick }
424e5dd7070Spatrick 
425e5dd7070Spatrick static llvm::json::Object
createCopyAssignmentDefinitionData(const CXXRecordDecl * RD)426e5dd7070Spatrick createCopyAssignmentDefinitionData(const CXXRecordDecl *RD) {
427e5dd7070Spatrick   llvm::json::Object Ret;
428e5dd7070Spatrick 
429ec727ea7Spatrick   FIELD2("simple", hasSimpleCopyAssignment);
430e5dd7070Spatrick   FIELD2("trivial", hasTrivialCopyAssignment);
431e5dd7070Spatrick   FIELD2("nonTrivial", hasNonTrivialCopyAssignment);
432e5dd7070Spatrick   FIELD2("hasConstParam", hasCopyAssignmentWithConstParam);
433e5dd7070Spatrick   FIELD2("implicitHasConstParam", implicitCopyAssignmentHasConstParam);
434e5dd7070Spatrick   FIELD2("userDeclared", hasUserDeclaredCopyAssignment);
435e5dd7070Spatrick   FIELD2("needsImplicit", needsImplicitCopyAssignment);
436e5dd7070Spatrick   FIELD2("needsOverloadResolution", needsOverloadResolutionForCopyAssignment);
437e5dd7070Spatrick 
438e5dd7070Spatrick   return Ret;
439e5dd7070Spatrick }
440e5dd7070Spatrick 
441e5dd7070Spatrick static llvm::json::Object
createMoveAssignmentDefinitionData(const CXXRecordDecl * RD)442e5dd7070Spatrick createMoveAssignmentDefinitionData(const CXXRecordDecl *RD) {
443e5dd7070Spatrick   llvm::json::Object Ret;
444e5dd7070Spatrick 
445e5dd7070Spatrick   FIELD2("exists", hasMoveAssignment);
446e5dd7070Spatrick   FIELD2("simple", hasSimpleMoveAssignment);
447e5dd7070Spatrick   FIELD2("trivial", hasTrivialMoveAssignment);
448e5dd7070Spatrick   FIELD2("nonTrivial", hasNonTrivialMoveAssignment);
449e5dd7070Spatrick   FIELD2("userDeclared", hasUserDeclaredMoveAssignment);
450e5dd7070Spatrick   FIELD2("needsImplicit", needsImplicitMoveAssignment);
451e5dd7070Spatrick   FIELD2("needsOverloadResolution", needsOverloadResolutionForMoveAssignment);
452e5dd7070Spatrick 
453e5dd7070Spatrick   return Ret;
454e5dd7070Spatrick }
455e5dd7070Spatrick 
456e5dd7070Spatrick static llvm::json::Object
createDestructorDefinitionData(const CXXRecordDecl * RD)457e5dd7070Spatrick createDestructorDefinitionData(const CXXRecordDecl *RD) {
458e5dd7070Spatrick   llvm::json::Object Ret;
459e5dd7070Spatrick 
460e5dd7070Spatrick   FIELD2("simple", hasSimpleDestructor);
461e5dd7070Spatrick   FIELD2("irrelevant", hasIrrelevantDestructor);
462e5dd7070Spatrick   FIELD2("trivial", hasTrivialDestructor);
463e5dd7070Spatrick   FIELD2("nonTrivial", hasNonTrivialDestructor);
464e5dd7070Spatrick   FIELD2("userDeclared", hasUserDeclaredDestructor);
465e5dd7070Spatrick   FIELD2("needsImplicit", needsImplicitDestructor);
466e5dd7070Spatrick   FIELD2("needsOverloadResolution", needsOverloadResolutionForDestructor);
467e5dd7070Spatrick   if (!RD->needsOverloadResolutionForDestructor())
468e5dd7070Spatrick     FIELD2("defaultedIsDeleted", defaultedDestructorIsDeleted);
469e5dd7070Spatrick 
470e5dd7070Spatrick   return Ret;
471e5dd7070Spatrick }
472e5dd7070Spatrick 
473e5dd7070Spatrick llvm::json::Object
createCXXRecordDefinitionData(const CXXRecordDecl * RD)474e5dd7070Spatrick JSONNodeDumper::createCXXRecordDefinitionData(const CXXRecordDecl *RD) {
475e5dd7070Spatrick   llvm::json::Object Ret;
476e5dd7070Spatrick 
477e5dd7070Spatrick   // This data is common to all C++ classes.
478e5dd7070Spatrick   FIELD1(isGenericLambda);
479e5dd7070Spatrick   FIELD1(isLambda);
480e5dd7070Spatrick   FIELD1(isEmpty);
481e5dd7070Spatrick   FIELD1(isAggregate);
482e5dd7070Spatrick   FIELD1(isStandardLayout);
483e5dd7070Spatrick   FIELD1(isTriviallyCopyable);
484e5dd7070Spatrick   FIELD1(isPOD);
485e5dd7070Spatrick   FIELD1(isTrivial);
486e5dd7070Spatrick   FIELD1(isPolymorphic);
487e5dd7070Spatrick   FIELD1(isAbstract);
488e5dd7070Spatrick   FIELD1(isLiteral);
489e5dd7070Spatrick   FIELD1(canPassInRegisters);
490e5dd7070Spatrick   FIELD1(hasUserDeclaredConstructor);
491e5dd7070Spatrick   FIELD1(hasConstexprNonCopyMoveConstructor);
492e5dd7070Spatrick   FIELD1(hasMutableFields);
493e5dd7070Spatrick   FIELD1(hasVariantMembers);
494e5dd7070Spatrick   FIELD2("canConstDefaultInit", allowConstDefaultInit);
495e5dd7070Spatrick 
496e5dd7070Spatrick   Ret["defaultCtor"] = createDefaultConstructorDefinitionData(RD);
497e5dd7070Spatrick   Ret["copyCtor"] = createCopyConstructorDefinitionData(RD);
498e5dd7070Spatrick   Ret["moveCtor"] = createMoveConstructorDefinitionData(RD);
499e5dd7070Spatrick   Ret["copyAssign"] = createCopyAssignmentDefinitionData(RD);
500e5dd7070Spatrick   Ret["moveAssign"] = createMoveAssignmentDefinitionData(RD);
501e5dd7070Spatrick   Ret["dtor"] = createDestructorDefinitionData(RD);
502e5dd7070Spatrick 
503e5dd7070Spatrick   return Ret;
504e5dd7070Spatrick }
505e5dd7070Spatrick 
506e5dd7070Spatrick #undef FIELD1
507e5dd7070Spatrick #undef FIELD2
508e5dd7070Spatrick 
createAccessSpecifier(AccessSpecifier AS)509e5dd7070Spatrick std::string JSONNodeDumper::createAccessSpecifier(AccessSpecifier AS) {
510ec727ea7Spatrick   const auto AccessSpelling = getAccessSpelling(AS);
511ec727ea7Spatrick   if (AccessSpelling.empty())
512ec727ea7Spatrick     return "none";
513ec727ea7Spatrick   return AccessSpelling.str();
514e5dd7070Spatrick }
515e5dd7070Spatrick 
516e5dd7070Spatrick llvm::json::Object
createCXXBaseSpecifier(const CXXBaseSpecifier & BS)517e5dd7070Spatrick JSONNodeDumper::createCXXBaseSpecifier(const CXXBaseSpecifier &BS) {
518e5dd7070Spatrick   llvm::json::Object Ret;
519e5dd7070Spatrick 
520e5dd7070Spatrick   Ret["type"] = createQualType(BS.getType());
521e5dd7070Spatrick   Ret["access"] = createAccessSpecifier(BS.getAccessSpecifier());
522e5dd7070Spatrick   Ret["writtenAccess"] =
523e5dd7070Spatrick       createAccessSpecifier(BS.getAccessSpecifierAsWritten());
524e5dd7070Spatrick   if (BS.isVirtual())
525e5dd7070Spatrick     Ret["isVirtual"] = true;
526e5dd7070Spatrick   if (BS.isPackExpansion())
527e5dd7070Spatrick     Ret["isPackExpansion"] = true;
528e5dd7070Spatrick 
529e5dd7070Spatrick   return Ret;
530e5dd7070Spatrick }
531e5dd7070Spatrick 
VisitTypedefType(const TypedefType * TT)532e5dd7070Spatrick void JSONNodeDumper::VisitTypedefType(const TypedefType *TT) {
533e5dd7070Spatrick   JOS.attribute("decl", createBareDeclRef(TT->getDecl()));
534*12c85518Srobert   if (!TT->typeMatchesDecl())
535*12c85518Srobert     JOS.attribute("type", createQualType(TT->desugar()));
536*12c85518Srobert }
537*12c85518Srobert 
VisitUsingType(const UsingType * TT)538*12c85518Srobert void JSONNodeDumper::VisitUsingType(const UsingType *TT) {
539*12c85518Srobert   JOS.attribute("decl", createBareDeclRef(TT->getFoundDecl()));
540*12c85518Srobert   if (!TT->typeMatchesDecl())
541*12c85518Srobert     JOS.attribute("type", createQualType(TT->desugar()));
542e5dd7070Spatrick }
543e5dd7070Spatrick 
VisitFunctionType(const FunctionType * T)544e5dd7070Spatrick void JSONNodeDumper::VisitFunctionType(const FunctionType *T) {
545e5dd7070Spatrick   FunctionType::ExtInfo E = T->getExtInfo();
546e5dd7070Spatrick   attributeOnlyIfTrue("noreturn", E.getNoReturn());
547e5dd7070Spatrick   attributeOnlyIfTrue("producesResult", E.getProducesResult());
548e5dd7070Spatrick   if (E.getHasRegParm())
549e5dd7070Spatrick     JOS.attribute("regParm", E.getRegParm());
550e5dd7070Spatrick   JOS.attribute("cc", FunctionType::getNameForCallConv(E.getCC()));
551e5dd7070Spatrick }
552e5dd7070Spatrick 
VisitFunctionProtoType(const FunctionProtoType * T)553e5dd7070Spatrick void JSONNodeDumper::VisitFunctionProtoType(const FunctionProtoType *T) {
554e5dd7070Spatrick   FunctionProtoType::ExtProtoInfo E = T->getExtProtoInfo();
555e5dd7070Spatrick   attributeOnlyIfTrue("trailingReturn", E.HasTrailingReturn);
556e5dd7070Spatrick   attributeOnlyIfTrue("const", T->isConst());
557e5dd7070Spatrick   attributeOnlyIfTrue("volatile", T->isVolatile());
558e5dd7070Spatrick   attributeOnlyIfTrue("restrict", T->isRestrict());
559e5dd7070Spatrick   attributeOnlyIfTrue("variadic", E.Variadic);
560e5dd7070Spatrick   switch (E.RefQualifier) {
561e5dd7070Spatrick   case RQ_LValue: JOS.attribute("refQualifier", "&"); break;
562e5dd7070Spatrick   case RQ_RValue: JOS.attribute("refQualifier", "&&"); break;
563e5dd7070Spatrick   case RQ_None: break;
564e5dd7070Spatrick   }
565e5dd7070Spatrick   switch (E.ExceptionSpec.Type) {
566e5dd7070Spatrick   case EST_DynamicNone:
567e5dd7070Spatrick   case EST_Dynamic: {
568e5dd7070Spatrick     JOS.attribute("exceptionSpec", "throw");
569e5dd7070Spatrick     llvm::json::Array Types;
570e5dd7070Spatrick     for (QualType QT : E.ExceptionSpec.Exceptions)
571e5dd7070Spatrick       Types.push_back(createQualType(QT));
572e5dd7070Spatrick     JOS.attribute("exceptionTypes", std::move(Types));
573e5dd7070Spatrick   } break;
574e5dd7070Spatrick   case EST_MSAny:
575e5dd7070Spatrick     JOS.attribute("exceptionSpec", "throw");
576e5dd7070Spatrick     JOS.attribute("throwsAny", true);
577e5dd7070Spatrick     break;
578e5dd7070Spatrick   case EST_BasicNoexcept:
579e5dd7070Spatrick     JOS.attribute("exceptionSpec", "noexcept");
580e5dd7070Spatrick     break;
581e5dd7070Spatrick   case EST_NoexceptTrue:
582e5dd7070Spatrick   case EST_NoexceptFalse:
583e5dd7070Spatrick     JOS.attribute("exceptionSpec", "noexcept");
584e5dd7070Spatrick     JOS.attribute("conditionEvaluatesTo",
585e5dd7070Spatrick                 E.ExceptionSpec.Type == EST_NoexceptTrue);
586e5dd7070Spatrick     //JOS.attributeWithCall("exceptionSpecExpr",
587e5dd7070Spatrick     //                    [this, E]() { Visit(E.ExceptionSpec.NoexceptExpr); });
588e5dd7070Spatrick     break;
589e5dd7070Spatrick   case EST_NoThrow:
590e5dd7070Spatrick     JOS.attribute("exceptionSpec", "nothrow");
591e5dd7070Spatrick     break;
592e5dd7070Spatrick   // FIXME: I cannot find a way to trigger these cases while dumping the AST. I
593e5dd7070Spatrick   // suspect you can only run into them when executing an AST dump from within
594e5dd7070Spatrick   // the debugger, which is not a use case we worry about for the JSON dumping
595e5dd7070Spatrick   // feature.
596e5dd7070Spatrick   case EST_DependentNoexcept:
597e5dd7070Spatrick   case EST_Unevaluated:
598e5dd7070Spatrick   case EST_Uninstantiated:
599e5dd7070Spatrick   case EST_Unparsed:
600e5dd7070Spatrick   case EST_None: break;
601e5dd7070Spatrick   }
602e5dd7070Spatrick   VisitFunctionType(T);
603e5dd7070Spatrick }
604e5dd7070Spatrick 
VisitRValueReferenceType(const ReferenceType * RT)605e5dd7070Spatrick void JSONNodeDumper::VisitRValueReferenceType(const ReferenceType *RT) {
606e5dd7070Spatrick   attributeOnlyIfTrue("spelledAsLValue", RT->isSpelledAsLValue());
607e5dd7070Spatrick }
608e5dd7070Spatrick 
VisitArrayType(const ArrayType * AT)609e5dd7070Spatrick void JSONNodeDumper::VisitArrayType(const ArrayType *AT) {
610e5dd7070Spatrick   switch (AT->getSizeModifier()) {
611e5dd7070Spatrick   case ArrayType::Star:
612e5dd7070Spatrick     JOS.attribute("sizeModifier", "*");
613e5dd7070Spatrick     break;
614e5dd7070Spatrick   case ArrayType::Static:
615e5dd7070Spatrick     JOS.attribute("sizeModifier", "static");
616e5dd7070Spatrick     break;
617e5dd7070Spatrick   case ArrayType::Normal:
618e5dd7070Spatrick     break;
619e5dd7070Spatrick   }
620e5dd7070Spatrick 
621e5dd7070Spatrick   std::string Str = AT->getIndexTypeQualifiers().getAsString();
622e5dd7070Spatrick   if (!Str.empty())
623e5dd7070Spatrick     JOS.attribute("indexTypeQualifiers", Str);
624e5dd7070Spatrick }
625e5dd7070Spatrick 
VisitConstantArrayType(const ConstantArrayType * CAT)626e5dd7070Spatrick void JSONNodeDumper::VisitConstantArrayType(const ConstantArrayType *CAT) {
627e5dd7070Spatrick   // FIXME: this should use ZExt instead of SExt, but JSON doesn't allow a
628e5dd7070Spatrick   // narrowing conversion to int64_t so it cannot be expressed.
629e5dd7070Spatrick   JOS.attribute("size", CAT->getSize().getSExtValue());
630e5dd7070Spatrick   VisitArrayType(CAT);
631e5dd7070Spatrick }
632e5dd7070Spatrick 
VisitDependentSizedExtVectorType(const DependentSizedExtVectorType * VT)633e5dd7070Spatrick void JSONNodeDumper::VisitDependentSizedExtVectorType(
634e5dd7070Spatrick     const DependentSizedExtVectorType *VT) {
635e5dd7070Spatrick   JOS.attributeObject(
636e5dd7070Spatrick       "attrLoc", [VT, this] { writeSourceLocation(VT->getAttributeLoc()); });
637e5dd7070Spatrick }
638e5dd7070Spatrick 
VisitVectorType(const VectorType * VT)639e5dd7070Spatrick void JSONNodeDumper::VisitVectorType(const VectorType *VT) {
640e5dd7070Spatrick   JOS.attribute("numElements", VT->getNumElements());
641e5dd7070Spatrick   switch (VT->getVectorKind()) {
642e5dd7070Spatrick   case VectorType::GenericVector:
643e5dd7070Spatrick     break;
644e5dd7070Spatrick   case VectorType::AltiVecVector:
645e5dd7070Spatrick     JOS.attribute("vectorKind", "altivec");
646e5dd7070Spatrick     break;
647e5dd7070Spatrick   case VectorType::AltiVecPixel:
648e5dd7070Spatrick     JOS.attribute("vectorKind", "altivec pixel");
649e5dd7070Spatrick     break;
650e5dd7070Spatrick   case VectorType::AltiVecBool:
651e5dd7070Spatrick     JOS.attribute("vectorKind", "altivec bool");
652e5dd7070Spatrick     break;
653e5dd7070Spatrick   case VectorType::NeonVector:
654e5dd7070Spatrick     JOS.attribute("vectorKind", "neon");
655e5dd7070Spatrick     break;
656e5dd7070Spatrick   case VectorType::NeonPolyVector:
657e5dd7070Spatrick     JOS.attribute("vectorKind", "neon poly");
658e5dd7070Spatrick     break;
659a9ac8606Spatrick   case VectorType::SveFixedLengthDataVector:
660a9ac8606Spatrick     JOS.attribute("vectorKind", "fixed-length sve data vector");
661a9ac8606Spatrick     break;
662a9ac8606Spatrick   case VectorType::SveFixedLengthPredicateVector:
663a9ac8606Spatrick     JOS.attribute("vectorKind", "fixed-length sve predicate vector");
664a9ac8606Spatrick     break;
665e5dd7070Spatrick   }
666e5dd7070Spatrick }
667e5dd7070Spatrick 
VisitUnresolvedUsingType(const UnresolvedUsingType * UUT)668e5dd7070Spatrick void JSONNodeDumper::VisitUnresolvedUsingType(const UnresolvedUsingType *UUT) {
669e5dd7070Spatrick   JOS.attribute("decl", createBareDeclRef(UUT->getDecl()));
670e5dd7070Spatrick }
671e5dd7070Spatrick 
VisitUnaryTransformType(const UnaryTransformType * UTT)672e5dd7070Spatrick void JSONNodeDumper::VisitUnaryTransformType(const UnaryTransformType *UTT) {
673e5dd7070Spatrick   switch (UTT->getUTTKind()) {
674*12c85518Srobert #define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait)                                  \
675*12c85518Srobert   case UnaryTransformType::Enum:                                               \
676*12c85518Srobert     JOS.attribute("transformKind", #Trait);                                    \
677e5dd7070Spatrick     break;
678*12c85518Srobert #include "clang/Basic/TransformTypeTraits.def"
679e5dd7070Spatrick   }
680e5dd7070Spatrick }
681e5dd7070Spatrick 
VisitTagType(const TagType * TT)682e5dd7070Spatrick void JSONNodeDumper::VisitTagType(const TagType *TT) {
683e5dd7070Spatrick   JOS.attribute("decl", createBareDeclRef(TT->getDecl()));
684e5dd7070Spatrick }
685e5dd7070Spatrick 
VisitTemplateTypeParmType(const TemplateTypeParmType * TTPT)686e5dd7070Spatrick void JSONNodeDumper::VisitTemplateTypeParmType(
687e5dd7070Spatrick     const TemplateTypeParmType *TTPT) {
688e5dd7070Spatrick   JOS.attribute("depth", TTPT->getDepth());
689e5dd7070Spatrick   JOS.attribute("index", TTPT->getIndex());
690e5dd7070Spatrick   attributeOnlyIfTrue("isPack", TTPT->isParameterPack());
691e5dd7070Spatrick   JOS.attribute("decl", createBareDeclRef(TTPT->getDecl()));
692e5dd7070Spatrick }
693e5dd7070Spatrick 
VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType * STTPT)694*12c85518Srobert void JSONNodeDumper::VisitSubstTemplateTypeParmType(
695*12c85518Srobert     const SubstTemplateTypeParmType *STTPT) {
696*12c85518Srobert   JOS.attribute("index", STTPT->getIndex());
697*12c85518Srobert   if (auto PackIndex = STTPT->getPackIndex())
698*12c85518Srobert     JOS.attribute("pack_index", *PackIndex);
699*12c85518Srobert }
700*12c85518Srobert 
VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType * T)701*12c85518Srobert void JSONNodeDumper::VisitSubstTemplateTypeParmPackType(
702*12c85518Srobert     const SubstTemplateTypeParmPackType *T) {
703*12c85518Srobert   JOS.attribute("index", T->getIndex());
704*12c85518Srobert }
705*12c85518Srobert 
VisitAutoType(const AutoType * AT)706e5dd7070Spatrick void JSONNodeDumper::VisitAutoType(const AutoType *AT) {
707e5dd7070Spatrick   JOS.attribute("undeduced", !AT->isDeduced());
708e5dd7070Spatrick   switch (AT->getKeyword()) {
709e5dd7070Spatrick   case AutoTypeKeyword::Auto:
710e5dd7070Spatrick     JOS.attribute("typeKeyword", "auto");
711e5dd7070Spatrick     break;
712e5dd7070Spatrick   case AutoTypeKeyword::DecltypeAuto:
713e5dd7070Spatrick     JOS.attribute("typeKeyword", "decltype(auto)");
714e5dd7070Spatrick     break;
715e5dd7070Spatrick   case AutoTypeKeyword::GNUAutoType:
716e5dd7070Spatrick     JOS.attribute("typeKeyword", "__auto_type");
717e5dd7070Spatrick     break;
718e5dd7070Spatrick   }
719e5dd7070Spatrick }
720e5dd7070Spatrick 
VisitTemplateSpecializationType(const TemplateSpecializationType * TST)721e5dd7070Spatrick void JSONNodeDumper::VisitTemplateSpecializationType(
722e5dd7070Spatrick     const TemplateSpecializationType *TST) {
723e5dd7070Spatrick   attributeOnlyIfTrue("isAlias", TST->isTypeAlias());
724e5dd7070Spatrick 
725e5dd7070Spatrick   std::string Str;
726e5dd7070Spatrick   llvm::raw_string_ostream OS(Str);
727e5dd7070Spatrick   TST->getTemplateName().print(OS, PrintPolicy);
728e5dd7070Spatrick   JOS.attribute("templateName", OS.str());
729e5dd7070Spatrick }
730e5dd7070Spatrick 
VisitInjectedClassNameType(const InjectedClassNameType * ICNT)731e5dd7070Spatrick void JSONNodeDumper::VisitInjectedClassNameType(
732e5dd7070Spatrick     const InjectedClassNameType *ICNT) {
733e5dd7070Spatrick   JOS.attribute("decl", createBareDeclRef(ICNT->getDecl()));
734e5dd7070Spatrick }
735e5dd7070Spatrick 
VisitObjCInterfaceType(const ObjCInterfaceType * OIT)736e5dd7070Spatrick void JSONNodeDumper::VisitObjCInterfaceType(const ObjCInterfaceType *OIT) {
737e5dd7070Spatrick   JOS.attribute("decl", createBareDeclRef(OIT->getDecl()));
738e5dd7070Spatrick }
739e5dd7070Spatrick 
VisitPackExpansionType(const PackExpansionType * PET)740e5dd7070Spatrick void JSONNodeDumper::VisitPackExpansionType(const PackExpansionType *PET) {
741*12c85518Srobert   if (std::optional<unsigned> N = PET->getNumExpansions())
742e5dd7070Spatrick     JOS.attribute("numExpansions", *N);
743e5dd7070Spatrick }
744e5dd7070Spatrick 
VisitElaboratedType(const ElaboratedType * ET)745e5dd7070Spatrick void JSONNodeDumper::VisitElaboratedType(const ElaboratedType *ET) {
746e5dd7070Spatrick   if (const NestedNameSpecifier *NNS = ET->getQualifier()) {
747e5dd7070Spatrick     std::string Str;
748e5dd7070Spatrick     llvm::raw_string_ostream OS(Str);
749e5dd7070Spatrick     NNS->print(OS, PrintPolicy, /*ResolveTemplateArgs*/ true);
750e5dd7070Spatrick     JOS.attribute("qualifier", OS.str());
751e5dd7070Spatrick   }
752e5dd7070Spatrick   if (const TagDecl *TD = ET->getOwnedTagDecl())
753e5dd7070Spatrick     JOS.attribute("ownedTagDecl", createBareDeclRef(TD));
754e5dd7070Spatrick }
755e5dd7070Spatrick 
VisitMacroQualifiedType(const MacroQualifiedType * MQT)756e5dd7070Spatrick void JSONNodeDumper::VisitMacroQualifiedType(const MacroQualifiedType *MQT) {
757e5dd7070Spatrick   JOS.attribute("macroName", MQT->getMacroIdentifier()->getName());
758e5dd7070Spatrick }
759e5dd7070Spatrick 
VisitMemberPointerType(const MemberPointerType * MPT)760e5dd7070Spatrick void JSONNodeDumper::VisitMemberPointerType(const MemberPointerType *MPT) {
761e5dd7070Spatrick   attributeOnlyIfTrue("isData", MPT->isMemberDataPointer());
762e5dd7070Spatrick   attributeOnlyIfTrue("isFunction", MPT->isMemberFunctionPointer());
763e5dd7070Spatrick }
764e5dd7070Spatrick 
VisitNamedDecl(const NamedDecl * ND)765e5dd7070Spatrick void JSONNodeDumper::VisitNamedDecl(const NamedDecl *ND) {
766e5dd7070Spatrick   if (ND && ND->getDeclName()) {
767e5dd7070Spatrick     JOS.attribute("name", ND->getNameAsString());
768a9ac8606Spatrick     // FIXME: There are likely other contexts in which it makes no sense to ask
769a9ac8606Spatrick     // for a mangled name.
770*12c85518Srobert     if (isa<RequiresExprBodyDecl>(ND->getDeclContext()))
771*12c85518Srobert       return;
772*12c85518Srobert 
773*12c85518Srobert     // Mangled names are not meaningful for locals, and may not be well-defined
774*12c85518Srobert     // in the case of VLAs.
775*12c85518Srobert     auto *VD = dyn_cast<VarDecl>(ND);
776*12c85518Srobert     if (VD && VD->hasLocalStorage())
777*12c85518Srobert       return;
778*12c85518Srobert 
779e5dd7070Spatrick     std::string MangledName = ASTNameGen.getName(ND);
780e5dd7070Spatrick     if (!MangledName.empty())
781e5dd7070Spatrick       JOS.attribute("mangledName", MangledName);
782e5dd7070Spatrick   }
783e5dd7070Spatrick }
784e5dd7070Spatrick 
VisitTypedefDecl(const TypedefDecl * TD)785e5dd7070Spatrick void JSONNodeDumper::VisitTypedefDecl(const TypedefDecl *TD) {
786e5dd7070Spatrick   VisitNamedDecl(TD);
787e5dd7070Spatrick   JOS.attribute("type", createQualType(TD->getUnderlyingType()));
788e5dd7070Spatrick }
789e5dd7070Spatrick 
VisitTypeAliasDecl(const TypeAliasDecl * TAD)790e5dd7070Spatrick void JSONNodeDumper::VisitTypeAliasDecl(const TypeAliasDecl *TAD) {
791e5dd7070Spatrick   VisitNamedDecl(TAD);
792e5dd7070Spatrick   JOS.attribute("type", createQualType(TAD->getUnderlyingType()));
793e5dd7070Spatrick }
794e5dd7070Spatrick 
VisitNamespaceDecl(const NamespaceDecl * ND)795e5dd7070Spatrick void JSONNodeDumper::VisitNamespaceDecl(const NamespaceDecl *ND) {
796e5dd7070Spatrick   VisitNamedDecl(ND);
797e5dd7070Spatrick   attributeOnlyIfTrue("isInline", ND->isInline());
798*12c85518Srobert   attributeOnlyIfTrue("isNested", ND->isNested());
799e5dd7070Spatrick   if (!ND->isOriginalNamespace())
800e5dd7070Spatrick     JOS.attribute("originalNamespace",
801e5dd7070Spatrick                   createBareDeclRef(ND->getOriginalNamespace()));
802e5dd7070Spatrick }
803e5dd7070Spatrick 
VisitUsingDirectiveDecl(const UsingDirectiveDecl * UDD)804e5dd7070Spatrick void JSONNodeDumper::VisitUsingDirectiveDecl(const UsingDirectiveDecl *UDD) {
805e5dd7070Spatrick   JOS.attribute("nominatedNamespace",
806e5dd7070Spatrick                 createBareDeclRef(UDD->getNominatedNamespace()));
807e5dd7070Spatrick }
808e5dd7070Spatrick 
VisitNamespaceAliasDecl(const NamespaceAliasDecl * NAD)809e5dd7070Spatrick void JSONNodeDumper::VisitNamespaceAliasDecl(const NamespaceAliasDecl *NAD) {
810e5dd7070Spatrick   VisitNamedDecl(NAD);
811e5dd7070Spatrick   JOS.attribute("aliasedNamespace",
812e5dd7070Spatrick                 createBareDeclRef(NAD->getAliasedNamespace()));
813e5dd7070Spatrick }
814e5dd7070Spatrick 
VisitUsingDecl(const UsingDecl * UD)815e5dd7070Spatrick void JSONNodeDumper::VisitUsingDecl(const UsingDecl *UD) {
816e5dd7070Spatrick   std::string Name;
817e5dd7070Spatrick   if (const NestedNameSpecifier *NNS = UD->getQualifier()) {
818e5dd7070Spatrick     llvm::raw_string_ostream SOS(Name);
819e5dd7070Spatrick     NNS->print(SOS, UD->getASTContext().getPrintingPolicy());
820e5dd7070Spatrick   }
821e5dd7070Spatrick   Name += UD->getNameAsString();
822e5dd7070Spatrick   JOS.attribute("name", Name);
823e5dd7070Spatrick }
824e5dd7070Spatrick 
VisitUsingEnumDecl(const UsingEnumDecl * UED)825a9ac8606Spatrick void JSONNodeDumper::VisitUsingEnumDecl(const UsingEnumDecl *UED) {
826a9ac8606Spatrick   JOS.attribute("target", createBareDeclRef(UED->getEnumDecl()));
827a9ac8606Spatrick }
828a9ac8606Spatrick 
VisitUsingShadowDecl(const UsingShadowDecl * USD)829e5dd7070Spatrick void JSONNodeDumper::VisitUsingShadowDecl(const UsingShadowDecl *USD) {
830e5dd7070Spatrick   JOS.attribute("target", createBareDeclRef(USD->getTargetDecl()));
831e5dd7070Spatrick }
832e5dd7070Spatrick 
VisitVarDecl(const VarDecl * VD)833e5dd7070Spatrick void JSONNodeDumper::VisitVarDecl(const VarDecl *VD) {
834e5dd7070Spatrick   VisitNamedDecl(VD);
835e5dd7070Spatrick   JOS.attribute("type", createQualType(VD->getType()));
836e5dd7070Spatrick 
837e5dd7070Spatrick   StorageClass SC = VD->getStorageClass();
838e5dd7070Spatrick   if (SC != SC_None)
839e5dd7070Spatrick     JOS.attribute("storageClass", VarDecl::getStorageClassSpecifierString(SC));
840e5dd7070Spatrick   switch (VD->getTLSKind()) {
841e5dd7070Spatrick   case VarDecl::TLS_Dynamic: JOS.attribute("tls", "dynamic"); break;
842e5dd7070Spatrick   case VarDecl::TLS_Static: JOS.attribute("tls", "static"); break;
843e5dd7070Spatrick   case VarDecl::TLS_None: break;
844e5dd7070Spatrick   }
845e5dd7070Spatrick   attributeOnlyIfTrue("nrvo", VD->isNRVOVariable());
846e5dd7070Spatrick   attributeOnlyIfTrue("inline", VD->isInline());
847e5dd7070Spatrick   attributeOnlyIfTrue("constexpr", VD->isConstexpr());
848e5dd7070Spatrick   attributeOnlyIfTrue("modulePrivate", VD->isModulePrivate());
849e5dd7070Spatrick   if (VD->hasInit()) {
850e5dd7070Spatrick     switch (VD->getInitStyle()) {
851e5dd7070Spatrick     case VarDecl::CInit: JOS.attribute("init", "c");  break;
852e5dd7070Spatrick     case VarDecl::CallInit: JOS.attribute("init", "call"); break;
853e5dd7070Spatrick     case VarDecl::ListInit: JOS.attribute("init", "list"); break;
854*12c85518Srobert     case VarDecl::ParenListInit:
855*12c85518Srobert       JOS.attribute("init", "paren-list");
856*12c85518Srobert       break;
857e5dd7070Spatrick     }
858e5dd7070Spatrick   }
859e5dd7070Spatrick   attributeOnlyIfTrue("isParameterPack", VD->isParameterPack());
860e5dd7070Spatrick }
861e5dd7070Spatrick 
VisitFieldDecl(const FieldDecl * FD)862e5dd7070Spatrick void JSONNodeDumper::VisitFieldDecl(const FieldDecl *FD) {
863e5dd7070Spatrick   VisitNamedDecl(FD);
864e5dd7070Spatrick   JOS.attribute("type", createQualType(FD->getType()));
865e5dd7070Spatrick   attributeOnlyIfTrue("mutable", FD->isMutable());
866e5dd7070Spatrick   attributeOnlyIfTrue("modulePrivate", FD->isModulePrivate());
867e5dd7070Spatrick   attributeOnlyIfTrue("isBitfield", FD->isBitField());
868e5dd7070Spatrick   attributeOnlyIfTrue("hasInClassInitializer", FD->hasInClassInitializer());
869e5dd7070Spatrick }
870e5dd7070Spatrick 
VisitFunctionDecl(const FunctionDecl * FD)871e5dd7070Spatrick void JSONNodeDumper::VisitFunctionDecl(const FunctionDecl *FD) {
872e5dd7070Spatrick   VisitNamedDecl(FD);
873e5dd7070Spatrick   JOS.attribute("type", createQualType(FD->getType()));
874e5dd7070Spatrick   StorageClass SC = FD->getStorageClass();
875e5dd7070Spatrick   if (SC != SC_None)
876e5dd7070Spatrick     JOS.attribute("storageClass", VarDecl::getStorageClassSpecifierString(SC));
877e5dd7070Spatrick   attributeOnlyIfTrue("inline", FD->isInlineSpecified());
878e5dd7070Spatrick   attributeOnlyIfTrue("virtual", FD->isVirtualAsWritten());
879e5dd7070Spatrick   attributeOnlyIfTrue("pure", FD->isPure());
880e5dd7070Spatrick   attributeOnlyIfTrue("explicitlyDeleted", FD->isDeletedAsWritten());
881e5dd7070Spatrick   attributeOnlyIfTrue("constexpr", FD->isConstexpr());
882e5dd7070Spatrick   attributeOnlyIfTrue("variadic", FD->isVariadic());
883e5dd7070Spatrick 
884e5dd7070Spatrick   if (FD->isDefaulted())
885e5dd7070Spatrick     JOS.attribute("explicitlyDefaulted",
886e5dd7070Spatrick                   FD->isDeleted() ? "deleted" : "default");
887e5dd7070Spatrick }
888e5dd7070Spatrick 
VisitEnumDecl(const EnumDecl * ED)889e5dd7070Spatrick void JSONNodeDumper::VisitEnumDecl(const EnumDecl *ED) {
890e5dd7070Spatrick   VisitNamedDecl(ED);
891e5dd7070Spatrick   if (ED->isFixed())
892e5dd7070Spatrick     JOS.attribute("fixedUnderlyingType", createQualType(ED->getIntegerType()));
893e5dd7070Spatrick   if (ED->isScoped())
894e5dd7070Spatrick     JOS.attribute("scopedEnumTag",
895e5dd7070Spatrick                   ED->isScopedUsingClassTag() ? "class" : "struct");
896e5dd7070Spatrick }
VisitEnumConstantDecl(const EnumConstantDecl * ECD)897e5dd7070Spatrick void JSONNodeDumper::VisitEnumConstantDecl(const EnumConstantDecl *ECD) {
898e5dd7070Spatrick   VisitNamedDecl(ECD);
899e5dd7070Spatrick   JOS.attribute("type", createQualType(ECD->getType()));
900e5dd7070Spatrick }
901e5dd7070Spatrick 
VisitRecordDecl(const RecordDecl * RD)902e5dd7070Spatrick void JSONNodeDumper::VisitRecordDecl(const RecordDecl *RD) {
903e5dd7070Spatrick   VisitNamedDecl(RD);
904e5dd7070Spatrick   JOS.attribute("tagUsed", RD->getKindName());
905e5dd7070Spatrick   attributeOnlyIfTrue("completeDefinition", RD->isCompleteDefinition());
906e5dd7070Spatrick }
VisitCXXRecordDecl(const CXXRecordDecl * RD)907e5dd7070Spatrick void JSONNodeDumper::VisitCXXRecordDecl(const CXXRecordDecl *RD) {
908e5dd7070Spatrick   VisitRecordDecl(RD);
909e5dd7070Spatrick 
910e5dd7070Spatrick   // All other information requires a complete definition.
911e5dd7070Spatrick   if (!RD->isCompleteDefinition())
912e5dd7070Spatrick     return;
913e5dd7070Spatrick 
914e5dd7070Spatrick   JOS.attribute("definitionData", createCXXRecordDefinitionData(RD));
915e5dd7070Spatrick   if (RD->getNumBases()) {
916e5dd7070Spatrick     JOS.attributeArray("bases", [this, RD] {
917e5dd7070Spatrick       for (const auto &Spec : RD->bases())
918e5dd7070Spatrick         JOS.value(createCXXBaseSpecifier(Spec));
919e5dd7070Spatrick     });
920e5dd7070Spatrick   }
921e5dd7070Spatrick }
922e5dd7070Spatrick 
VisitHLSLBufferDecl(const HLSLBufferDecl * D)923*12c85518Srobert void JSONNodeDumper::VisitHLSLBufferDecl(const HLSLBufferDecl *D) {
924*12c85518Srobert   VisitNamedDecl(D);
925*12c85518Srobert   JOS.attribute("bufferKind", D->isCBuffer() ? "cbuffer" : "tbuffer");
926*12c85518Srobert }
927*12c85518Srobert 
VisitTemplateTypeParmDecl(const TemplateTypeParmDecl * D)928e5dd7070Spatrick void JSONNodeDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
929e5dd7070Spatrick   VisitNamedDecl(D);
930e5dd7070Spatrick   JOS.attribute("tagUsed", D->wasDeclaredWithTypename() ? "typename" : "class");
931e5dd7070Spatrick   JOS.attribute("depth", D->getDepth());
932e5dd7070Spatrick   JOS.attribute("index", D->getIndex());
933e5dd7070Spatrick   attributeOnlyIfTrue("isParameterPack", D->isParameterPack());
934e5dd7070Spatrick 
935e5dd7070Spatrick   if (D->hasDefaultArgument())
936e5dd7070Spatrick     JOS.attributeObject("defaultArg", [=] {
937e5dd7070Spatrick       Visit(D->getDefaultArgument(), SourceRange(),
938e5dd7070Spatrick             D->getDefaultArgStorage().getInheritedFrom(),
939e5dd7070Spatrick             D->defaultArgumentWasInherited() ? "inherited from" : "previous");
940e5dd7070Spatrick     });
941e5dd7070Spatrick }
942e5dd7070Spatrick 
VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl * D)943e5dd7070Spatrick void JSONNodeDumper::VisitNonTypeTemplateParmDecl(
944e5dd7070Spatrick     const NonTypeTemplateParmDecl *D) {
945e5dd7070Spatrick   VisitNamedDecl(D);
946e5dd7070Spatrick   JOS.attribute("type", createQualType(D->getType()));
947e5dd7070Spatrick   JOS.attribute("depth", D->getDepth());
948e5dd7070Spatrick   JOS.attribute("index", D->getIndex());
949e5dd7070Spatrick   attributeOnlyIfTrue("isParameterPack", D->isParameterPack());
950e5dd7070Spatrick 
951e5dd7070Spatrick   if (D->hasDefaultArgument())
952e5dd7070Spatrick     JOS.attributeObject("defaultArg", [=] {
953e5dd7070Spatrick       Visit(D->getDefaultArgument(), SourceRange(),
954e5dd7070Spatrick             D->getDefaultArgStorage().getInheritedFrom(),
955e5dd7070Spatrick             D->defaultArgumentWasInherited() ? "inherited from" : "previous");
956e5dd7070Spatrick     });
957e5dd7070Spatrick }
958e5dd7070Spatrick 
VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl * D)959e5dd7070Spatrick void JSONNodeDumper::VisitTemplateTemplateParmDecl(
960e5dd7070Spatrick     const TemplateTemplateParmDecl *D) {
961e5dd7070Spatrick   VisitNamedDecl(D);
962e5dd7070Spatrick   JOS.attribute("depth", D->getDepth());
963e5dd7070Spatrick   JOS.attribute("index", D->getIndex());
964e5dd7070Spatrick   attributeOnlyIfTrue("isParameterPack", D->isParameterPack());
965e5dd7070Spatrick 
966e5dd7070Spatrick   if (D->hasDefaultArgument())
967e5dd7070Spatrick     JOS.attributeObject("defaultArg", [=] {
968a9ac8606Spatrick       const auto *InheritedFrom = D->getDefaultArgStorage().getInheritedFrom();
969e5dd7070Spatrick       Visit(D->getDefaultArgument().getArgument(),
970a9ac8606Spatrick             InheritedFrom ? InheritedFrom->getSourceRange() : SourceLocation{},
971a9ac8606Spatrick             InheritedFrom,
972e5dd7070Spatrick             D->defaultArgumentWasInherited() ? "inherited from" : "previous");
973e5dd7070Spatrick     });
974e5dd7070Spatrick }
975e5dd7070Spatrick 
VisitLinkageSpecDecl(const LinkageSpecDecl * LSD)976e5dd7070Spatrick void JSONNodeDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *LSD) {
977e5dd7070Spatrick   StringRef Lang;
978e5dd7070Spatrick   switch (LSD->getLanguage()) {
979e5dd7070Spatrick   case LinkageSpecDecl::lang_c: Lang = "C"; break;
980e5dd7070Spatrick   case LinkageSpecDecl::lang_cxx: Lang = "C++"; break;
981e5dd7070Spatrick   }
982e5dd7070Spatrick   JOS.attribute("language", Lang);
983e5dd7070Spatrick   attributeOnlyIfTrue("hasBraces", LSD->hasBraces());
984e5dd7070Spatrick }
985e5dd7070Spatrick 
VisitAccessSpecDecl(const AccessSpecDecl * ASD)986e5dd7070Spatrick void JSONNodeDumper::VisitAccessSpecDecl(const AccessSpecDecl *ASD) {
987e5dd7070Spatrick   JOS.attribute("access", createAccessSpecifier(ASD->getAccess()));
988e5dd7070Spatrick }
989e5dd7070Spatrick 
VisitFriendDecl(const FriendDecl * FD)990e5dd7070Spatrick void JSONNodeDumper::VisitFriendDecl(const FriendDecl *FD) {
991e5dd7070Spatrick   if (const TypeSourceInfo *T = FD->getFriendType())
992e5dd7070Spatrick     JOS.attribute("type", createQualType(T->getType()));
993e5dd7070Spatrick }
994e5dd7070Spatrick 
VisitObjCIvarDecl(const ObjCIvarDecl * D)995e5dd7070Spatrick void JSONNodeDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) {
996e5dd7070Spatrick   VisitNamedDecl(D);
997e5dd7070Spatrick   JOS.attribute("type", createQualType(D->getType()));
998e5dd7070Spatrick   attributeOnlyIfTrue("synthesized", D->getSynthesize());
999e5dd7070Spatrick   switch (D->getAccessControl()) {
1000e5dd7070Spatrick   case ObjCIvarDecl::None: JOS.attribute("access", "none"); break;
1001e5dd7070Spatrick   case ObjCIvarDecl::Private: JOS.attribute("access", "private"); break;
1002e5dd7070Spatrick   case ObjCIvarDecl::Protected: JOS.attribute("access", "protected"); break;
1003e5dd7070Spatrick   case ObjCIvarDecl::Public: JOS.attribute("access", "public"); break;
1004e5dd7070Spatrick   case ObjCIvarDecl::Package: JOS.attribute("access", "package"); break;
1005e5dd7070Spatrick   }
1006e5dd7070Spatrick }
1007e5dd7070Spatrick 
VisitObjCMethodDecl(const ObjCMethodDecl * D)1008e5dd7070Spatrick void JSONNodeDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) {
1009e5dd7070Spatrick   VisitNamedDecl(D);
1010e5dd7070Spatrick   JOS.attribute("returnType", createQualType(D->getReturnType()));
1011e5dd7070Spatrick   JOS.attribute("instance", D->isInstanceMethod());
1012e5dd7070Spatrick   attributeOnlyIfTrue("variadic", D->isVariadic());
1013e5dd7070Spatrick }
1014e5dd7070Spatrick 
VisitObjCTypeParamDecl(const ObjCTypeParamDecl * D)1015e5dd7070Spatrick void JSONNodeDumper::VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D) {
1016e5dd7070Spatrick   VisitNamedDecl(D);
1017e5dd7070Spatrick   JOS.attribute("type", createQualType(D->getUnderlyingType()));
1018e5dd7070Spatrick   attributeOnlyIfTrue("bounded", D->hasExplicitBound());
1019e5dd7070Spatrick   switch (D->getVariance()) {
1020e5dd7070Spatrick   case ObjCTypeParamVariance::Invariant:
1021e5dd7070Spatrick     break;
1022e5dd7070Spatrick   case ObjCTypeParamVariance::Covariant:
1023e5dd7070Spatrick     JOS.attribute("variance", "covariant");
1024e5dd7070Spatrick     break;
1025e5dd7070Spatrick   case ObjCTypeParamVariance::Contravariant:
1026e5dd7070Spatrick     JOS.attribute("variance", "contravariant");
1027e5dd7070Spatrick     break;
1028e5dd7070Spatrick   }
1029e5dd7070Spatrick }
1030e5dd7070Spatrick 
VisitObjCCategoryDecl(const ObjCCategoryDecl * D)1031e5dd7070Spatrick void JSONNodeDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
1032e5dd7070Spatrick   VisitNamedDecl(D);
1033e5dd7070Spatrick   JOS.attribute("interface", createBareDeclRef(D->getClassInterface()));
1034e5dd7070Spatrick   JOS.attribute("implementation", createBareDeclRef(D->getImplementation()));
1035e5dd7070Spatrick 
1036e5dd7070Spatrick   llvm::json::Array Protocols;
1037e5dd7070Spatrick   for (const auto* P : D->protocols())
1038e5dd7070Spatrick     Protocols.push_back(createBareDeclRef(P));
1039e5dd7070Spatrick   if (!Protocols.empty())
1040e5dd7070Spatrick     JOS.attribute("protocols", std::move(Protocols));
1041e5dd7070Spatrick }
1042e5dd7070Spatrick 
VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl * D)1043e5dd7070Spatrick void JSONNodeDumper::VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) {
1044e5dd7070Spatrick   VisitNamedDecl(D);
1045e5dd7070Spatrick   JOS.attribute("interface", createBareDeclRef(D->getClassInterface()));
1046e5dd7070Spatrick   JOS.attribute("categoryDecl", createBareDeclRef(D->getCategoryDecl()));
1047e5dd7070Spatrick }
1048e5dd7070Spatrick 
VisitObjCProtocolDecl(const ObjCProtocolDecl * D)1049e5dd7070Spatrick void JSONNodeDumper::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
1050e5dd7070Spatrick   VisitNamedDecl(D);
1051e5dd7070Spatrick 
1052e5dd7070Spatrick   llvm::json::Array Protocols;
1053e5dd7070Spatrick   for (const auto *P : D->protocols())
1054e5dd7070Spatrick     Protocols.push_back(createBareDeclRef(P));
1055e5dd7070Spatrick   if (!Protocols.empty())
1056e5dd7070Spatrick     JOS.attribute("protocols", std::move(Protocols));
1057e5dd7070Spatrick }
1058e5dd7070Spatrick 
VisitObjCInterfaceDecl(const ObjCInterfaceDecl * D)1059e5dd7070Spatrick void JSONNodeDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
1060e5dd7070Spatrick   VisitNamedDecl(D);
1061e5dd7070Spatrick   JOS.attribute("super", createBareDeclRef(D->getSuperClass()));
1062e5dd7070Spatrick   JOS.attribute("implementation", createBareDeclRef(D->getImplementation()));
1063e5dd7070Spatrick 
1064e5dd7070Spatrick   llvm::json::Array Protocols;
1065e5dd7070Spatrick   for (const auto* P : D->protocols())
1066e5dd7070Spatrick     Protocols.push_back(createBareDeclRef(P));
1067e5dd7070Spatrick   if (!Protocols.empty())
1068e5dd7070Spatrick     JOS.attribute("protocols", std::move(Protocols));
1069e5dd7070Spatrick }
1070e5dd7070Spatrick 
VisitObjCImplementationDecl(const ObjCImplementationDecl * D)1071e5dd7070Spatrick void JSONNodeDumper::VisitObjCImplementationDecl(
1072e5dd7070Spatrick     const ObjCImplementationDecl *D) {
1073e5dd7070Spatrick   VisitNamedDecl(D);
1074e5dd7070Spatrick   JOS.attribute("super", createBareDeclRef(D->getSuperClass()));
1075e5dd7070Spatrick   JOS.attribute("interface", createBareDeclRef(D->getClassInterface()));
1076e5dd7070Spatrick }
1077e5dd7070Spatrick 
VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl * D)1078e5dd7070Spatrick void JSONNodeDumper::VisitObjCCompatibleAliasDecl(
1079e5dd7070Spatrick     const ObjCCompatibleAliasDecl *D) {
1080e5dd7070Spatrick   VisitNamedDecl(D);
1081e5dd7070Spatrick   JOS.attribute("interface", createBareDeclRef(D->getClassInterface()));
1082e5dd7070Spatrick }
1083e5dd7070Spatrick 
VisitObjCPropertyDecl(const ObjCPropertyDecl * D)1084e5dd7070Spatrick void JSONNodeDumper::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
1085e5dd7070Spatrick   VisitNamedDecl(D);
1086e5dd7070Spatrick   JOS.attribute("type", createQualType(D->getType()));
1087e5dd7070Spatrick 
1088e5dd7070Spatrick   switch (D->getPropertyImplementation()) {
1089e5dd7070Spatrick   case ObjCPropertyDecl::None: break;
1090e5dd7070Spatrick   case ObjCPropertyDecl::Required: JOS.attribute("control", "required"); break;
1091e5dd7070Spatrick   case ObjCPropertyDecl::Optional: JOS.attribute("control", "optional"); break;
1092e5dd7070Spatrick   }
1093e5dd7070Spatrick 
1094ec727ea7Spatrick   ObjCPropertyAttribute::Kind Attrs = D->getPropertyAttributes();
1095ec727ea7Spatrick   if (Attrs != ObjCPropertyAttribute::kind_noattr) {
1096ec727ea7Spatrick     if (Attrs & ObjCPropertyAttribute::kind_getter)
1097e5dd7070Spatrick       JOS.attribute("getter", createBareDeclRef(D->getGetterMethodDecl()));
1098ec727ea7Spatrick     if (Attrs & ObjCPropertyAttribute::kind_setter)
1099e5dd7070Spatrick       JOS.attribute("setter", createBareDeclRef(D->getSetterMethodDecl()));
1100ec727ea7Spatrick     attributeOnlyIfTrue("readonly",
1101ec727ea7Spatrick                         Attrs & ObjCPropertyAttribute::kind_readonly);
1102ec727ea7Spatrick     attributeOnlyIfTrue("assign", Attrs & ObjCPropertyAttribute::kind_assign);
1103e5dd7070Spatrick     attributeOnlyIfTrue("readwrite",
1104ec727ea7Spatrick                         Attrs & ObjCPropertyAttribute::kind_readwrite);
1105ec727ea7Spatrick     attributeOnlyIfTrue("retain", Attrs & ObjCPropertyAttribute::kind_retain);
1106ec727ea7Spatrick     attributeOnlyIfTrue("copy", Attrs & ObjCPropertyAttribute::kind_copy);
1107e5dd7070Spatrick     attributeOnlyIfTrue("nonatomic",
1108ec727ea7Spatrick                         Attrs & ObjCPropertyAttribute::kind_nonatomic);
1109ec727ea7Spatrick     attributeOnlyIfTrue("atomic", Attrs & ObjCPropertyAttribute::kind_atomic);
1110ec727ea7Spatrick     attributeOnlyIfTrue("weak", Attrs & ObjCPropertyAttribute::kind_weak);
1111ec727ea7Spatrick     attributeOnlyIfTrue("strong", Attrs & ObjCPropertyAttribute::kind_strong);
1112e5dd7070Spatrick     attributeOnlyIfTrue("unsafe_unretained",
1113ec727ea7Spatrick                         Attrs & ObjCPropertyAttribute::kind_unsafe_unretained);
1114ec727ea7Spatrick     attributeOnlyIfTrue("class", Attrs & ObjCPropertyAttribute::kind_class);
1115ec727ea7Spatrick     attributeOnlyIfTrue("direct", Attrs & ObjCPropertyAttribute::kind_direct);
1116e5dd7070Spatrick     attributeOnlyIfTrue("nullability",
1117ec727ea7Spatrick                         Attrs & ObjCPropertyAttribute::kind_nullability);
1118e5dd7070Spatrick     attributeOnlyIfTrue("null_resettable",
1119ec727ea7Spatrick                         Attrs & ObjCPropertyAttribute::kind_null_resettable);
1120e5dd7070Spatrick   }
1121e5dd7070Spatrick }
1122e5dd7070Spatrick 
VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl * D)1123e5dd7070Spatrick void JSONNodeDumper::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {
1124e5dd7070Spatrick   VisitNamedDecl(D->getPropertyDecl());
1125e5dd7070Spatrick   JOS.attribute("implKind", D->getPropertyImplementation() ==
1126e5dd7070Spatrick                                     ObjCPropertyImplDecl::Synthesize
1127e5dd7070Spatrick                                 ? "synthesize"
1128e5dd7070Spatrick                                 : "dynamic");
1129e5dd7070Spatrick   JOS.attribute("propertyDecl", createBareDeclRef(D->getPropertyDecl()));
1130e5dd7070Spatrick   JOS.attribute("ivarDecl", createBareDeclRef(D->getPropertyIvarDecl()));
1131e5dd7070Spatrick }
1132e5dd7070Spatrick 
VisitBlockDecl(const BlockDecl * D)1133e5dd7070Spatrick void JSONNodeDumper::VisitBlockDecl(const BlockDecl *D) {
1134e5dd7070Spatrick   attributeOnlyIfTrue("variadic", D->isVariadic());
1135e5dd7070Spatrick   attributeOnlyIfTrue("capturesThis", D->capturesCXXThis());
1136e5dd7070Spatrick }
1137e5dd7070Spatrick 
VisitObjCEncodeExpr(const ObjCEncodeExpr * OEE)1138e5dd7070Spatrick void JSONNodeDumper::VisitObjCEncodeExpr(const ObjCEncodeExpr *OEE) {
1139e5dd7070Spatrick   JOS.attribute("encodedType", createQualType(OEE->getEncodedType()));
1140e5dd7070Spatrick }
1141e5dd7070Spatrick 
VisitObjCMessageExpr(const ObjCMessageExpr * OME)1142e5dd7070Spatrick void JSONNodeDumper::VisitObjCMessageExpr(const ObjCMessageExpr *OME) {
1143e5dd7070Spatrick   std::string Str;
1144e5dd7070Spatrick   llvm::raw_string_ostream OS(Str);
1145e5dd7070Spatrick 
1146e5dd7070Spatrick   OME->getSelector().print(OS);
1147e5dd7070Spatrick   JOS.attribute("selector", OS.str());
1148e5dd7070Spatrick 
1149e5dd7070Spatrick   switch (OME->getReceiverKind()) {
1150e5dd7070Spatrick   case ObjCMessageExpr::Instance:
1151e5dd7070Spatrick     JOS.attribute("receiverKind", "instance");
1152e5dd7070Spatrick     break;
1153e5dd7070Spatrick   case ObjCMessageExpr::Class:
1154e5dd7070Spatrick     JOS.attribute("receiverKind", "class");
1155e5dd7070Spatrick     JOS.attribute("classType", createQualType(OME->getClassReceiver()));
1156e5dd7070Spatrick     break;
1157e5dd7070Spatrick   case ObjCMessageExpr::SuperInstance:
1158e5dd7070Spatrick     JOS.attribute("receiverKind", "super (instance)");
1159e5dd7070Spatrick     JOS.attribute("superType", createQualType(OME->getSuperType()));
1160e5dd7070Spatrick     break;
1161e5dd7070Spatrick   case ObjCMessageExpr::SuperClass:
1162e5dd7070Spatrick     JOS.attribute("receiverKind", "super (class)");
1163e5dd7070Spatrick     JOS.attribute("superType", createQualType(OME->getSuperType()));
1164e5dd7070Spatrick     break;
1165e5dd7070Spatrick   }
1166e5dd7070Spatrick 
1167e5dd7070Spatrick   QualType CallReturnTy = OME->getCallReturnType(Ctx);
1168e5dd7070Spatrick   if (OME->getType() != CallReturnTy)
1169e5dd7070Spatrick     JOS.attribute("callReturnType", createQualType(CallReturnTy));
1170e5dd7070Spatrick }
1171e5dd7070Spatrick 
VisitObjCBoxedExpr(const ObjCBoxedExpr * OBE)1172e5dd7070Spatrick void JSONNodeDumper::VisitObjCBoxedExpr(const ObjCBoxedExpr *OBE) {
1173e5dd7070Spatrick   if (const ObjCMethodDecl *MD = OBE->getBoxingMethod()) {
1174e5dd7070Spatrick     std::string Str;
1175e5dd7070Spatrick     llvm::raw_string_ostream OS(Str);
1176e5dd7070Spatrick 
1177e5dd7070Spatrick     MD->getSelector().print(OS);
1178e5dd7070Spatrick     JOS.attribute("selector", OS.str());
1179e5dd7070Spatrick   }
1180e5dd7070Spatrick }
1181e5dd7070Spatrick 
VisitObjCSelectorExpr(const ObjCSelectorExpr * OSE)1182e5dd7070Spatrick void JSONNodeDumper::VisitObjCSelectorExpr(const ObjCSelectorExpr *OSE) {
1183e5dd7070Spatrick   std::string Str;
1184e5dd7070Spatrick   llvm::raw_string_ostream OS(Str);
1185e5dd7070Spatrick 
1186e5dd7070Spatrick   OSE->getSelector().print(OS);
1187e5dd7070Spatrick   JOS.attribute("selector", OS.str());
1188e5dd7070Spatrick }
1189e5dd7070Spatrick 
VisitObjCProtocolExpr(const ObjCProtocolExpr * OPE)1190e5dd7070Spatrick void JSONNodeDumper::VisitObjCProtocolExpr(const ObjCProtocolExpr *OPE) {
1191e5dd7070Spatrick   JOS.attribute("protocol", createBareDeclRef(OPE->getProtocol()));
1192e5dd7070Spatrick }
1193e5dd7070Spatrick 
VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr * OPRE)1194e5dd7070Spatrick void JSONNodeDumper::VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *OPRE) {
1195e5dd7070Spatrick   if (OPRE->isImplicitProperty()) {
1196e5dd7070Spatrick     JOS.attribute("propertyKind", "implicit");
1197e5dd7070Spatrick     if (const ObjCMethodDecl *MD = OPRE->getImplicitPropertyGetter())
1198e5dd7070Spatrick       JOS.attribute("getter", createBareDeclRef(MD));
1199e5dd7070Spatrick     if (const ObjCMethodDecl *MD = OPRE->getImplicitPropertySetter())
1200e5dd7070Spatrick       JOS.attribute("setter", createBareDeclRef(MD));
1201e5dd7070Spatrick   } else {
1202e5dd7070Spatrick     JOS.attribute("propertyKind", "explicit");
1203e5dd7070Spatrick     JOS.attribute("property", createBareDeclRef(OPRE->getExplicitProperty()));
1204e5dd7070Spatrick   }
1205e5dd7070Spatrick 
1206e5dd7070Spatrick   attributeOnlyIfTrue("isSuperReceiver", OPRE->isSuperReceiver());
1207e5dd7070Spatrick   attributeOnlyIfTrue("isMessagingGetter", OPRE->isMessagingGetter());
1208e5dd7070Spatrick   attributeOnlyIfTrue("isMessagingSetter", OPRE->isMessagingSetter());
1209e5dd7070Spatrick }
1210e5dd7070Spatrick 
VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr * OSRE)1211e5dd7070Spatrick void JSONNodeDumper::VisitObjCSubscriptRefExpr(
1212e5dd7070Spatrick     const ObjCSubscriptRefExpr *OSRE) {
1213e5dd7070Spatrick   JOS.attribute("subscriptKind",
1214e5dd7070Spatrick                 OSRE->isArraySubscriptRefExpr() ? "array" : "dictionary");
1215e5dd7070Spatrick 
1216e5dd7070Spatrick   if (const ObjCMethodDecl *MD = OSRE->getAtIndexMethodDecl())
1217e5dd7070Spatrick     JOS.attribute("getter", createBareDeclRef(MD));
1218e5dd7070Spatrick   if (const ObjCMethodDecl *MD = OSRE->setAtIndexMethodDecl())
1219e5dd7070Spatrick     JOS.attribute("setter", createBareDeclRef(MD));
1220e5dd7070Spatrick }
1221e5dd7070Spatrick 
VisitObjCIvarRefExpr(const ObjCIvarRefExpr * OIRE)1222e5dd7070Spatrick void JSONNodeDumper::VisitObjCIvarRefExpr(const ObjCIvarRefExpr *OIRE) {
1223e5dd7070Spatrick   JOS.attribute("decl", createBareDeclRef(OIRE->getDecl()));
1224e5dd7070Spatrick   attributeOnlyIfTrue("isFreeIvar", OIRE->isFreeIvar());
1225e5dd7070Spatrick   JOS.attribute("isArrow", OIRE->isArrow());
1226e5dd7070Spatrick }
1227e5dd7070Spatrick 
VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr * OBLE)1228e5dd7070Spatrick void JSONNodeDumper::VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *OBLE) {
1229e5dd7070Spatrick   JOS.attribute("value", OBLE->getValue() ? "__objc_yes" : "__objc_no");
1230e5dd7070Spatrick }
1231e5dd7070Spatrick 
VisitDeclRefExpr(const DeclRefExpr * DRE)1232e5dd7070Spatrick void JSONNodeDumper::VisitDeclRefExpr(const DeclRefExpr *DRE) {
1233e5dd7070Spatrick   JOS.attribute("referencedDecl", createBareDeclRef(DRE->getDecl()));
1234e5dd7070Spatrick   if (DRE->getDecl() != DRE->getFoundDecl())
1235e5dd7070Spatrick     JOS.attribute("foundReferencedDecl",
1236e5dd7070Spatrick                   createBareDeclRef(DRE->getFoundDecl()));
1237e5dd7070Spatrick   switch (DRE->isNonOdrUse()) {
1238e5dd7070Spatrick   case NOUR_None: break;
1239e5dd7070Spatrick   case NOUR_Unevaluated: JOS.attribute("nonOdrUseReason", "unevaluated"); break;
1240e5dd7070Spatrick   case NOUR_Constant: JOS.attribute("nonOdrUseReason", "constant"); break;
1241e5dd7070Spatrick   case NOUR_Discarded: JOS.attribute("nonOdrUseReason", "discarded"); break;
1242e5dd7070Spatrick   }
1243e5dd7070Spatrick }
1244e5dd7070Spatrick 
VisitSYCLUniqueStableNameExpr(const SYCLUniqueStableNameExpr * E)1245a9ac8606Spatrick void JSONNodeDumper::VisitSYCLUniqueStableNameExpr(
1246a9ac8606Spatrick     const SYCLUniqueStableNameExpr *E) {
1247a9ac8606Spatrick   JOS.attribute("typeSourceInfo",
1248a9ac8606Spatrick                 createQualType(E->getTypeSourceInfo()->getType()));
1249a9ac8606Spatrick }
1250a9ac8606Spatrick 
VisitPredefinedExpr(const PredefinedExpr * PE)1251e5dd7070Spatrick void JSONNodeDumper::VisitPredefinedExpr(const PredefinedExpr *PE) {
1252e5dd7070Spatrick   JOS.attribute("name", PredefinedExpr::getIdentKindName(PE->getIdentKind()));
1253e5dd7070Spatrick }
1254e5dd7070Spatrick 
VisitUnaryOperator(const UnaryOperator * UO)1255e5dd7070Spatrick void JSONNodeDumper::VisitUnaryOperator(const UnaryOperator *UO) {
1256e5dd7070Spatrick   JOS.attribute("isPostfix", UO->isPostfix());
1257e5dd7070Spatrick   JOS.attribute("opcode", UnaryOperator::getOpcodeStr(UO->getOpcode()));
1258e5dd7070Spatrick   if (!UO->canOverflow())
1259e5dd7070Spatrick     JOS.attribute("canOverflow", false);
1260e5dd7070Spatrick }
1261e5dd7070Spatrick 
VisitBinaryOperator(const BinaryOperator * BO)1262e5dd7070Spatrick void JSONNodeDumper::VisitBinaryOperator(const BinaryOperator *BO) {
1263e5dd7070Spatrick   JOS.attribute("opcode", BinaryOperator::getOpcodeStr(BO->getOpcode()));
1264e5dd7070Spatrick }
1265e5dd7070Spatrick 
VisitCompoundAssignOperator(const CompoundAssignOperator * CAO)1266e5dd7070Spatrick void JSONNodeDumper::VisitCompoundAssignOperator(
1267e5dd7070Spatrick     const CompoundAssignOperator *CAO) {
1268e5dd7070Spatrick   VisitBinaryOperator(CAO);
1269e5dd7070Spatrick   JOS.attribute("computeLHSType", createQualType(CAO->getComputationLHSType()));
1270e5dd7070Spatrick   JOS.attribute("computeResultType",
1271e5dd7070Spatrick                 createQualType(CAO->getComputationResultType()));
1272e5dd7070Spatrick }
1273e5dd7070Spatrick 
VisitMemberExpr(const MemberExpr * ME)1274e5dd7070Spatrick void JSONNodeDumper::VisitMemberExpr(const MemberExpr *ME) {
1275e5dd7070Spatrick   // Note, we always write this Boolean field because the information it conveys
1276e5dd7070Spatrick   // is critical to understanding the AST node.
1277e5dd7070Spatrick   ValueDecl *VD = ME->getMemberDecl();
1278e5dd7070Spatrick   JOS.attribute("name", VD && VD->getDeclName() ? VD->getNameAsString() : "");
1279e5dd7070Spatrick   JOS.attribute("isArrow", ME->isArrow());
1280e5dd7070Spatrick   JOS.attribute("referencedMemberDecl", createPointerRepresentation(VD));
1281e5dd7070Spatrick   switch (ME->isNonOdrUse()) {
1282e5dd7070Spatrick   case NOUR_None: break;
1283e5dd7070Spatrick   case NOUR_Unevaluated: JOS.attribute("nonOdrUseReason", "unevaluated"); break;
1284e5dd7070Spatrick   case NOUR_Constant: JOS.attribute("nonOdrUseReason", "constant"); break;
1285e5dd7070Spatrick   case NOUR_Discarded: JOS.attribute("nonOdrUseReason", "discarded"); break;
1286e5dd7070Spatrick   }
1287e5dd7070Spatrick }
1288e5dd7070Spatrick 
VisitCXXNewExpr(const CXXNewExpr * NE)1289e5dd7070Spatrick void JSONNodeDumper::VisitCXXNewExpr(const CXXNewExpr *NE) {
1290e5dd7070Spatrick   attributeOnlyIfTrue("isGlobal", NE->isGlobalNew());
1291e5dd7070Spatrick   attributeOnlyIfTrue("isArray", NE->isArray());
1292e5dd7070Spatrick   attributeOnlyIfTrue("isPlacement", NE->getNumPlacementArgs() != 0);
1293e5dd7070Spatrick   switch (NE->getInitializationStyle()) {
1294e5dd7070Spatrick   case CXXNewExpr::NoInit: break;
1295e5dd7070Spatrick   case CXXNewExpr::CallInit: JOS.attribute("initStyle", "call"); break;
1296e5dd7070Spatrick   case CXXNewExpr::ListInit: JOS.attribute("initStyle", "list"); break;
1297e5dd7070Spatrick   }
1298e5dd7070Spatrick   if (const FunctionDecl *FD = NE->getOperatorNew())
1299e5dd7070Spatrick     JOS.attribute("operatorNewDecl", createBareDeclRef(FD));
1300e5dd7070Spatrick   if (const FunctionDecl *FD = NE->getOperatorDelete())
1301e5dd7070Spatrick     JOS.attribute("operatorDeleteDecl", createBareDeclRef(FD));
1302e5dd7070Spatrick }
VisitCXXDeleteExpr(const CXXDeleteExpr * DE)1303e5dd7070Spatrick void JSONNodeDumper::VisitCXXDeleteExpr(const CXXDeleteExpr *DE) {
1304e5dd7070Spatrick   attributeOnlyIfTrue("isGlobal", DE->isGlobalDelete());
1305e5dd7070Spatrick   attributeOnlyIfTrue("isArray", DE->isArrayForm());
1306e5dd7070Spatrick   attributeOnlyIfTrue("isArrayAsWritten", DE->isArrayFormAsWritten());
1307e5dd7070Spatrick   if (const FunctionDecl *FD = DE->getOperatorDelete())
1308e5dd7070Spatrick     JOS.attribute("operatorDeleteDecl", createBareDeclRef(FD));
1309e5dd7070Spatrick }
1310e5dd7070Spatrick 
VisitCXXThisExpr(const CXXThisExpr * TE)1311e5dd7070Spatrick void JSONNodeDumper::VisitCXXThisExpr(const CXXThisExpr *TE) {
1312e5dd7070Spatrick   attributeOnlyIfTrue("implicit", TE->isImplicit());
1313e5dd7070Spatrick }
1314e5dd7070Spatrick 
VisitCastExpr(const CastExpr * CE)1315e5dd7070Spatrick void JSONNodeDumper::VisitCastExpr(const CastExpr *CE) {
1316e5dd7070Spatrick   JOS.attribute("castKind", CE->getCastKindName());
1317e5dd7070Spatrick   llvm::json::Array Path = createCastPath(CE);
1318e5dd7070Spatrick   if (!Path.empty())
1319e5dd7070Spatrick     JOS.attribute("path", std::move(Path));
1320e5dd7070Spatrick   // FIXME: This may not be useful information as it can be obtusely gleaned
1321e5dd7070Spatrick   // from the inner[] array.
1322e5dd7070Spatrick   if (const NamedDecl *ND = CE->getConversionFunction())
1323e5dd7070Spatrick     JOS.attribute("conversionFunc", createBareDeclRef(ND));
1324e5dd7070Spatrick }
1325e5dd7070Spatrick 
VisitImplicitCastExpr(const ImplicitCastExpr * ICE)1326e5dd7070Spatrick void JSONNodeDumper::VisitImplicitCastExpr(const ImplicitCastExpr *ICE) {
1327e5dd7070Spatrick   VisitCastExpr(ICE);
1328e5dd7070Spatrick   attributeOnlyIfTrue("isPartOfExplicitCast", ICE->isPartOfExplicitCast());
1329e5dd7070Spatrick }
1330e5dd7070Spatrick 
VisitCallExpr(const CallExpr * CE)1331e5dd7070Spatrick void JSONNodeDumper::VisitCallExpr(const CallExpr *CE) {
1332e5dd7070Spatrick   attributeOnlyIfTrue("adl", CE->usesADL());
1333e5dd7070Spatrick }
1334e5dd7070Spatrick 
VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr * TTE)1335e5dd7070Spatrick void JSONNodeDumper::VisitUnaryExprOrTypeTraitExpr(
1336e5dd7070Spatrick     const UnaryExprOrTypeTraitExpr *TTE) {
1337ec727ea7Spatrick   JOS.attribute("name", getTraitSpelling(TTE->getKind()));
1338e5dd7070Spatrick   if (TTE->isArgumentType())
1339e5dd7070Spatrick     JOS.attribute("argType", createQualType(TTE->getArgumentType()));
1340e5dd7070Spatrick }
1341e5dd7070Spatrick 
VisitSizeOfPackExpr(const SizeOfPackExpr * SOPE)1342e5dd7070Spatrick void JSONNodeDumper::VisitSizeOfPackExpr(const SizeOfPackExpr *SOPE) {
1343e5dd7070Spatrick   VisitNamedDecl(SOPE->getPack());
1344e5dd7070Spatrick }
1345e5dd7070Spatrick 
VisitUnresolvedLookupExpr(const UnresolvedLookupExpr * ULE)1346e5dd7070Spatrick void JSONNodeDumper::VisitUnresolvedLookupExpr(
1347e5dd7070Spatrick     const UnresolvedLookupExpr *ULE) {
1348e5dd7070Spatrick   JOS.attribute("usesADL", ULE->requiresADL());
1349e5dd7070Spatrick   JOS.attribute("name", ULE->getName().getAsString());
1350e5dd7070Spatrick 
1351e5dd7070Spatrick   JOS.attributeArray("lookups", [this, ULE] {
1352e5dd7070Spatrick     for (const NamedDecl *D : ULE->decls())
1353e5dd7070Spatrick       JOS.value(createBareDeclRef(D));
1354e5dd7070Spatrick   });
1355e5dd7070Spatrick }
1356e5dd7070Spatrick 
VisitAddrLabelExpr(const AddrLabelExpr * ALE)1357e5dd7070Spatrick void JSONNodeDumper::VisitAddrLabelExpr(const AddrLabelExpr *ALE) {
1358e5dd7070Spatrick   JOS.attribute("name", ALE->getLabel()->getName());
1359e5dd7070Spatrick   JOS.attribute("labelDeclId", createPointerRepresentation(ALE->getLabel()));
1360e5dd7070Spatrick }
1361e5dd7070Spatrick 
VisitCXXTypeidExpr(const CXXTypeidExpr * CTE)1362e5dd7070Spatrick void JSONNodeDumper::VisitCXXTypeidExpr(const CXXTypeidExpr *CTE) {
1363e5dd7070Spatrick   if (CTE->isTypeOperand()) {
1364e5dd7070Spatrick     QualType Adjusted = CTE->getTypeOperand(Ctx);
1365e5dd7070Spatrick     QualType Unadjusted = CTE->getTypeOperandSourceInfo()->getType();
1366e5dd7070Spatrick     JOS.attribute("typeArg", createQualType(Unadjusted));
1367e5dd7070Spatrick     if (Adjusted != Unadjusted)
1368e5dd7070Spatrick       JOS.attribute("adjustedTypeArg", createQualType(Adjusted));
1369e5dd7070Spatrick   }
1370e5dd7070Spatrick }
1371e5dd7070Spatrick 
VisitConstantExpr(const ConstantExpr * CE)1372e5dd7070Spatrick void JSONNodeDumper::VisitConstantExpr(const ConstantExpr *CE) {
1373ec727ea7Spatrick   if (CE->getResultAPValueKind() != APValue::None)
1374ec727ea7Spatrick     Visit(CE->getAPValueResult(), CE->getType());
1375e5dd7070Spatrick }
1376e5dd7070Spatrick 
VisitInitListExpr(const InitListExpr * ILE)1377e5dd7070Spatrick void JSONNodeDumper::VisitInitListExpr(const InitListExpr *ILE) {
1378e5dd7070Spatrick   if (const FieldDecl *FD = ILE->getInitializedFieldInUnion())
1379e5dd7070Spatrick     JOS.attribute("field", createBareDeclRef(FD));
1380e5dd7070Spatrick }
1381e5dd7070Spatrick 
VisitGenericSelectionExpr(const GenericSelectionExpr * GSE)1382e5dd7070Spatrick void JSONNodeDumper::VisitGenericSelectionExpr(
1383e5dd7070Spatrick     const GenericSelectionExpr *GSE) {
1384e5dd7070Spatrick   attributeOnlyIfTrue("resultDependent", GSE->isResultDependent());
1385e5dd7070Spatrick }
1386e5dd7070Spatrick 
VisitCXXUnresolvedConstructExpr(const CXXUnresolvedConstructExpr * UCE)1387e5dd7070Spatrick void JSONNodeDumper::VisitCXXUnresolvedConstructExpr(
1388e5dd7070Spatrick     const CXXUnresolvedConstructExpr *UCE) {
1389e5dd7070Spatrick   if (UCE->getType() != UCE->getTypeAsWritten())
1390e5dd7070Spatrick     JOS.attribute("typeAsWritten", createQualType(UCE->getTypeAsWritten()));
1391e5dd7070Spatrick   attributeOnlyIfTrue("list", UCE->isListInitialization());
1392e5dd7070Spatrick }
1393e5dd7070Spatrick 
VisitCXXConstructExpr(const CXXConstructExpr * CE)1394e5dd7070Spatrick void JSONNodeDumper::VisitCXXConstructExpr(const CXXConstructExpr *CE) {
1395e5dd7070Spatrick   CXXConstructorDecl *Ctor = CE->getConstructor();
1396e5dd7070Spatrick   JOS.attribute("ctorType", createQualType(Ctor->getType()));
1397e5dd7070Spatrick   attributeOnlyIfTrue("elidable", CE->isElidable());
1398e5dd7070Spatrick   attributeOnlyIfTrue("list", CE->isListInitialization());
1399e5dd7070Spatrick   attributeOnlyIfTrue("initializer_list", CE->isStdInitListInitialization());
1400e5dd7070Spatrick   attributeOnlyIfTrue("zeroing", CE->requiresZeroInitialization());
1401e5dd7070Spatrick   attributeOnlyIfTrue("hadMultipleCandidates", CE->hadMultipleCandidates());
1402e5dd7070Spatrick 
1403e5dd7070Spatrick   switch (CE->getConstructionKind()) {
1404e5dd7070Spatrick   case CXXConstructExpr::CK_Complete:
1405e5dd7070Spatrick     JOS.attribute("constructionKind", "complete");
1406e5dd7070Spatrick     break;
1407e5dd7070Spatrick   case CXXConstructExpr::CK_Delegating:
1408e5dd7070Spatrick     JOS.attribute("constructionKind", "delegating");
1409e5dd7070Spatrick     break;
1410e5dd7070Spatrick   case CXXConstructExpr::CK_NonVirtualBase:
1411e5dd7070Spatrick     JOS.attribute("constructionKind", "non-virtual base");
1412e5dd7070Spatrick     break;
1413e5dd7070Spatrick   case CXXConstructExpr::CK_VirtualBase:
1414e5dd7070Spatrick     JOS.attribute("constructionKind", "virtual base");
1415e5dd7070Spatrick     break;
1416e5dd7070Spatrick   }
1417e5dd7070Spatrick }
1418e5dd7070Spatrick 
VisitExprWithCleanups(const ExprWithCleanups * EWC)1419e5dd7070Spatrick void JSONNodeDumper::VisitExprWithCleanups(const ExprWithCleanups *EWC) {
1420e5dd7070Spatrick   attributeOnlyIfTrue("cleanupsHaveSideEffects",
1421e5dd7070Spatrick                       EWC->cleanupsHaveSideEffects());
1422e5dd7070Spatrick   if (EWC->getNumObjects()) {
1423e5dd7070Spatrick     JOS.attributeArray("cleanups", [this, EWC] {
1424e5dd7070Spatrick       for (const ExprWithCleanups::CleanupObject &CO : EWC->getObjects())
1425ec727ea7Spatrick         if (auto *BD = CO.dyn_cast<BlockDecl *>()) {
1426ec727ea7Spatrick           JOS.value(createBareDeclRef(BD));
1427ec727ea7Spatrick         } else if (auto *CLE = CO.dyn_cast<CompoundLiteralExpr *>()) {
1428ec727ea7Spatrick           llvm::json::Object Obj;
1429ec727ea7Spatrick           Obj["id"] = createPointerRepresentation(CLE);
1430ec727ea7Spatrick           Obj["kind"] = CLE->getStmtClassName();
1431ec727ea7Spatrick           JOS.value(std::move(Obj));
1432ec727ea7Spatrick         } else {
1433ec727ea7Spatrick           llvm_unreachable("unexpected cleanup object type");
1434ec727ea7Spatrick         }
1435e5dd7070Spatrick     });
1436e5dd7070Spatrick   }
1437e5dd7070Spatrick }
1438e5dd7070Spatrick 
VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr * BTE)1439e5dd7070Spatrick void JSONNodeDumper::VisitCXXBindTemporaryExpr(
1440e5dd7070Spatrick     const CXXBindTemporaryExpr *BTE) {
1441e5dd7070Spatrick   const CXXTemporary *Temp = BTE->getTemporary();
1442e5dd7070Spatrick   JOS.attribute("temp", createPointerRepresentation(Temp));
1443e5dd7070Spatrick   if (const CXXDestructorDecl *Dtor = Temp->getDestructor())
1444e5dd7070Spatrick     JOS.attribute("dtor", createBareDeclRef(Dtor));
1445e5dd7070Spatrick }
1446e5dd7070Spatrick 
VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr * MTE)1447e5dd7070Spatrick void JSONNodeDumper::VisitMaterializeTemporaryExpr(
1448e5dd7070Spatrick     const MaterializeTemporaryExpr *MTE) {
1449e5dd7070Spatrick   if (const ValueDecl *VD = MTE->getExtendingDecl())
1450e5dd7070Spatrick     JOS.attribute("extendingDecl", createBareDeclRef(VD));
1451e5dd7070Spatrick 
1452e5dd7070Spatrick   switch (MTE->getStorageDuration()) {
1453e5dd7070Spatrick   case SD_Automatic:
1454e5dd7070Spatrick     JOS.attribute("storageDuration", "automatic");
1455e5dd7070Spatrick     break;
1456e5dd7070Spatrick   case SD_Dynamic:
1457e5dd7070Spatrick     JOS.attribute("storageDuration", "dynamic");
1458e5dd7070Spatrick     break;
1459e5dd7070Spatrick   case SD_FullExpression:
1460e5dd7070Spatrick     JOS.attribute("storageDuration", "full expression");
1461e5dd7070Spatrick     break;
1462e5dd7070Spatrick   case SD_Static:
1463e5dd7070Spatrick     JOS.attribute("storageDuration", "static");
1464e5dd7070Spatrick     break;
1465e5dd7070Spatrick   case SD_Thread:
1466e5dd7070Spatrick     JOS.attribute("storageDuration", "thread");
1467e5dd7070Spatrick     break;
1468e5dd7070Spatrick   }
1469e5dd7070Spatrick 
1470e5dd7070Spatrick   attributeOnlyIfTrue("boundToLValueRef", MTE->isBoundToLvalueReference());
1471e5dd7070Spatrick }
1472e5dd7070Spatrick 
VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr * DSME)1473e5dd7070Spatrick void JSONNodeDumper::VisitCXXDependentScopeMemberExpr(
1474e5dd7070Spatrick     const CXXDependentScopeMemberExpr *DSME) {
1475e5dd7070Spatrick   JOS.attribute("isArrow", DSME->isArrow());
1476e5dd7070Spatrick   JOS.attribute("member", DSME->getMember().getAsString());
1477e5dd7070Spatrick   attributeOnlyIfTrue("hasTemplateKeyword", DSME->hasTemplateKeyword());
1478e5dd7070Spatrick   attributeOnlyIfTrue("hasExplicitTemplateArgs",
1479e5dd7070Spatrick                       DSME->hasExplicitTemplateArgs());
1480e5dd7070Spatrick 
1481e5dd7070Spatrick   if (DSME->getNumTemplateArgs()) {
1482e5dd7070Spatrick     JOS.attributeArray("explicitTemplateArgs", [DSME, this] {
1483e5dd7070Spatrick       for (const TemplateArgumentLoc &TAL : DSME->template_arguments())
1484e5dd7070Spatrick         JOS.object(
1485e5dd7070Spatrick             [&TAL, this] { Visit(TAL.getArgument(), TAL.getSourceRange()); });
1486e5dd7070Spatrick     });
1487e5dd7070Spatrick   }
1488e5dd7070Spatrick }
1489e5dd7070Spatrick 
VisitRequiresExpr(const RequiresExpr * RE)1490a9ac8606Spatrick void JSONNodeDumper::VisitRequiresExpr(const RequiresExpr *RE) {
1491a9ac8606Spatrick   if (!RE->isValueDependent())
1492a9ac8606Spatrick     JOS.attribute("satisfied", RE->isSatisfied());
1493a9ac8606Spatrick }
1494a9ac8606Spatrick 
VisitIntegerLiteral(const IntegerLiteral * IL)1495e5dd7070Spatrick void JSONNodeDumper::VisitIntegerLiteral(const IntegerLiteral *IL) {
1496a9ac8606Spatrick   llvm::SmallString<16> Buffer;
1497a9ac8606Spatrick   IL->getValue().toString(Buffer,
1498a9ac8606Spatrick                           /*Radix=*/10, IL->getType()->isSignedIntegerType());
1499a9ac8606Spatrick   JOS.attribute("value", Buffer);
1500e5dd7070Spatrick }
VisitCharacterLiteral(const CharacterLiteral * CL)1501e5dd7070Spatrick void JSONNodeDumper::VisitCharacterLiteral(const CharacterLiteral *CL) {
1502e5dd7070Spatrick   // FIXME: This should probably print the character literal as a string,
1503e5dd7070Spatrick   // rather than as a numerical value. It would be nice if the behavior matched
1504e5dd7070Spatrick   // what we do to print a string literal; right now, it is impossible to tell
1505e5dd7070Spatrick   // the difference between 'a' and L'a' in C from the JSON output.
1506e5dd7070Spatrick   JOS.attribute("value", CL->getValue());
1507e5dd7070Spatrick }
VisitFixedPointLiteral(const FixedPointLiteral * FPL)1508e5dd7070Spatrick void JSONNodeDumper::VisitFixedPointLiteral(const FixedPointLiteral *FPL) {
1509e5dd7070Spatrick   JOS.attribute("value", FPL->getValueAsString(/*Radix=*/10));
1510e5dd7070Spatrick }
VisitFloatingLiteral(const FloatingLiteral * FL)1511e5dd7070Spatrick void JSONNodeDumper::VisitFloatingLiteral(const FloatingLiteral *FL) {
1512a9ac8606Spatrick   llvm::SmallString<16> Buffer;
1513e5dd7070Spatrick   FL->getValue().toString(Buffer);
1514e5dd7070Spatrick   JOS.attribute("value", Buffer);
1515e5dd7070Spatrick }
VisitStringLiteral(const StringLiteral * SL)1516e5dd7070Spatrick void JSONNodeDumper::VisitStringLiteral(const StringLiteral *SL) {
1517e5dd7070Spatrick   std::string Buffer;
1518e5dd7070Spatrick   llvm::raw_string_ostream SS(Buffer);
1519e5dd7070Spatrick   SL->outputString(SS);
1520e5dd7070Spatrick   JOS.attribute("value", SS.str());
1521e5dd7070Spatrick }
VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr * BLE)1522e5dd7070Spatrick void JSONNodeDumper::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *BLE) {
1523e5dd7070Spatrick   JOS.attribute("value", BLE->getValue());
1524e5dd7070Spatrick }
1525e5dd7070Spatrick 
VisitIfStmt(const IfStmt * IS)1526e5dd7070Spatrick void JSONNodeDumper::VisitIfStmt(const IfStmt *IS) {
1527e5dd7070Spatrick   attributeOnlyIfTrue("hasInit", IS->hasInitStorage());
1528e5dd7070Spatrick   attributeOnlyIfTrue("hasVar", IS->hasVarStorage());
1529e5dd7070Spatrick   attributeOnlyIfTrue("hasElse", IS->hasElseStorage());
1530e5dd7070Spatrick   attributeOnlyIfTrue("isConstexpr", IS->isConstexpr());
1531*12c85518Srobert   attributeOnlyIfTrue("isConsteval", IS->isConsteval());
1532*12c85518Srobert   attributeOnlyIfTrue("constevalIsNegated", IS->isNegatedConsteval());
1533e5dd7070Spatrick }
1534e5dd7070Spatrick 
VisitSwitchStmt(const SwitchStmt * SS)1535e5dd7070Spatrick void JSONNodeDumper::VisitSwitchStmt(const SwitchStmt *SS) {
1536e5dd7070Spatrick   attributeOnlyIfTrue("hasInit", SS->hasInitStorage());
1537e5dd7070Spatrick   attributeOnlyIfTrue("hasVar", SS->hasVarStorage());
1538e5dd7070Spatrick }
VisitCaseStmt(const CaseStmt * CS)1539e5dd7070Spatrick void JSONNodeDumper::VisitCaseStmt(const CaseStmt *CS) {
1540e5dd7070Spatrick   attributeOnlyIfTrue("isGNURange", CS->caseStmtIsGNURange());
1541e5dd7070Spatrick }
1542e5dd7070Spatrick 
VisitLabelStmt(const LabelStmt * LS)1543e5dd7070Spatrick void JSONNodeDumper::VisitLabelStmt(const LabelStmt *LS) {
1544e5dd7070Spatrick   JOS.attribute("name", LS->getName());
1545e5dd7070Spatrick   JOS.attribute("declId", createPointerRepresentation(LS->getDecl()));
1546a9ac8606Spatrick   attributeOnlyIfTrue("sideEntry", LS->isSideEntry());
1547e5dd7070Spatrick }
VisitGotoStmt(const GotoStmt * GS)1548e5dd7070Spatrick void JSONNodeDumper::VisitGotoStmt(const GotoStmt *GS) {
1549e5dd7070Spatrick   JOS.attribute("targetLabelDeclId",
1550e5dd7070Spatrick                 createPointerRepresentation(GS->getLabel()));
1551e5dd7070Spatrick }
1552e5dd7070Spatrick 
VisitWhileStmt(const WhileStmt * WS)1553e5dd7070Spatrick void JSONNodeDumper::VisitWhileStmt(const WhileStmt *WS) {
1554e5dd7070Spatrick   attributeOnlyIfTrue("hasVar", WS->hasVarStorage());
1555e5dd7070Spatrick }
1556e5dd7070Spatrick 
VisitObjCAtCatchStmt(const ObjCAtCatchStmt * OACS)1557e5dd7070Spatrick void JSONNodeDumper::VisitObjCAtCatchStmt(const ObjCAtCatchStmt* OACS) {
1558e5dd7070Spatrick   // FIXME: it would be nice for the ASTNodeTraverser would handle the catch
1559e5dd7070Spatrick   // parameter the same way for C++ and ObjC rather. In this case, C++ gets a
1560e5dd7070Spatrick   // null child node and ObjC gets no child node.
1561e5dd7070Spatrick   attributeOnlyIfTrue("isCatchAll", OACS->getCatchParamDecl() == nullptr);
1562e5dd7070Spatrick }
1563e5dd7070Spatrick 
VisitNullTemplateArgument(const TemplateArgument & TA)1564e5dd7070Spatrick void JSONNodeDumper::VisitNullTemplateArgument(const TemplateArgument &TA) {
1565e5dd7070Spatrick   JOS.attribute("isNull", true);
1566e5dd7070Spatrick }
VisitTypeTemplateArgument(const TemplateArgument & TA)1567e5dd7070Spatrick void JSONNodeDumper::VisitTypeTemplateArgument(const TemplateArgument &TA) {
1568e5dd7070Spatrick   JOS.attribute("type", createQualType(TA.getAsType()));
1569e5dd7070Spatrick }
VisitDeclarationTemplateArgument(const TemplateArgument & TA)1570e5dd7070Spatrick void JSONNodeDumper::VisitDeclarationTemplateArgument(
1571e5dd7070Spatrick     const TemplateArgument &TA) {
1572e5dd7070Spatrick   JOS.attribute("decl", createBareDeclRef(TA.getAsDecl()));
1573e5dd7070Spatrick }
VisitNullPtrTemplateArgument(const TemplateArgument & TA)1574e5dd7070Spatrick void JSONNodeDumper::VisitNullPtrTemplateArgument(const TemplateArgument &TA) {
1575e5dd7070Spatrick   JOS.attribute("isNullptr", true);
1576e5dd7070Spatrick }
VisitIntegralTemplateArgument(const TemplateArgument & TA)1577e5dd7070Spatrick void JSONNodeDumper::VisitIntegralTemplateArgument(const TemplateArgument &TA) {
1578e5dd7070Spatrick   JOS.attribute("value", TA.getAsIntegral().getSExtValue());
1579e5dd7070Spatrick }
VisitTemplateTemplateArgument(const TemplateArgument & TA)1580e5dd7070Spatrick void JSONNodeDumper::VisitTemplateTemplateArgument(const TemplateArgument &TA) {
1581e5dd7070Spatrick   // FIXME: cannot just call dump() on the argument, as that doesn't specify
1582e5dd7070Spatrick   // the output format.
1583e5dd7070Spatrick }
VisitTemplateExpansionTemplateArgument(const TemplateArgument & TA)1584e5dd7070Spatrick void JSONNodeDumper::VisitTemplateExpansionTemplateArgument(
1585e5dd7070Spatrick     const TemplateArgument &TA) {
1586e5dd7070Spatrick   // FIXME: cannot just call dump() on the argument, as that doesn't specify
1587e5dd7070Spatrick   // the output format.
1588e5dd7070Spatrick }
VisitExpressionTemplateArgument(const TemplateArgument & TA)1589e5dd7070Spatrick void JSONNodeDumper::VisitExpressionTemplateArgument(
1590e5dd7070Spatrick     const TemplateArgument &TA) {
1591e5dd7070Spatrick   JOS.attribute("isExpr", true);
1592e5dd7070Spatrick }
VisitPackTemplateArgument(const TemplateArgument & TA)1593e5dd7070Spatrick void JSONNodeDumper::VisitPackTemplateArgument(const TemplateArgument &TA) {
1594e5dd7070Spatrick   JOS.attribute("isPack", true);
1595e5dd7070Spatrick }
1596e5dd7070Spatrick 
getCommentCommandName(unsigned CommandID) const1597e5dd7070Spatrick StringRef JSONNodeDumper::getCommentCommandName(unsigned CommandID) const {
1598e5dd7070Spatrick   if (Traits)
1599e5dd7070Spatrick     return Traits->getCommandInfo(CommandID)->Name;
1600e5dd7070Spatrick   if (const comments::CommandInfo *Info =
1601e5dd7070Spatrick           comments::CommandTraits::getBuiltinCommandInfo(CommandID))
1602e5dd7070Spatrick     return Info->Name;
1603e5dd7070Spatrick   return "<invalid>";
1604e5dd7070Spatrick }
1605e5dd7070Spatrick 
visitTextComment(const comments::TextComment * C,const comments::FullComment *)1606e5dd7070Spatrick void JSONNodeDumper::visitTextComment(const comments::TextComment *C,
1607e5dd7070Spatrick                                       const comments::FullComment *) {
1608e5dd7070Spatrick   JOS.attribute("text", C->getText());
1609e5dd7070Spatrick }
1610e5dd7070Spatrick 
visitInlineCommandComment(const comments::InlineCommandComment * C,const comments::FullComment *)1611e5dd7070Spatrick void JSONNodeDumper::visitInlineCommandComment(
1612e5dd7070Spatrick     const comments::InlineCommandComment *C, const comments::FullComment *) {
1613e5dd7070Spatrick   JOS.attribute("name", getCommentCommandName(C->getCommandID()));
1614e5dd7070Spatrick 
1615e5dd7070Spatrick   switch (C->getRenderKind()) {
1616e5dd7070Spatrick   case comments::InlineCommandComment::RenderNormal:
1617e5dd7070Spatrick     JOS.attribute("renderKind", "normal");
1618e5dd7070Spatrick     break;
1619e5dd7070Spatrick   case comments::InlineCommandComment::RenderBold:
1620e5dd7070Spatrick     JOS.attribute("renderKind", "bold");
1621e5dd7070Spatrick     break;
1622e5dd7070Spatrick   case comments::InlineCommandComment::RenderEmphasized:
1623e5dd7070Spatrick     JOS.attribute("renderKind", "emphasized");
1624e5dd7070Spatrick     break;
1625e5dd7070Spatrick   case comments::InlineCommandComment::RenderMonospaced:
1626e5dd7070Spatrick     JOS.attribute("renderKind", "monospaced");
1627e5dd7070Spatrick     break;
1628e5dd7070Spatrick   case comments::InlineCommandComment::RenderAnchor:
1629e5dd7070Spatrick     JOS.attribute("renderKind", "anchor");
1630e5dd7070Spatrick     break;
1631e5dd7070Spatrick   }
1632e5dd7070Spatrick 
1633e5dd7070Spatrick   llvm::json::Array Args;
1634e5dd7070Spatrick   for (unsigned I = 0, E = C->getNumArgs(); I < E; ++I)
1635e5dd7070Spatrick     Args.push_back(C->getArgText(I));
1636e5dd7070Spatrick 
1637e5dd7070Spatrick   if (!Args.empty())
1638e5dd7070Spatrick     JOS.attribute("args", std::move(Args));
1639e5dd7070Spatrick }
1640e5dd7070Spatrick 
visitHTMLStartTagComment(const comments::HTMLStartTagComment * C,const comments::FullComment *)1641e5dd7070Spatrick void JSONNodeDumper::visitHTMLStartTagComment(
1642e5dd7070Spatrick     const comments::HTMLStartTagComment *C, const comments::FullComment *) {
1643e5dd7070Spatrick   JOS.attribute("name", C->getTagName());
1644e5dd7070Spatrick   attributeOnlyIfTrue("selfClosing", C->isSelfClosing());
1645e5dd7070Spatrick   attributeOnlyIfTrue("malformed", C->isMalformed());
1646e5dd7070Spatrick 
1647e5dd7070Spatrick   llvm::json::Array Attrs;
1648e5dd7070Spatrick   for (unsigned I = 0, E = C->getNumAttrs(); I < E; ++I)
1649e5dd7070Spatrick     Attrs.push_back(
1650e5dd7070Spatrick         {{"name", C->getAttr(I).Name}, {"value", C->getAttr(I).Value}});
1651e5dd7070Spatrick 
1652e5dd7070Spatrick   if (!Attrs.empty())
1653e5dd7070Spatrick     JOS.attribute("attrs", std::move(Attrs));
1654e5dd7070Spatrick }
1655e5dd7070Spatrick 
visitHTMLEndTagComment(const comments::HTMLEndTagComment * C,const comments::FullComment *)1656e5dd7070Spatrick void JSONNodeDumper::visitHTMLEndTagComment(
1657e5dd7070Spatrick     const comments::HTMLEndTagComment *C, const comments::FullComment *) {
1658e5dd7070Spatrick   JOS.attribute("name", C->getTagName());
1659e5dd7070Spatrick }
1660e5dd7070Spatrick 
visitBlockCommandComment(const comments::BlockCommandComment * C,const comments::FullComment *)1661e5dd7070Spatrick void JSONNodeDumper::visitBlockCommandComment(
1662e5dd7070Spatrick     const comments::BlockCommandComment *C, const comments::FullComment *) {
1663e5dd7070Spatrick   JOS.attribute("name", getCommentCommandName(C->getCommandID()));
1664e5dd7070Spatrick 
1665e5dd7070Spatrick   llvm::json::Array Args;
1666e5dd7070Spatrick   for (unsigned I = 0, E = C->getNumArgs(); I < E; ++I)
1667e5dd7070Spatrick     Args.push_back(C->getArgText(I));
1668e5dd7070Spatrick 
1669e5dd7070Spatrick   if (!Args.empty())
1670e5dd7070Spatrick     JOS.attribute("args", std::move(Args));
1671e5dd7070Spatrick }
1672e5dd7070Spatrick 
visitParamCommandComment(const comments::ParamCommandComment * C,const comments::FullComment * FC)1673e5dd7070Spatrick void JSONNodeDumper::visitParamCommandComment(
1674e5dd7070Spatrick     const comments::ParamCommandComment *C, const comments::FullComment *FC) {
1675e5dd7070Spatrick   switch (C->getDirection()) {
1676e5dd7070Spatrick   case comments::ParamCommandComment::In:
1677e5dd7070Spatrick     JOS.attribute("direction", "in");
1678e5dd7070Spatrick     break;
1679e5dd7070Spatrick   case comments::ParamCommandComment::Out:
1680e5dd7070Spatrick     JOS.attribute("direction", "out");
1681e5dd7070Spatrick     break;
1682e5dd7070Spatrick   case comments::ParamCommandComment::InOut:
1683e5dd7070Spatrick     JOS.attribute("direction", "in,out");
1684e5dd7070Spatrick     break;
1685e5dd7070Spatrick   }
1686e5dd7070Spatrick   attributeOnlyIfTrue("explicit", C->isDirectionExplicit());
1687e5dd7070Spatrick 
1688e5dd7070Spatrick   if (C->hasParamName())
1689e5dd7070Spatrick     JOS.attribute("param", C->isParamIndexValid() ? C->getParamName(FC)
1690e5dd7070Spatrick                                                   : C->getParamNameAsWritten());
1691e5dd7070Spatrick 
1692e5dd7070Spatrick   if (C->isParamIndexValid() && !C->isVarArgParam())
1693e5dd7070Spatrick     JOS.attribute("paramIdx", C->getParamIndex());
1694e5dd7070Spatrick }
1695e5dd7070Spatrick 
visitTParamCommandComment(const comments::TParamCommandComment * C,const comments::FullComment * FC)1696e5dd7070Spatrick void JSONNodeDumper::visitTParamCommandComment(
1697e5dd7070Spatrick     const comments::TParamCommandComment *C, const comments::FullComment *FC) {
1698e5dd7070Spatrick   if (C->hasParamName())
1699e5dd7070Spatrick     JOS.attribute("param", C->isPositionValid() ? C->getParamName(FC)
1700e5dd7070Spatrick                                                 : C->getParamNameAsWritten());
1701e5dd7070Spatrick   if (C->isPositionValid()) {
1702e5dd7070Spatrick     llvm::json::Array Positions;
1703e5dd7070Spatrick     for (unsigned I = 0, E = C->getDepth(); I < E; ++I)
1704e5dd7070Spatrick       Positions.push_back(C->getIndex(I));
1705e5dd7070Spatrick 
1706e5dd7070Spatrick     if (!Positions.empty())
1707e5dd7070Spatrick       JOS.attribute("positions", std::move(Positions));
1708e5dd7070Spatrick   }
1709e5dd7070Spatrick }
1710e5dd7070Spatrick 
visitVerbatimBlockComment(const comments::VerbatimBlockComment * C,const comments::FullComment *)1711e5dd7070Spatrick void JSONNodeDumper::visitVerbatimBlockComment(
1712e5dd7070Spatrick     const comments::VerbatimBlockComment *C, const comments::FullComment *) {
1713e5dd7070Spatrick   JOS.attribute("name", getCommentCommandName(C->getCommandID()));
1714e5dd7070Spatrick   JOS.attribute("closeName", C->getCloseName());
1715e5dd7070Spatrick }
1716e5dd7070Spatrick 
visitVerbatimBlockLineComment(const comments::VerbatimBlockLineComment * C,const comments::FullComment *)1717e5dd7070Spatrick void JSONNodeDumper::visitVerbatimBlockLineComment(
1718e5dd7070Spatrick     const comments::VerbatimBlockLineComment *C,
1719e5dd7070Spatrick     const comments::FullComment *) {
1720e5dd7070Spatrick   JOS.attribute("text", C->getText());
1721e5dd7070Spatrick }
1722e5dd7070Spatrick 
visitVerbatimLineComment(const comments::VerbatimLineComment * C,const comments::FullComment *)1723e5dd7070Spatrick void JSONNodeDumper::visitVerbatimLineComment(
1724e5dd7070Spatrick     const comments::VerbatimLineComment *C, const comments::FullComment *) {
1725e5dd7070Spatrick   JOS.attribute("text", C->getText());
1726e5dd7070Spatrick }
1727*12c85518Srobert 
createFPOptions(FPOptionsOverride FPO)1728*12c85518Srobert llvm::json::Object JSONNodeDumper::createFPOptions(FPOptionsOverride FPO) {
1729*12c85518Srobert   llvm::json::Object Ret;
1730*12c85518Srobert #define OPTION(NAME, TYPE, WIDTH, PREVIOUS)                                    \
1731*12c85518Srobert   if (FPO.has##NAME##Override())                                               \
1732*12c85518Srobert     Ret.try_emplace(#NAME, static_cast<unsigned>(FPO.get##NAME##Override()));
1733*12c85518Srobert #include "clang/Basic/FPOptions.def"
1734*12c85518Srobert   return Ret;
1735*12c85518Srobert }
1736*12c85518Srobert 
VisitCompoundStmt(const CompoundStmt * S)1737*12c85518Srobert void JSONNodeDumper::VisitCompoundStmt(const CompoundStmt *S) {
1738*12c85518Srobert   VisitStmt(S);
1739*12c85518Srobert   if (S->hasStoredFPFeatures())
1740*12c85518Srobert     JOS.attribute("fpoptions", createFPOptions(S->getStoredFPFeatures()));
1741*12c85518Srobert }
1742