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