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