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