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