1 //===--- JSONNodeDumper.h - Printing of AST nodes to JSON -----------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements AST dumping of components of individual AST nodes to 10 // a JSON. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_CLANG_AST_JSONNODEDUMPER_H 15 #define LLVM_CLANG_AST_JSONNODEDUMPER_H 16 17 #include "clang/AST/ASTContext.h" 18 #include "clang/AST/ASTDumperUtils.h" 19 #include "clang/AST/ASTNodeTraverser.h" 20 #include "clang/AST/AttrVisitor.h" 21 #include "clang/AST/CommentCommandTraits.h" 22 #include "clang/AST/CommentVisitor.h" 23 #include "clang/AST/ExprConcepts.h" 24 #include "clang/AST/ExprCXX.h" 25 #include "clang/AST/Mangle.h" 26 #include "clang/AST/Type.h" 27 #include "llvm/Support/JSON.h" 28 29 namespace clang { 30 31 class APValue; 32 33 class NodeStreamer { 34 bool FirstChild = true; 35 bool TopLevel = true; 36 llvm::SmallVector<std::function<void(bool IsLastChild)>, 32> Pending; 37 38 protected: 39 llvm::json::OStream JOS; 40 41 public: 42 /// Add a child of the current node. Calls DoAddChild without arguments AddChild(Fn DoAddChild)43 template <typename Fn> void AddChild(Fn DoAddChild) { 44 return AddChild("", DoAddChild); 45 } 46 47 /// Add a child of the current node with an optional label. 48 /// Calls DoAddChild without arguments. AddChild(StringRef Label,Fn DoAddChild)49 template <typename Fn> void AddChild(StringRef Label, Fn DoAddChild) { 50 // If we're at the top level, there's nothing interesting to do; just 51 // run the dumper. 52 if (TopLevel) { 53 TopLevel = false; 54 JOS.objectBegin(); 55 56 DoAddChild(); 57 58 while (!Pending.empty()) { 59 Pending.back()(true); 60 Pending.pop_back(); 61 } 62 63 JOS.objectEnd(); 64 TopLevel = true; 65 return; 66 } 67 68 // We need to capture an owning-string in the lambda because the lambda 69 // is invoked in a deferred manner. 70 std::string LabelStr(!Label.empty() ? Label : "inner"); 71 bool WasFirstChild = FirstChild; 72 auto DumpWithIndent = [=](bool IsLastChild) { 73 if (WasFirstChild) { 74 JOS.attributeBegin(LabelStr); 75 JOS.arrayBegin(); 76 } 77 78 FirstChild = true; 79 unsigned Depth = Pending.size(); 80 JOS.objectBegin(); 81 82 DoAddChild(); 83 84 // If any children are left, they're the last at their nesting level. 85 // Dump those ones out now. 86 while (Depth < Pending.size()) { 87 Pending.back()(true); 88 this->Pending.pop_back(); 89 } 90 91 JOS.objectEnd(); 92 93 if (IsLastChild) { 94 JOS.arrayEnd(); 95 JOS.attributeEnd(); 96 } 97 }; 98 99 if (FirstChild) { 100 Pending.push_back(std::move(DumpWithIndent)); 101 } else { 102 Pending.back()(false); 103 Pending.back() = std::move(DumpWithIndent); 104 } 105 FirstChild = false; 106 } 107 NodeStreamer(raw_ostream & OS)108 NodeStreamer(raw_ostream &OS) : JOS(OS, 2) {} 109 }; 110 111 // Dumps AST nodes in JSON format. There is no implied stability for the 112 // content or format of the dump between major releases of Clang, other than it 113 // being valid JSON output. Further, there is no requirement that the 114 // information dumped is a complete representation of the AST, only that the 115 // information presented is correct. 116 class JSONNodeDumper 117 : public ConstAttrVisitor<JSONNodeDumper>, 118 public comments::ConstCommentVisitor<JSONNodeDumper, void, 119 const comments::FullComment *>, 120 public ConstTemplateArgumentVisitor<JSONNodeDumper>, 121 public ConstStmtVisitor<JSONNodeDumper>, 122 public TypeVisitor<JSONNodeDumper>, 123 public ConstDeclVisitor<JSONNodeDumper>, 124 public NodeStreamer { 125 friend class JSONDumper; 126 127 const SourceManager &SM; 128 ASTContext& Ctx; 129 ASTNameGenerator ASTNameGen; 130 PrintingPolicy PrintPolicy; 131 const comments::CommandTraits *Traits; 132 StringRef LastLocFilename, LastLocPresumedFilename; 133 unsigned LastLocLine, LastLocPresumedLine; 134 135 using InnerAttrVisitor = ConstAttrVisitor<JSONNodeDumper>; 136 using InnerCommentVisitor = 137 comments::ConstCommentVisitor<JSONNodeDumper, void, 138 const comments::FullComment *>; 139 using InnerTemplateArgVisitor = ConstTemplateArgumentVisitor<JSONNodeDumper>; 140 using InnerStmtVisitor = ConstStmtVisitor<JSONNodeDumper>; 141 using InnerTypeVisitor = TypeVisitor<JSONNodeDumper>; 142 using InnerDeclVisitor = ConstDeclVisitor<JSONNodeDumper>; 143 attributeOnlyIfTrue(StringRef Key,bool Value)144 void attributeOnlyIfTrue(StringRef Key, bool Value) { 145 if (Value) 146 JOS.attribute(Key, Value); 147 } 148 149 void writeIncludeStack(PresumedLoc Loc, bool JustFirst = false); 150 151 // Writes the attributes of a SourceLocation object without. 152 void writeBareSourceLocation(SourceLocation Loc, bool IsSpelling); 153 154 // Writes the attributes of a SourceLocation to JSON based on its presumed 155 // spelling location. If the given location represents a macro invocation, 156 // this outputs two sub-objects: one for the spelling and one for the 157 // expansion location. 158 void writeSourceLocation(SourceLocation Loc); 159 void writeSourceRange(SourceRange R); 160 std::string createPointerRepresentation(const void *Ptr); 161 llvm::json::Object createQualType(QualType QT, bool Desugar = true); 162 llvm::json::Object createBareDeclRef(const Decl *D); 163 llvm::json::Object createFPOptions(FPOptionsOverride FPO); 164 void writeBareDeclRef(const Decl *D); 165 llvm::json::Object createCXXRecordDefinitionData(const CXXRecordDecl *RD); 166 llvm::json::Object createCXXBaseSpecifier(const CXXBaseSpecifier &BS); 167 std::string createAccessSpecifier(AccessSpecifier AS); 168 llvm::json::Array createCastPath(const CastExpr *C); 169 writePreviousDeclImpl(...)170 void writePreviousDeclImpl(...) {} 171 writePreviousDeclImpl(const Mergeable<T> * D)172 template <typename T> void writePreviousDeclImpl(const Mergeable<T> *D) { 173 const T *First = D->getFirstDecl(); 174 if (First != D) 175 JOS.attribute("firstRedecl", createPointerRepresentation(First)); 176 } 177 writePreviousDeclImpl(const Redeclarable<T> * D)178 template <typename T> void writePreviousDeclImpl(const Redeclarable<T> *D) { 179 const T *Prev = D->getPreviousDecl(); 180 if (Prev) 181 JOS.attribute("previousDecl", createPointerRepresentation(Prev)); 182 } 183 void addPreviousDeclaration(const Decl *D); 184 185 StringRef getCommentCommandName(unsigned CommandID) const; 186 187 public: JSONNodeDumper(raw_ostream & OS,const SourceManager & SrcMgr,ASTContext & Ctx,const PrintingPolicy & PrintPolicy,const comments::CommandTraits * Traits)188 JSONNodeDumper(raw_ostream &OS, const SourceManager &SrcMgr, ASTContext &Ctx, 189 const PrintingPolicy &PrintPolicy, 190 const comments::CommandTraits *Traits) 191 : NodeStreamer(OS), SM(SrcMgr), Ctx(Ctx), ASTNameGen(Ctx), 192 PrintPolicy(PrintPolicy), Traits(Traits), LastLocLine(0), 193 LastLocPresumedLine(0) {} 194 195 void Visit(const Attr *A); 196 void Visit(const Stmt *Node); 197 void Visit(const Type *T); 198 void Visit(QualType T); 199 void Visit(const Decl *D); 200 void Visit(TypeLoc TL); 201 202 void Visit(const comments::Comment *C, const comments::FullComment *FC); 203 void Visit(const TemplateArgument &TA, SourceRange R = {}, 204 const Decl *From = nullptr, StringRef Label = {}); 205 void Visit(const CXXCtorInitializer *Init); 206 void Visit(const OpenACCClause *C); 207 void Visit(const OMPClause *C); 208 void Visit(const BlockDecl::Capture &C); 209 void Visit(const GenericSelectionExpr::ConstAssociation &A); 210 void Visit(const concepts::Requirement *R); 211 void Visit(const APValue &Value, QualType Ty); 212 void Visit(const ConceptReference *); 213 214 void VisitAliasAttr(const AliasAttr *AA); 215 void VisitCleanupAttr(const CleanupAttr *CA); 216 void VisitDeprecatedAttr(const DeprecatedAttr *DA); 217 void VisitUnavailableAttr(const UnavailableAttr *UA); 218 void VisitSectionAttr(const SectionAttr *SA); 219 void VisitVisibilityAttr(const VisibilityAttr *VA); 220 void VisitTLSModelAttr(const TLSModelAttr *TA); 221 222 void VisitTypedefType(const TypedefType *TT); 223 void VisitUsingType(const UsingType *TT); 224 void VisitFunctionType(const FunctionType *T); 225 void VisitFunctionProtoType(const FunctionProtoType *T); 226 void VisitRValueReferenceType(const ReferenceType *RT); 227 void VisitArrayType(const ArrayType *AT); 228 void VisitConstantArrayType(const ConstantArrayType *CAT); 229 void VisitDependentSizedExtVectorType(const DependentSizedExtVectorType *VT); 230 void VisitVectorType(const VectorType *VT); 231 void VisitUnresolvedUsingType(const UnresolvedUsingType *UUT); 232 void VisitUnaryTransformType(const UnaryTransformType *UTT); 233 void VisitTagType(const TagType *TT); 234 void VisitTemplateTypeParmType(const TemplateTypeParmType *TTPT); 235 void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *STTPT); 236 void 237 VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T); 238 void VisitAutoType(const AutoType *AT); 239 void VisitTemplateSpecializationType(const TemplateSpecializationType *TST); 240 void VisitInjectedClassNameType(const InjectedClassNameType *ICNT); 241 void VisitObjCInterfaceType(const ObjCInterfaceType *OIT); 242 void VisitPackExpansionType(const PackExpansionType *PET); 243 void VisitElaboratedType(const ElaboratedType *ET); 244 void VisitMacroQualifiedType(const MacroQualifiedType *MQT); 245 void VisitMemberPointerType(const MemberPointerType *MPT); 246 247 void VisitNamedDecl(const NamedDecl *ND); 248 void VisitTypedefDecl(const TypedefDecl *TD); 249 void VisitTypeAliasDecl(const TypeAliasDecl *TAD); 250 void VisitNamespaceDecl(const NamespaceDecl *ND); 251 void VisitUsingDirectiveDecl(const UsingDirectiveDecl *UDD); 252 void VisitNamespaceAliasDecl(const NamespaceAliasDecl *NAD); 253 void VisitUsingDecl(const UsingDecl *UD); 254 void VisitUsingEnumDecl(const UsingEnumDecl *UED); 255 void VisitUsingShadowDecl(const UsingShadowDecl *USD); 256 void VisitVarDecl(const VarDecl *VD); 257 void VisitFieldDecl(const FieldDecl *FD); 258 void VisitFunctionDecl(const FunctionDecl *FD); 259 void VisitEnumDecl(const EnumDecl *ED); 260 void VisitEnumConstantDecl(const EnumConstantDecl *ECD); 261 void VisitRecordDecl(const RecordDecl *RD); 262 void VisitCXXRecordDecl(const CXXRecordDecl *RD); 263 void VisitHLSLBufferDecl(const HLSLBufferDecl *D); 264 void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D); 265 void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D); 266 void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D); 267 void VisitLinkageSpecDecl(const LinkageSpecDecl *LSD); 268 void VisitAccessSpecDecl(const AccessSpecDecl *ASD); 269 void VisitFriendDecl(const FriendDecl *FD); 270 271 void VisitObjCIvarDecl(const ObjCIvarDecl *D); 272 void VisitObjCMethodDecl(const ObjCMethodDecl *D); 273 void VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D); 274 void VisitObjCCategoryDecl(const ObjCCategoryDecl *D); 275 void VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D); 276 void VisitObjCProtocolDecl(const ObjCProtocolDecl *D); 277 void VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D); 278 void VisitObjCImplementationDecl(const ObjCImplementationDecl *D); 279 void VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D); 280 void VisitObjCPropertyDecl(const ObjCPropertyDecl *D); 281 void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D); 282 void VisitBlockDecl(const BlockDecl *D); 283 284 void VisitDeclRefExpr(const DeclRefExpr *DRE); 285 void VisitSYCLUniqueStableNameExpr(const SYCLUniqueStableNameExpr *E); 286 void VisitPredefinedExpr(const PredefinedExpr *PE); 287 void VisitUnaryOperator(const UnaryOperator *UO); 288 void VisitBinaryOperator(const BinaryOperator *BO); 289 void VisitCompoundAssignOperator(const CompoundAssignOperator *CAO); 290 void VisitMemberExpr(const MemberExpr *ME); 291 void VisitAtomicExpr(const AtomicExpr *AE); 292 void VisitCXXNewExpr(const CXXNewExpr *NE); 293 void VisitCXXDeleteExpr(const CXXDeleteExpr *DE); 294 void VisitCXXThisExpr(const CXXThisExpr *TE); 295 void VisitCastExpr(const CastExpr *CE); 296 void VisitImplicitCastExpr(const ImplicitCastExpr *ICE); 297 void VisitCallExpr(const CallExpr *CE); 298 void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *TTE); 299 void VisitSizeOfPackExpr(const SizeOfPackExpr *SOPE); 300 void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *ULE); 301 void VisitAddrLabelExpr(const AddrLabelExpr *ALE); 302 void VisitCXXTypeidExpr(const CXXTypeidExpr *CTE); 303 void VisitConstantExpr(const ConstantExpr *CE); 304 void VisitInitListExpr(const InitListExpr *ILE); 305 void VisitGenericSelectionExpr(const GenericSelectionExpr *GSE); 306 void VisitCXXUnresolvedConstructExpr(const CXXUnresolvedConstructExpr *UCE); 307 void VisitCXXConstructExpr(const CXXConstructExpr *CE); 308 void VisitExprWithCleanups(const ExprWithCleanups *EWC); 309 void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE); 310 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *MTE); 311 void VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *ME); 312 void VisitRequiresExpr(const RequiresExpr *RE); 313 void VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *Node); 314 void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *Node); 315 316 void VisitObjCEncodeExpr(const ObjCEncodeExpr *OEE); 317 void VisitObjCMessageExpr(const ObjCMessageExpr *OME); 318 void VisitObjCBoxedExpr(const ObjCBoxedExpr *OBE); 319 void VisitObjCSelectorExpr(const ObjCSelectorExpr *OSE); 320 void VisitObjCProtocolExpr(const ObjCProtocolExpr *OPE); 321 void VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *OPRE); 322 void VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *OSRE); 323 void VisitObjCIvarRefExpr(const ObjCIvarRefExpr *OIRE); 324 void VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *OBLE); 325 326 void VisitIntegerLiteral(const IntegerLiteral *IL); 327 void VisitCharacterLiteral(const CharacterLiteral *CL); 328 void VisitFixedPointLiteral(const FixedPointLiteral *FPL); 329 void VisitFloatingLiteral(const FloatingLiteral *FL); 330 void VisitStringLiteral(const StringLiteral *SL); 331 void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *BLE); 332 333 void VisitIfStmt(const IfStmt *IS); 334 void VisitSwitchStmt(const SwitchStmt *SS); 335 void VisitCaseStmt(const CaseStmt *CS); 336 void VisitLabelStmt(const LabelStmt *LS); 337 void VisitGotoStmt(const GotoStmt *GS); 338 void VisitWhileStmt(const WhileStmt *WS); 339 void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *OACS); 340 void VisitCompoundStmt(const CompoundStmt *IS); 341 342 void VisitNullTemplateArgument(const TemplateArgument &TA); 343 void VisitTypeTemplateArgument(const TemplateArgument &TA); 344 void VisitDeclarationTemplateArgument(const TemplateArgument &TA); 345 void VisitNullPtrTemplateArgument(const TemplateArgument &TA); 346 void VisitIntegralTemplateArgument(const TemplateArgument &TA); 347 void VisitTemplateTemplateArgument(const TemplateArgument &TA); 348 void VisitTemplateExpansionTemplateArgument(const TemplateArgument &TA); 349 void VisitExpressionTemplateArgument(const TemplateArgument &TA); 350 void VisitPackTemplateArgument(const TemplateArgument &TA); 351 352 void visitTextComment(const comments::TextComment *C, 353 const comments::FullComment *); 354 void visitInlineCommandComment(const comments::InlineCommandComment *C, 355 const comments::FullComment *); 356 void visitHTMLStartTagComment(const comments::HTMLStartTagComment *C, 357 const comments::FullComment *); 358 void visitHTMLEndTagComment(const comments::HTMLEndTagComment *C, 359 const comments::FullComment *); 360 void visitBlockCommandComment(const comments::BlockCommandComment *C, 361 const comments::FullComment *); 362 void visitParamCommandComment(const comments::ParamCommandComment *C, 363 const comments::FullComment *FC); 364 void visitTParamCommandComment(const comments::TParamCommandComment *C, 365 const comments::FullComment *FC); 366 void visitVerbatimBlockComment(const comments::VerbatimBlockComment *C, 367 const comments::FullComment *); 368 void 369 visitVerbatimBlockLineComment(const comments::VerbatimBlockLineComment *C, 370 const comments::FullComment *); 371 void visitVerbatimLineComment(const comments::VerbatimLineComment *C, 372 const comments::FullComment *); 373 }; 374 375 class JSONDumper : public ASTNodeTraverser<JSONDumper, JSONNodeDumper> { 376 JSONNodeDumper NodeDumper; 377 378 template <typename SpecializationDecl> writeTemplateDeclSpecialization(const SpecializationDecl * SD,bool DumpExplicitInst,bool DumpRefOnly)379 void writeTemplateDeclSpecialization(const SpecializationDecl *SD, 380 bool DumpExplicitInst, 381 bool DumpRefOnly) { 382 bool DumpedAny = false; 383 for (const auto *RedeclWithBadType : SD->redecls()) { 384 // FIXME: The redecls() range sometimes has elements of a less-specific 385 // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives 386 // us TagDecls, and should give CXXRecordDecls). 387 const auto *Redecl = dyn_cast<SpecializationDecl>(RedeclWithBadType); 388 if (!Redecl) { 389 // Found the injected-class-name for a class template. This will be 390 // dumped as part of its surrounding class so we don't need to dump it 391 // here. 392 assert(isa<CXXRecordDecl>(RedeclWithBadType) && 393 "expected an injected-class-name"); 394 continue; 395 } 396 397 switch (Redecl->getTemplateSpecializationKind()) { 398 case TSK_ExplicitInstantiationDeclaration: 399 case TSK_ExplicitInstantiationDefinition: 400 if (!DumpExplicitInst) 401 break; 402 [[fallthrough]]; 403 case TSK_Undeclared: 404 case TSK_ImplicitInstantiation: 405 if (DumpRefOnly) 406 NodeDumper.AddChild([=] { NodeDumper.writeBareDeclRef(Redecl); }); 407 else 408 Visit(Redecl); 409 DumpedAny = true; 410 break; 411 case TSK_ExplicitSpecialization: 412 break; 413 } 414 } 415 416 // Ensure we dump at least one decl for each specialization. 417 if (!DumpedAny) 418 NodeDumper.AddChild([=] { NodeDumper.writeBareDeclRef(SD); }); 419 } 420 421 template <typename TemplateDecl> writeTemplateDecl(const TemplateDecl * TD,bool DumpExplicitInst)422 void writeTemplateDecl(const TemplateDecl *TD, bool DumpExplicitInst) { 423 // FIXME: it would be nice to dump template parameters and specializations 424 // to their own named arrays rather than shoving them into the "inner" 425 // array. However, template declarations are currently being handled at the 426 // wrong "level" of the traversal hierarchy and so it is difficult to 427 // achieve without losing information elsewhere. 428 429 dumpTemplateParameters(TD->getTemplateParameters()); 430 431 Visit(TD->getTemplatedDecl()); 432 433 for (const auto *Child : TD->specializations()) 434 writeTemplateDeclSpecialization(Child, DumpExplicitInst, 435 !TD->isCanonicalDecl()); 436 } 437 438 public: JSONDumper(raw_ostream & OS,const SourceManager & SrcMgr,ASTContext & Ctx,const PrintingPolicy & PrintPolicy,const comments::CommandTraits * Traits)439 JSONDumper(raw_ostream &OS, const SourceManager &SrcMgr, ASTContext &Ctx, 440 const PrintingPolicy &PrintPolicy, 441 const comments::CommandTraits *Traits) 442 : NodeDumper(OS, SrcMgr, Ctx, PrintPolicy, Traits) {} 443 doGetNodeDelegate()444 JSONNodeDumper &doGetNodeDelegate() { return NodeDumper; } 445 VisitFunctionTemplateDecl(const FunctionTemplateDecl * FTD)446 void VisitFunctionTemplateDecl(const FunctionTemplateDecl *FTD) { 447 writeTemplateDecl(FTD, true); 448 } VisitClassTemplateDecl(const ClassTemplateDecl * CTD)449 void VisitClassTemplateDecl(const ClassTemplateDecl *CTD) { 450 writeTemplateDecl(CTD, false); 451 } VisitVarTemplateDecl(const VarTemplateDecl * VTD)452 void VisitVarTemplateDecl(const VarTemplateDecl *VTD) { 453 writeTemplateDecl(VTD, false); 454 } 455 }; 456 457 } // namespace clang 458 459 #endif // LLVM_CLANG_AST_JSONNODEDUMPER_H 460