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