1351280Sdim//===--- JSONNodeDumper.h - Printing of AST nodes to JSON -----------------===//
2351280Sdim//
3351280Sdim//                     The LLVM Compiler Infrastructure
4351280Sdim//
5351280Sdim// This file is distributed under the University of Illinois Open Source
6351280Sdim// License. See LICENSE.TXT for details.
7351280Sdim//
8351280Sdim//===----------------------------------------------------------------------===//
9351280Sdim//
10351280Sdim// This file implements AST dumping of components of individual AST nodes to
11351280Sdim// a JSON.
12351280Sdim//
13351280Sdim//===----------------------------------------------------------------------===//
14351280Sdim
15351280Sdim#ifndef LLVM_CLANG_AST_JSONNODEDUMPER_H
16351280Sdim#define LLVM_CLANG_AST_JSONNODEDUMPER_H
17351280Sdim
18351280Sdim#include "clang/AST/ASTContext.h"
19360784Sdim#include "clang/AST/ASTDumperUtils.h"
20351280Sdim#include "clang/AST/ASTNodeTraverser.h"
21351280Sdim#include "clang/AST/AttrVisitor.h"
22351280Sdim#include "clang/AST/CommentCommandTraits.h"
23351280Sdim#include "clang/AST/CommentVisitor.h"
24351280Sdim#include "clang/AST/ExprCXX.h"
25360784Sdim#include "clang/AST/Mangle.h"
26351280Sdim#include "llvm/Support/JSON.h"
27351280Sdim
28351280Sdimnamespace clang {
29351280Sdim
30351280Sdimclass NodeStreamer {
31351280Sdim  bool FirstChild = true;
32351280Sdim  bool TopLevel = true;
33351280Sdim  llvm::SmallVector<std::function<void(bool IsLastChild)>, 32> Pending;
34351280Sdim
35351280Sdimprotected:
36351280Sdim  llvm::json::OStream JOS;
37351280Sdim
38351280Sdimpublic:
39351280Sdim  /// Add a child of the current node.  Calls DoAddChild without arguments
40351280Sdim  template <typename Fn> void AddChild(Fn DoAddChild) {
41351280Sdim    return AddChild("", DoAddChild);
42351280Sdim  }
43351280Sdim
44351280Sdim  /// Add a child of the current node with an optional label.
45351280Sdim  /// Calls DoAddChild without arguments.
46351280Sdim  template <typename Fn> void AddChild(StringRef Label, Fn DoAddChild) {
47351280Sdim    // If we're at the top level, there's nothing interesting to do; just
48351280Sdim    // run the dumper.
49351280Sdim    if (TopLevel) {
50351280Sdim      TopLevel = false;
51351280Sdim      JOS.objectBegin();
52351280Sdim
53351280Sdim      DoAddChild();
54351280Sdim
55351280Sdim      while (!Pending.empty()) {
56351280Sdim        Pending.back()(true);
57351280Sdim        Pending.pop_back();
58351280Sdim      }
59351280Sdim
60351280Sdim      JOS.objectEnd();
61351280Sdim      TopLevel = true;
62351280Sdim      return;
63351280Sdim    }
64351280Sdim
65351280Sdim    // We need to capture an owning-string in the lambda because the lambda
66351280Sdim    // is invoked in a deferred manner.
67351280Sdim    std::string LabelStr = !Label.empty() ? Label : "inner";
68351280Sdim    bool WasFirstChild = FirstChild;
69351280Sdim    auto DumpWithIndent = [=](bool IsLastChild) {
70351280Sdim      if (WasFirstChild) {
71351280Sdim        JOS.attributeBegin(LabelStr);
72351280Sdim        JOS.arrayBegin();
73351280Sdim      }
74351280Sdim
75351280Sdim      FirstChild = true;
76351280Sdim      unsigned Depth = Pending.size();
77351280Sdim      JOS.objectBegin();
78351280Sdim
79351280Sdim      DoAddChild();
80351280Sdim
81351280Sdim      // If any children are left, they're the last at their nesting level.
82351280Sdim      // Dump those ones out now.
83351280Sdim      while (Depth < Pending.size()) {
84351280Sdim        Pending.back()(true);
85351280Sdim        this->Pending.pop_back();
86351280Sdim      }
87351280Sdim
88351280Sdim      JOS.objectEnd();
89351280Sdim
90351280Sdim      if (IsLastChild) {
91351280Sdim        JOS.arrayEnd();
92351280Sdim        JOS.attributeEnd();
93351280Sdim      }
94351280Sdim    };
95351280Sdim
96351280Sdim    if (FirstChild) {
97351280Sdim      Pending.push_back(std::move(DumpWithIndent));
98351280Sdim    } else {
99351280Sdim      Pending.back()(false);
100351280Sdim      Pending.back() = std::move(DumpWithIndent);
101351280Sdim    }
102351280Sdim    FirstChild = false;
103351280Sdim  }
104351280Sdim
105351280Sdim  NodeStreamer(raw_ostream &OS) : JOS(OS, 2) {}
106351280Sdim};
107351280Sdim
108351280Sdim// Dumps AST nodes in JSON format. There is no implied stability for the
109351280Sdim// content or format of the dump between major releases of Clang, other than it
110351280Sdim// being valid JSON output. Further, there is no requirement that the
111351280Sdim// information dumped is a complete representation of the AST, only that the
112351280Sdim// information presented is correct.
113351280Sdimclass JSONNodeDumper
114351280Sdim    : public ConstAttrVisitor<JSONNodeDumper>,
115351280Sdim      public comments::ConstCommentVisitor<JSONNodeDumper, void,
116351280Sdim                                           const comments::FullComment *>,
117351280Sdim      public ConstTemplateArgumentVisitor<JSONNodeDumper>,
118351280Sdim      public ConstStmtVisitor<JSONNodeDumper>,
119351280Sdim      public TypeVisitor<JSONNodeDumper>,
120351280Sdim      public ConstDeclVisitor<JSONNodeDumper>,
121351280Sdim      public NodeStreamer {
122351280Sdim  friend class JSONDumper;
123351280Sdim
124351280Sdim  const SourceManager &SM;
125351280Sdim  ASTContext& Ctx;
126360784Sdim  ASTNameGenerator ASTNameGen;
127351280Sdim  PrintingPolicy PrintPolicy;
128351280Sdim  const comments::CommandTraits *Traits;
129360784Sdim  StringRef LastLocFilename, LastLocPresumedFilename;
130351280Sdim  unsigned LastLocLine, LastLocPresumedLine;
131351280Sdim
132351280Sdim  using InnerAttrVisitor = ConstAttrVisitor<JSONNodeDumper>;
133351280Sdim  using InnerCommentVisitor =
134351280Sdim      comments::ConstCommentVisitor<JSONNodeDumper, void,
135351280Sdim                                    const comments::FullComment *>;
136351280Sdim  using InnerTemplateArgVisitor = ConstTemplateArgumentVisitor<JSONNodeDumper>;
137351280Sdim  using InnerStmtVisitor = ConstStmtVisitor<JSONNodeDumper>;
138351280Sdim  using InnerTypeVisitor = TypeVisitor<JSONNodeDumper>;
139351280Sdim  using InnerDeclVisitor = ConstDeclVisitor<JSONNodeDumper>;
140351280Sdim
141351280Sdim  void attributeOnlyIfTrue(StringRef Key, bool Value) {
142351280Sdim    if (Value)
143351280Sdim      JOS.attribute(Key, Value);
144351280Sdim  }
145351280Sdim
146360784Sdim  void writeIncludeStack(PresumedLoc Loc, bool JustFirst = false);
147360784Sdim
148351280Sdim  // Writes the attributes of a SourceLocation object without.
149351280Sdim  void writeBareSourceLocation(SourceLocation Loc, bool IsSpelling);
150351280Sdim
151351280Sdim  // Writes the attributes of a SourceLocation to JSON based on its presumed
152351280Sdim  // spelling location. If the given location represents a macro invocation,
153351280Sdim  // this outputs two sub-objects: one for the spelling and one for the
154351280Sdim  // expansion location.
155351280Sdim  void writeSourceLocation(SourceLocation Loc);
156351280Sdim  void writeSourceRange(SourceRange R);
157351280Sdim  std::string createPointerRepresentation(const void *Ptr);
158351280Sdim  llvm::json::Object createQualType(QualType QT, bool Desugar = true);
159351280Sdim  llvm::json::Object createBareDeclRef(const Decl *D);
160351280Sdim  void writeBareDeclRef(const Decl *D);
161351280Sdim  llvm::json::Object createCXXRecordDefinitionData(const CXXRecordDecl *RD);
162351280Sdim  llvm::json::Object createCXXBaseSpecifier(const CXXBaseSpecifier &BS);
163351280Sdim  std::string createAccessSpecifier(AccessSpecifier AS);
164351280Sdim  llvm::json::Array createCastPath(const CastExpr *C);
165351280Sdim
166351280Sdim  void writePreviousDeclImpl(...) {}
167351280Sdim
168351280Sdim  template <typename T> void writePreviousDeclImpl(const Mergeable<T> *D) {
169351280Sdim    const T *First = D->getFirstDecl();
170351280Sdim    if (First != D)
171351280Sdim      JOS.attribute("firstRedecl", createPointerRepresentation(First));
172351280Sdim  }
173351280Sdim
174351280Sdim  template <typename T> void writePreviousDeclImpl(const Redeclarable<T> *D) {
175351280Sdim    const T *Prev = D->getPreviousDecl();
176351280Sdim    if (Prev)
177351280Sdim      JOS.attribute("previousDecl", createPointerRepresentation(Prev));
178351280Sdim  }
179351280Sdim  void addPreviousDeclaration(const Decl *D);
180351280Sdim
181351280Sdim  StringRef getCommentCommandName(unsigned CommandID) const;
182351280Sdim
183351280Sdimpublic:
184351280Sdim  JSONNodeDumper(raw_ostream &OS, const SourceManager &SrcMgr, ASTContext &Ctx,
185351280Sdim                 const PrintingPolicy &PrintPolicy,
186351280Sdim                 const comments::CommandTraits *Traits)
187360784Sdim      : NodeStreamer(OS), SM(SrcMgr), Ctx(Ctx), ASTNameGen(Ctx),
188360784Sdim        PrintPolicy(PrintPolicy), Traits(Traits), LastLocLine(0),
189360784Sdim        LastLocPresumedLine(0) {}
190351280Sdim
191351280Sdim  void Visit(const Attr *A);
192351280Sdim  void Visit(const Stmt *Node);
193351280Sdim  void Visit(const Type *T);
194351280Sdim  void Visit(QualType T);
195351280Sdim  void Visit(const Decl *D);
196351280Sdim
197351280Sdim  void Visit(const comments::Comment *C, const comments::FullComment *FC);
198351280Sdim  void Visit(const TemplateArgument &TA, SourceRange R = {},
199351280Sdim             const Decl *From = nullptr, StringRef Label = {});
200351280Sdim  void Visit(const CXXCtorInitializer *Init);
201351280Sdim  void Visit(const OMPClause *C);
202351280Sdim  void Visit(const BlockDecl::Capture &C);
203351280Sdim  void Visit(const GenericSelectionExpr::ConstAssociation &A);
204351280Sdim
205351280Sdim  void VisitTypedefType(const TypedefType *TT);
206351280Sdim  void VisitFunctionType(const FunctionType *T);
207351280Sdim  void VisitFunctionProtoType(const FunctionProtoType *T);
208351280Sdim  void VisitRValueReferenceType(const ReferenceType *RT);
209351280Sdim  void VisitArrayType(const ArrayType *AT);
210351280Sdim  void VisitConstantArrayType(const ConstantArrayType *CAT);
211351280Sdim  void VisitDependentSizedExtVectorType(const DependentSizedExtVectorType *VT);
212351280Sdim  void VisitVectorType(const VectorType *VT);
213351280Sdim  void VisitUnresolvedUsingType(const UnresolvedUsingType *UUT);
214351280Sdim  void VisitUnaryTransformType(const UnaryTransformType *UTT);
215351280Sdim  void VisitTagType(const TagType *TT);
216351280Sdim  void VisitTemplateTypeParmType(const TemplateTypeParmType *TTPT);
217351280Sdim  void VisitAutoType(const AutoType *AT);
218351280Sdim  void VisitTemplateSpecializationType(const TemplateSpecializationType *TST);
219351280Sdim  void VisitInjectedClassNameType(const InjectedClassNameType *ICNT);
220351280Sdim  void VisitObjCInterfaceType(const ObjCInterfaceType *OIT);
221351280Sdim  void VisitPackExpansionType(const PackExpansionType *PET);
222351280Sdim  void VisitElaboratedType(const ElaboratedType *ET);
223351280Sdim  void VisitMacroQualifiedType(const MacroQualifiedType *MQT);
224351280Sdim  void VisitMemberPointerType(const MemberPointerType *MPT);
225351280Sdim
226351280Sdim  void VisitNamedDecl(const NamedDecl *ND);
227351280Sdim  void VisitTypedefDecl(const TypedefDecl *TD);
228351280Sdim  void VisitTypeAliasDecl(const TypeAliasDecl *TAD);
229351280Sdim  void VisitNamespaceDecl(const NamespaceDecl *ND);
230351280Sdim  void VisitUsingDirectiveDecl(const UsingDirectiveDecl *UDD);
231351280Sdim  void VisitNamespaceAliasDecl(const NamespaceAliasDecl *NAD);
232351280Sdim  void VisitUsingDecl(const UsingDecl *UD);
233351280Sdim  void VisitUsingShadowDecl(const UsingShadowDecl *USD);
234351280Sdim  void VisitVarDecl(const VarDecl *VD);
235351280Sdim  void VisitFieldDecl(const FieldDecl *FD);
236351280Sdim  void VisitFunctionDecl(const FunctionDecl *FD);
237351280Sdim  void VisitEnumDecl(const EnumDecl *ED);
238351280Sdim  void VisitEnumConstantDecl(const EnumConstantDecl *ECD);
239351280Sdim  void VisitRecordDecl(const RecordDecl *RD);
240351280Sdim  void VisitCXXRecordDecl(const CXXRecordDecl *RD);
241351280Sdim  void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D);
242351280Sdim  void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D);
243351280Sdim  void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D);
244351280Sdim  void VisitLinkageSpecDecl(const LinkageSpecDecl *LSD);
245351280Sdim  void VisitAccessSpecDecl(const AccessSpecDecl *ASD);
246351280Sdim  void VisitFriendDecl(const FriendDecl *FD);
247351280Sdim
248351280Sdim  void VisitObjCIvarDecl(const ObjCIvarDecl *D);
249351280Sdim  void VisitObjCMethodDecl(const ObjCMethodDecl *D);
250351280Sdim  void VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D);
251351280Sdim  void VisitObjCCategoryDecl(const ObjCCategoryDecl *D);
252351280Sdim  void VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D);
253351280Sdim  void VisitObjCProtocolDecl(const ObjCProtocolDecl *D);
254351280Sdim  void VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D);
255351280Sdim  void VisitObjCImplementationDecl(const ObjCImplementationDecl *D);
256351280Sdim  void VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D);
257351280Sdim  void VisitObjCPropertyDecl(const ObjCPropertyDecl *D);
258351280Sdim  void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D);
259351280Sdim  void VisitBlockDecl(const BlockDecl *D);
260351280Sdim
261351280Sdim  void VisitDeclRefExpr(const DeclRefExpr *DRE);
262351280Sdim  void VisitPredefinedExpr(const PredefinedExpr *PE);
263351280Sdim  void VisitUnaryOperator(const UnaryOperator *UO);
264351280Sdim  void VisitBinaryOperator(const BinaryOperator *BO);
265351280Sdim  void VisitCompoundAssignOperator(const CompoundAssignOperator *CAO);
266351280Sdim  void VisitMemberExpr(const MemberExpr *ME);
267351280Sdim  void VisitCXXNewExpr(const CXXNewExpr *NE);
268351280Sdim  void VisitCXXDeleteExpr(const CXXDeleteExpr *DE);
269351280Sdim  void VisitCXXThisExpr(const CXXThisExpr *TE);
270351280Sdim  void VisitCastExpr(const CastExpr *CE);
271351280Sdim  void VisitImplicitCastExpr(const ImplicitCastExpr *ICE);
272351280Sdim  void VisitCallExpr(const CallExpr *CE);
273351280Sdim  void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *TTE);
274351280Sdim  void VisitSizeOfPackExpr(const SizeOfPackExpr *SOPE);
275351280Sdim  void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *ULE);
276351280Sdim  void VisitAddrLabelExpr(const AddrLabelExpr *ALE);
277351280Sdim  void VisitCXXTypeidExpr(const CXXTypeidExpr *CTE);
278351280Sdim  void VisitConstantExpr(const ConstantExpr *CE);
279351280Sdim  void VisitInitListExpr(const InitListExpr *ILE);
280351280Sdim  void VisitGenericSelectionExpr(const GenericSelectionExpr *GSE);
281351280Sdim  void VisitCXXUnresolvedConstructExpr(const CXXUnresolvedConstructExpr *UCE);
282351280Sdim  void VisitCXXConstructExpr(const CXXConstructExpr *CE);
283351280Sdim  void VisitExprWithCleanups(const ExprWithCleanups *EWC);
284351280Sdim  void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE);
285351280Sdim  void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *MTE);
286351280Sdim  void VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *ME);
287351280Sdim
288351280Sdim  void VisitObjCEncodeExpr(const ObjCEncodeExpr *OEE);
289351280Sdim  void VisitObjCMessageExpr(const ObjCMessageExpr *OME);
290351280Sdim  void VisitObjCBoxedExpr(const ObjCBoxedExpr *OBE);
291351280Sdim  void VisitObjCSelectorExpr(const ObjCSelectorExpr *OSE);
292351280Sdim  void VisitObjCProtocolExpr(const ObjCProtocolExpr *OPE);
293351280Sdim  void VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *OPRE);
294351280Sdim  void VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *OSRE);
295351280Sdim  void VisitObjCIvarRefExpr(const ObjCIvarRefExpr *OIRE);
296351280Sdim  void VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *OBLE);
297351280Sdim
298351280Sdim  void VisitIntegerLiteral(const IntegerLiteral *IL);
299351280Sdim  void VisitCharacterLiteral(const CharacterLiteral *CL);
300351280Sdim  void VisitFixedPointLiteral(const FixedPointLiteral *FPL);
301351280Sdim  void VisitFloatingLiteral(const FloatingLiteral *FL);
302351280Sdim  void VisitStringLiteral(const StringLiteral *SL);
303351280Sdim  void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *BLE);
304351280Sdim
305351280Sdim  void VisitIfStmt(const IfStmt *IS);
306351280Sdim  void VisitSwitchStmt(const SwitchStmt *SS);
307351280Sdim  void VisitCaseStmt(const CaseStmt *CS);
308351280Sdim  void VisitLabelStmt(const LabelStmt *LS);
309351280Sdim  void VisitGotoStmt(const GotoStmt *GS);
310351280Sdim  void VisitWhileStmt(const WhileStmt *WS);
311351280Sdim  void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *OACS);
312351280Sdim
313351280Sdim  void VisitNullTemplateArgument(const TemplateArgument &TA);
314351280Sdim  void VisitTypeTemplateArgument(const TemplateArgument &TA);
315351280Sdim  void VisitDeclarationTemplateArgument(const TemplateArgument &TA);
316351280Sdim  void VisitNullPtrTemplateArgument(const TemplateArgument &TA);
317351280Sdim  void VisitIntegralTemplateArgument(const TemplateArgument &TA);
318351280Sdim  void VisitTemplateTemplateArgument(const TemplateArgument &TA);
319351280Sdim  void VisitTemplateExpansionTemplateArgument(const TemplateArgument &TA);
320351280Sdim  void VisitExpressionTemplateArgument(const TemplateArgument &TA);
321351280Sdim  void VisitPackTemplateArgument(const TemplateArgument &TA);
322351280Sdim
323351280Sdim  void visitTextComment(const comments::TextComment *C,
324351280Sdim                        const comments::FullComment *);
325351280Sdim  void visitInlineCommandComment(const comments::InlineCommandComment *C,
326351280Sdim                                 const comments::FullComment *);
327351280Sdim  void visitHTMLStartTagComment(const comments::HTMLStartTagComment *C,
328351280Sdim                                const comments::FullComment *);
329351280Sdim  void visitHTMLEndTagComment(const comments::HTMLEndTagComment *C,
330351280Sdim                              const comments::FullComment *);
331351280Sdim  void visitBlockCommandComment(const comments::BlockCommandComment *C,
332351280Sdim                                const comments::FullComment *);
333351280Sdim  void visitParamCommandComment(const comments::ParamCommandComment *C,
334351280Sdim                                const comments::FullComment *FC);
335351280Sdim  void visitTParamCommandComment(const comments::TParamCommandComment *C,
336351280Sdim                                 const comments::FullComment *FC);
337351280Sdim  void visitVerbatimBlockComment(const comments::VerbatimBlockComment *C,
338351280Sdim                                 const comments::FullComment *);
339351280Sdim  void
340351280Sdim  visitVerbatimBlockLineComment(const comments::VerbatimBlockLineComment *C,
341351280Sdim                                const comments::FullComment *);
342351280Sdim  void visitVerbatimLineComment(const comments::VerbatimLineComment *C,
343351280Sdim                                const comments::FullComment *);
344351280Sdim};
345351280Sdim
346351280Sdimclass JSONDumper : public ASTNodeTraverser<JSONDumper, JSONNodeDumper> {
347351280Sdim  JSONNodeDumper NodeDumper;
348351280Sdim
349351280Sdim  template <typename SpecializationDecl>
350351280Sdim  void writeTemplateDeclSpecialization(const SpecializationDecl *SD,
351351280Sdim                                       bool DumpExplicitInst,
352351280Sdim                                       bool DumpRefOnly) {
353351280Sdim    bool DumpedAny = false;
354351280Sdim    for (const auto *RedeclWithBadType : SD->redecls()) {
355351280Sdim      // FIXME: The redecls() range sometimes has elements of a less-specific
356351280Sdim      // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives
357351280Sdim      // us TagDecls, and should give CXXRecordDecls).
358351280Sdim      const auto *Redecl = dyn_cast<SpecializationDecl>(RedeclWithBadType);
359351280Sdim      if (!Redecl) {
360351280Sdim        // Found the injected-class-name for a class template. This will be
361351280Sdim        // dumped as part of its surrounding class so we don't need to dump it
362351280Sdim        // here.
363351280Sdim        assert(isa<CXXRecordDecl>(RedeclWithBadType) &&
364351280Sdim               "expected an injected-class-name");
365351280Sdim        continue;
366351280Sdim      }
367351280Sdim
368351280Sdim      switch (Redecl->getTemplateSpecializationKind()) {
369351280Sdim      case TSK_ExplicitInstantiationDeclaration:
370351280Sdim      case TSK_ExplicitInstantiationDefinition:
371351280Sdim        if (!DumpExplicitInst)
372351280Sdim          break;
373351280Sdim        LLVM_FALLTHROUGH;
374351280Sdim      case TSK_Undeclared:
375351280Sdim      case TSK_ImplicitInstantiation:
376351280Sdim        if (DumpRefOnly)
377351280Sdim          NodeDumper.AddChild([=] { NodeDumper.writeBareDeclRef(Redecl); });
378351280Sdim        else
379351280Sdim          Visit(Redecl);
380351280Sdim        DumpedAny = true;
381351280Sdim        break;
382351280Sdim      case TSK_ExplicitSpecialization:
383351280Sdim        break;
384351280Sdim      }
385351280Sdim    }
386351280Sdim
387351280Sdim    // Ensure we dump at least one decl for each specialization.
388351280Sdim    if (!DumpedAny)
389351280Sdim      NodeDumper.AddChild([=] { NodeDumper.writeBareDeclRef(SD); });
390351280Sdim  }
391351280Sdim
392351280Sdim  template <typename TemplateDecl>
393351280Sdim  void writeTemplateDecl(const TemplateDecl *TD, bool DumpExplicitInst) {
394351280Sdim    // FIXME: it would be nice to dump template parameters and specializations
395351280Sdim    // to their own named arrays rather than shoving them into the "inner"
396351280Sdim    // array. However, template declarations are currently being handled at the
397351280Sdim    // wrong "level" of the traversal hierarchy and so it is difficult to
398351280Sdim    // achieve without losing information elsewhere.
399351280Sdim
400351280Sdim    dumpTemplateParameters(TD->getTemplateParameters());
401351280Sdim
402351280Sdim    Visit(TD->getTemplatedDecl());
403351280Sdim
404351280Sdim    for (const auto *Child : TD->specializations())
405351280Sdim      writeTemplateDeclSpecialization(Child, DumpExplicitInst,
406351280Sdim                                      !TD->isCanonicalDecl());
407351280Sdim  }
408351280Sdim
409351280Sdimpublic:
410351280Sdim  JSONDumper(raw_ostream &OS, const SourceManager &SrcMgr, ASTContext &Ctx,
411351280Sdim             const PrintingPolicy &PrintPolicy,
412351280Sdim             const comments::CommandTraits *Traits)
413351280Sdim      : NodeDumper(OS, SrcMgr, Ctx, PrintPolicy, Traits) {}
414351280Sdim
415351280Sdim  JSONNodeDumper &doGetNodeDelegate() { return NodeDumper; }
416351280Sdim
417351280Sdim  void VisitFunctionTemplateDecl(const FunctionTemplateDecl *FTD) {
418351280Sdim    writeTemplateDecl(FTD, true);
419351280Sdim  }
420351280Sdim  void VisitClassTemplateDecl(const ClassTemplateDecl *CTD) {
421351280Sdim    writeTemplateDecl(CTD, false);
422351280Sdim  }
423351280Sdim  void VisitVarTemplateDecl(const VarTemplateDecl *VTD) {
424351280Sdim    writeTemplateDecl(VTD, false);
425351280Sdim  }
426351280Sdim};
427351280Sdim
428351280Sdim} // namespace clang
429351280Sdim
430351280Sdim#endif // LLVM_CLANG_AST_JSONNODEDUMPER_H
431