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