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