xref: /freebsd/contrib/llvm-project/clang/include/clang/AST/JSONNodeDumper.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
29 namespace clang {
30 
31 class APValue;
32 
33 class NodeStreamer {
34   bool FirstChild = true;
35   bool TopLevel = true;
36   llvm::SmallVector<std::function<void(bool IsLastChild)>, 32> Pending;
37 
38 protected:
39   llvm::json::OStream JOS;
40 
41 public:
42   /// Add a child of the current node.  Calls DoAddChild without arguments
AddChild(Fn DoAddChild)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.
AddChild(StringRef Label,Fn DoAddChild)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 
NodeStreamer(raw_ostream & OS)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.
116 class 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 
attributeOnlyIfTrue(StringRef Key,bool Value)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 
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   void Visit(TypeLoc TL);
201 
202   void Visit(const comments::Comment *C, const comments::FullComment *FC);
203   void Visit(const TemplateArgument &TA, SourceRange R = {},
204              const Decl *From = nullptr, StringRef Label = {});
205   void Visit(const CXXCtorInitializer *Init);
206   void Visit(const OpenACCClause *C);
207   void Visit(const OMPClause *C);
208   void Visit(const BlockDecl::Capture &C);
209   void Visit(const GenericSelectionExpr::ConstAssociation &A);
210   void Visit(const concepts::Requirement *R);
211   void Visit(const APValue &Value, QualType Ty);
212   void Visit(const ConceptReference *);
213 
214   void VisitAliasAttr(const AliasAttr *AA);
215   void VisitCleanupAttr(const CleanupAttr *CA);
216   void VisitDeprecatedAttr(const DeprecatedAttr *DA);
217   void VisitUnavailableAttr(const UnavailableAttr *UA);
218   void VisitSectionAttr(const SectionAttr *SA);
219   void VisitVisibilityAttr(const VisibilityAttr *VA);
220   void VisitTLSModelAttr(const TLSModelAttr *TA);
221 
222   void VisitTypedefType(const TypedefType *TT);
223   void VisitUsingType(const UsingType *TT);
224   void VisitFunctionType(const FunctionType *T);
225   void VisitFunctionProtoType(const FunctionProtoType *T);
226   void VisitRValueReferenceType(const ReferenceType *RT);
227   void VisitArrayType(const ArrayType *AT);
228   void VisitConstantArrayType(const ConstantArrayType *CAT);
229   void VisitDependentSizedExtVectorType(const DependentSizedExtVectorType *VT);
230   void VisitVectorType(const VectorType *VT);
231   void VisitUnresolvedUsingType(const UnresolvedUsingType *UUT);
232   void VisitUnaryTransformType(const UnaryTransformType *UTT);
233   void VisitTagType(const TagType *TT);
234   void VisitTemplateTypeParmType(const TemplateTypeParmType *TTPT);
235   void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *STTPT);
236   void
237   VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T);
238   void VisitAutoType(const AutoType *AT);
239   void VisitTemplateSpecializationType(const TemplateSpecializationType *TST);
240   void VisitInjectedClassNameType(const InjectedClassNameType *ICNT);
241   void VisitObjCInterfaceType(const ObjCInterfaceType *OIT);
242   void VisitPackExpansionType(const PackExpansionType *PET);
243   void VisitElaboratedType(const ElaboratedType *ET);
244   void VisitMacroQualifiedType(const MacroQualifiedType *MQT);
245   void VisitMemberPointerType(const MemberPointerType *MPT);
246 
247   void VisitNamedDecl(const NamedDecl *ND);
248   void VisitTypedefDecl(const TypedefDecl *TD);
249   void VisitTypeAliasDecl(const TypeAliasDecl *TAD);
250   void VisitNamespaceDecl(const NamespaceDecl *ND);
251   void VisitUsingDirectiveDecl(const UsingDirectiveDecl *UDD);
252   void VisitNamespaceAliasDecl(const NamespaceAliasDecl *NAD);
253   void VisitUsingDecl(const UsingDecl *UD);
254   void VisitUsingEnumDecl(const UsingEnumDecl *UED);
255   void VisitUsingShadowDecl(const UsingShadowDecl *USD);
256   void VisitVarDecl(const VarDecl *VD);
257   void VisitFieldDecl(const FieldDecl *FD);
258   void VisitFunctionDecl(const FunctionDecl *FD);
259   void VisitEnumDecl(const EnumDecl *ED);
260   void VisitEnumConstantDecl(const EnumConstantDecl *ECD);
261   void VisitRecordDecl(const RecordDecl *RD);
262   void VisitCXXRecordDecl(const CXXRecordDecl *RD);
263   void VisitHLSLBufferDecl(const HLSLBufferDecl *D);
264   void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D);
265   void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D);
266   void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D);
267   void VisitLinkageSpecDecl(const LinkageSpecDecl *LSD);
268   void VisitAccessSpecDecl(const AccessSpecDecl *ASD);
269   void VisitFriendDecl(const FriendDecl *FD);
270 
271   void VisitObjCIvarDecl(const ObjCIvarDecl *D);
272   void VisitObjCMethodDecl(const ObjCMethodDecl *D);
273   void VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D);
274   void VisitObjCCategoryDecl(const ObjCCategoryDecl *D);
275   void VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D);
276   void VisitObjCProtocolDecl(const ObjCProtocolDecl *D);
277   void VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D);
278   void VisitObjCImplementationDecl(const ObjCImplementationDecl *D);
279   void VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D);
280   void VisitObjCPropertyDecl(const ObjCPropertyDecl *D);
281   void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D);
282   void VisitBlockDecl(const BlockDecl *D);
283 
284   void VisitDeclRefExpr(const DeclRefExpr *DRE);
285   void VisitSYCLUniqueStableNameExpr(const SYCLUniqueStableNameExpr *E);
286   void VisitPredefinedExpr(const PredefinedExpr *PE);
287   void VisitUnaryOperator(const UnaryOperator *UO);
288   void VisitBinaryOperator(const BinaryOperator *BO);
289   void VisitCompoundAssignOperator(const CompoundAssignOperator *CAO);
290   void VisitMemberExpr(const MemberExpr *ME);
291   void VisitAtomicExpr(const AtomicExpr *AE);
292   void VisitCXXNewExpr(const CXXNewExpr *NE);
293   void VisitCXXDeleteExpr(const CXXDeleteExpr *DE);
294   void VisitCXXThisExpr(const CXXThisExpr *TE);
295   void VisitCastExpr(const CastExpr *CE);
296   void VisitImplicitCastExpr(const ImplicitCastExpr *ICE);
297   void VisitCallExpr(const CallExpr *CE);
298   void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *TTE);
299   void VisitSizeOfPackExpr(const SizeOfPackExpr *SOPE);
300   void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *ULE);
301   void VisitAddrLabelExpr(const AddrLabelExpr *ALE);
302   void VisitCXXTypeidExpr(const CXXTypeidExpr *CTE);
303   void VisitConstantExpr(const ConstantExpr *CE);
304   void VisitInitListExpr(const InitListExpr *ILE);
305   void VisitGenericSelectionExpr(const GenericSelectionExpr *GSE);
306   void VisitCXXUnresolvedConstructExpr(const CXXUnresolvedConstructExpr *UCE);
307   void VisitCXXConstructExpr(const CXXConstructExpr *CE);
308   void VisitExprWithCleanups(const ExprWithCleanups *EWC);
309   void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE);
310   void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *MTE);
311   void VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *ME);
312   void VisitRequiresExpr(const RequiresExpr *RE);
313   void VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *Node);
314   void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *Node);
315 
316   void VisitObjCEncodeExpr(const ObjCEncodeExpr *OEE);
317   void VisitObjCMessageExpr(const ObjCMessageExpr *OME);
318   void VisitObjCBoxedExpr(const ObjCBoxedExpr *OBE);
319   void VisitObjCSelectorExpr(const ObjCSelectorExpr *OSE);
320   void VisitObjCProtocolExpr(const ObjCProtocolExpr *OPE);
321   void VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *OPRE);
322   void VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *OSRE);
323   void VisitObjCIvarRefExpr(const ObjCIvarRefExpr *OIRE);
324   void VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *OBLE);
325 
326   void VisitIntegerLiteral(const IntegerLiteral *IL);
327   void VisitCharacterLiteral(const CharacterLiteral *CL);
328   void VisitFixedPointLiteral(const FixedPointLiteral *FPL);
329   void VisitFloatingLiteral(const FloatingLiteral *FL);
330   void VisitStringLiteral(const StringLiteral *SL);
331   void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *BLE);
332 
333   void VisitIfStmt(const IfStmt *IS);
334   void VisitSwitchStmt(const SwitchStmt *SS);
335   void VisitCaseStmt(const CaseStmt *CS);
336   void VisitLabelStmt(const LabelStmt *LS);
337   void VisitGotoStmt(const GotoStmt *GS);
338   void VisitWhileStmt(const WhileStmt *WS);
339   void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *OACS);
340   void VisitCompoundStmt(const CompoundStmt *IS);
341 
342   void VisitNullTemplateArgument(const TemplateArgument &TA);
343   void VisitTypeTemplateArgument(const TemplateArgument &TA);
344   void VisitDeclarationTemplateArgument(const TemplateArgument &TA);
345   void VisitNullPtrTemplateArgument(const TemplateArgument &TA);
346   void VisitIntegralTemplateArgument(const TemplateArgument &TA);
347   void VisitTemplateTemplateArgument(const TemplateArgument &TA);
348   void VisitTemplateExpansionTemplateArgument(const TemplateArgument &TA);
349   void VisitExpressionTemplateArgument(const TemplateArgument &TA);
350   void VisitPackTemplateArgument(const TemplateArgument &TA);
351 
352   void visitTextComment(const comments::TextComment *C,
353                         const comments::FullComment *);
354   void visitInlineCommandComment(const comments::InlineCommandComment *C,
355                                  const comments::FullComment *);
356   void visitHTMLStartTagComment(const comments::HTMLStartTagComment *C,
357                                 const comments::FullComment *);
358   void visitHTMLEndTagComment(const comments::HTMLEndTagComment *C,
359                               const comments::FullComment *);
360   void visitBlockCommandComment(const comments::BlockCommandComment *C,
361                                 const comments::FullComment *);
362   void visitParamCommandComment(const comments::ParamCommandComment *C,
363                                 const comments::FullComment *FC);
364   void visitTParamCommandComment(const comments::TParamCommandComment *C,
365                                  const comments::FullComment *FC);
366   void visitVerbatimBlockComment(const comments::VerbatimBlockComment *C,
367                                  const comments::FullComment *);
368   void
369   visitVerbatimBlockLineComment(const comments::VerbatimBlockLineComment *C,
370                                 const comments::FullComment *);
371   void visitVerbatimLineComment(const comments::VerbatimLineComment *C,
372                                 const comments::FullComment *);
373 };
374 
375 class JSONDumper : public ASTNodeTraverser<JSONDumper, JSONNodeDumper> {
376   JSONNodeDumper NodeDumper;
377 
378   template <typename SpecializationDecl>
writeTemplateDeclSpecialization(const SpecializationDecl * SD,bool DumpExplicitInst,bool DumpRefOnly)379   void writeTemplateDeclSpecialization(const SpecializationDecl *SD,
380                                        bool DumpExplicitInst,
381                                        bool DumpRefOnly) {
382     bool DumpedAny = false;
383     for (const auto *RedeclWithBadType : SD->redecls()) {
384       // FIXME: The redecls() range sometimes has elements of a less-specific
385       // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives
386       // us TagDecls, and should give CXXRecordDecls).
387       const auto *Redecl = dyn_cast<SpecializationDecl>(RedeclWithBadType);
388       if (!Redecl) {
389         // Found the injected-class-name for a class template. This will be
390         // dumped as part of its surrounding class so we don't need to dump it
391         // here.
392         assert(isa<CXXRecordDecl>(RedeclWithBadType) &&
393                "expected an injected-class-name");
394         continue;
395       }
396 
397       switch (Redecl->getTemplateSpecializationKind()) {
398       case TSK_ExplicitInstantiationDeclaration:
399       case TSK_ExplicitInstantiationDefinition:
400         if (!DumpExplicitInst)
401           break;
402         [[fallthrough]];
403       case TSK_Undeclared:
404       case TSK_ImplicitInstantiation:
405         if (DumpRefOnly)
406           NodeDumper.AddChild([=] { NodeDumper.writeBareDeclRef(Redecl); });
407         else
408           Visit(Redecl);
409         DumpedAny = true;
410         break;
411       case TSK_ExplicitSpecialization:
412         break;
413       }
414     }
415 
416     // Ensure we dump at least one decl for each specialization.
417     if (!DumpedAny)
418       NodeDumper.AddChild([=] { NodeDumper.writeBareDeclRef(SD); });
419   }
420 
421   template <typename TemplateDecl>
writeTemplateDecl(const TemplateDecl * TD,bool DumpExplicitInst)422   void writeTemplateDecl(const TemplateDecl *TD, bool DumpExplicitInst) {
423     // FIXME: it would be nice to dump template parameters and specializations
424     // to their own named arrays rather than shoving them into the "inner"
425     // array. However, template declarations are currently being handled at the
426     // wrong "level" of the traversal hierarchy and so it is difficult to
427     // achieve without losing information elsewhere.
428 
429     dumpTemplateParameters(TD->getTemplateParameters());
430 
431     Visit(TD->getTemplatedDecl());
432 
433     for (const auto *Child : TD->specializations())
434       writeTemplateDeclSpecialization(Child, DumpExplicitInst,
435                                       !TD->isCanonicalDecl());
436   }
437 
438 public:
JSONDumper(raw_ostream & OS,const SourceManager & SrcMgr,ASTContext & Ctx,const PrintingPolicy & PrintPolicy,const comments::CommandTraits * Traits)439   JSONDumper(raw_ostream &OS, const SourceManager &SrcMgr, ASTContext &Ctx,
440              const PrintingPolicy &PrintPolicy,
441              const comments::CommandTraits *Traits)
442       : NodeDumper(OS, SrcMgr, Ctx, PrintPolicy, Traits) {}
443 
doGetNodeDelegate()444   JSONNodeDumper &doGetNodeDelegate() { return NodeDumper; }
445 
VisitFunctionTemplateDecl(const FunctionTemplateDecl * FTD)446   void VisitFunctionTemplateDecl(const FunctionTemplateDecl *FTD) {
447     writeTemplateDecl(FTD, true);
448   }
VisitClassTemplateDecl(const ClassTemplateDecl * CTD)449   void VisitClassTemplateDecl(const ClassTemplateDecl *CTD) {
450     writeTemplateDecl(CTD, false);
451   }
VisitVarTemplateDecl(const VarTemplateDecl * VTD)452   void VisitVarTemplateDecl(const VarTemplateDecl *VTD) {
453     writeTemplateDecl(VTD, false);
454   }
455 };
456 
457 } // namespace clang
458 
459 #endif // LLVM_CLANG_AST_JSONNODEDUMPER_H
460