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