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