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