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