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 
28 namespace clang {
29 
30 class NodeStreamer {
31   bool FirstChild = true;
32   bool TopLevel = true;
33   llvm::SmallVector<std::function<void(bool IsLastChild)>, 32> Pending;
34 
35 protected:
36   llvm::json::OStream JOS;
37 
38 public:
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.
113 class 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 
183 public:
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 
346 class 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 
409 public:
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