xref: /freebsd/contrib/llvm-project/clang/lib/AST/ASTDumper.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===--- ASTDumper.cpp - Dumping implementation for ASTs ------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // This file implements the AST dump methods, which dump out the
10*0b57cec5SDimitry Andric // AST in a form that exposes type details and other fields.
11*0b57cec5SDimitry Andric //
12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
13*0b57cec5SDimitry Andric 
14*0b57cec5SDimitry Andric #include "clang/AST/ASTDumper.h"
15*0b57cec5SDimitry Andric #include "clang/AST/ASTContext.h"
16*0b57cec5SDimitry Andric #include "clang/AST/DeclLookups.h"
17*0b57cec5SDimitry Andric #include "clang/AST/JSONNodeDumper.h"
18*0b57cec5SDimitry Andric #include "clang/Basic/Builtins.h"
19*0b57cec5SDimitry Andric #include "clang/Basic/Module.h"
20*0b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h"
21*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
22*0b57cec5SDimitry Andric using namespace clang;
23*0b57cec5SDimitry Andric using namespace clang::comments;
24*0b57cec5SDimitry Andric 
25*0b57cec5SDimitry Andric void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) {
26*0b57cec5SDimitry Andric   NodeDumper.AddChild([=] {
27*0b57cec5SDimitry Andric     OS << "StoredDeclsMap ";
28*0b57cec5SDimitry Andric     NodeDumper.dumpBareDeclRef(cast<Decl>(DC));
29*0b57cec5SDimitry Andric 
30*0b57cec5SDimitry Andric     const DeclContext *Primary = DC->getPrimaryContext();
31*0b57cec5SDimitry Andric     if (Primary != DC) {
32*0b57cec5SDimitry Andric       OS << " primary";
33*0b57cec5SDimitry Andric       NodeDumper.dumpPointer(cast<Decl>(Primary));
34*0b57cec5SDimitry Andric     }
35*0b57cec5SDimitry Andric 
36*0b57cec5SDimitry Andric     bool HasUndeserializedLookups = Primary->hasExternalVisibleStorage();
37*0b57cec5SDimitry Andric 
38*0b57cec5SDimitry Andric     auto Range = getDeserialize()
39*0b57cec5SDimitry Andric                      ? Primary->lookups()
40*0b57cec5SDimitry Andric                      : Primary->noload_lookups(/*PreserveInternalState=*/true);
41*0b57cec5SDimitry Andric     for (auto I = Range.begin(), E = Range.end(); I != E; ++I) {
42*0b57cec5SDimitry Andric       DeclarationName Name = I.getLookupName();
43*0b57cec5SDimitry Andric       DeclContextLookupResult R = *I;
44*0b57cec5SDimitry Andric 
45*0b57cec5SDimitry Andric       NodeDumper.AddChild([=] {
46*0b57cec5SDimitry Andric         OS << "DeclarationName ";
47*0b57cec5SDimitry Andric         {
48*0b57cec5SDimitry Andric           ColorScope Color(OS, ShowColors, DeclNameColor);
49*0b57cec5SDimitry Andric           OS << '\'' << Name << '\'';
50*0b57cec5SDimitry Andric         }
51*0b57cec5SDimitry Andric 
52*0b57cec5SDimitry Andric         for (DeclContextLookupResult::iterator RI = R.begin(), RE = R.end();
53*0b57cec5SDimitry Andric              RI != RE; ++RI) {
54*0b57cec5SDimitry Andric           NodeDumper.AddChild([=] {
55*0b57cec5SDimitry Andric             NodeDumper.dumpBareDeclRef(*RI);
56*0b57cec5SDimitry Andric 
57*0b57cec5SDimitry Andric             if ((*RI)->isHidden())
58*0b57cec5SDimitry Andric               OS << " hidden";
59*0b57cec5SDimitry Andric 
60*0b57cec5SDimitry Andric             // If requested, dump the redecl chain for this lookup.
61*0b57cec5SDimitry Andric             if (DumpDecls) {
62*0b57cec5SDimitry Andric               // Dump earliest decl first.
63*0b57cec5SDimitry Andric               std::function<void(Decl *)> DumpWithPrev = [&](Decl *D) {
64*0b57cec5SDimitry Andric                 if (Decl *Prev = D->getPreviousDecl())
65*0b57cec5SDimitry Andric                   DumpWithPrev(Prev);
66*0b57cec5SDimitry Andric                 Visit(D);
67*0b57cec5SDimitry Andric               };
68*0b57cec5SDimitry Andric               DumpWithPrev(*RI);
69*0b57cec5SDimitry Andric             }
70*0b57cec5SDimitry Andric           });
71*0b57cec5SDimitry Andric         }
72*0b57cec5SDimitry Andric       });
73*0b57cec5SDimitry Andric     }
74*0b57cec5SDimitry Andric 
75*0b57cec5SDimitry Andric     if (HasUndeserializedLookups) {
76*0b57cec5SDimitry Andric       NodeDumper.AddChild([=] {
77*0b57cec5SDimitry Andric         ColorScope Color(OS, ShowColors, UndeserializedColor);
78*0b57cec5SDimitry Andric         OS << "<undeserialized lookups>";
79*0b57cec5SDimitry Andric       });
80*0b57cec5SDimitry Andric     }
81*0b57cec5SDimitry Andric   });
82*0b57cec5SDimitry Andric }
83*0b57cec5SDimitry Andric 
84*0b57cec5SDimitry Andric template <typename SpecializationDecl>
85*0b57cec5SDimitry Andric void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl *D,
86*0b57cec5SDimitry Andric                                                bool DumpExplicitInst,
87*0b57cec5SDimitry Andric                                                bool DumpRefOnly) {
88*0b57cec5SDimitry Andric   bool DumpedAny = false;
89*0b57cec5SDimitry Andric   for (const auto *RedeclWithBadType : D->redecls()) {
90*0b57cec5SDimitry Andric     // FIXME: The redecls() range sometimes has elements of a less-specific
91*0b57cec5SDimitry Andric     // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives
92*0b57cec5SDimitry Andric     // us TagDecls, and should give CXXRecordDecls).
93*0b57cec5SDimitry Andric     auto *Redecl = dyn_cast<SpecializationDecl>(RedeclWithBadType);
94*0b57cec5SDimitry Andric     if (!Redecl) {
95*0b57cec5SDimitry Andric       // Found the injected-class-name for a class template. This will be dumped
96*0b57cec5SDimitry Andric       // as part of its surrounding class so we don't need to dump it here.
97*0b57cec5SDimitry Andric       assert(isa<CXXRecordDecl>(RedeclWithBadType) &&
98*0b57cec5SDimitry Andric              "expected an injected-class-name");
99*0b57cec5SDimitry Andric       continue;
100*0b57cec5SDimitry Andric     }
101*0b57cec5SDimitry Andric 
102*0b57cec5SDimitry Andric     switch (Redecl->getTemplateSpecializationKind()) {
103*0b57cec5SDimitry Andric     case TSK_ExplicitInstantiationDeclaration:
104*0b57cec5SDimitry Andric     case TSK_ExplicitInstantiationDefinition:
105*0b57cec5SDimitry Andric       if (!DumpExplicitInst)
106*0b57cec5SDimitry Andric         break;
107*0b57cec5SDimitry Andric       LLVM_FALLTHROUGH;
108*0b57cec5SDimitry Andric     case TSK_Undeclared:
109*0b57cec5SDimitry Andric     case TSK_ImplicitInstantiation:
110*0b57cec5SDimitry Andric       if (DumpRefOnly)
111*0b57cec5SDimitry Andric         NodeDumper.dumpDeclRef(Redecl);
112*0b57cec5SDimitry Andric       else
113*0b57cec5SDimitry Andric         Visit(Redecl);
114*0b57cec5SDimitry Andric       DumpedAny = true;
115*0b57cec5SDimitry Andric       break;
116*0b57cec5SDimitry Andric     case TSK_ExplicitSpecialization:
117*0b57cec5SDimitry Andric       break;
118*0b57cec5SDimitry Andric     }
119*0b57cec5SDimitry Andric   }
120*0b57cec5SDimitry Andric 
121*0b57cec5SDimitry Andric   // Ensure we dump at least one decl for each specialization.
122*0b57cec5SDimitry Andric   if (!DumpedAny)
123*0b57cec5SDimitry Andric     NodeDumper.dumpDeclRef(D);
124*0b57cec5SDimitry Andric }
125*0b57cec5SDimitry Andric 
126*0b57cec5SDimitry Andric template <typename TemplateDecl>
127*0b57cec5SDimitry Andric void ASTDumper::dumpTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst) {
128*0b57cec5SDimitry Andric   dumpTemplateParameters(D->getTemplateParameters());
129*0b57cec5SDimitry Andric 
130*0b57cec5SDimitry Andric   Visit(D->getTemplatedDecl());
131*0b57cec5SDimitry Andric 
132*0b57cec5SDimitry Andric   for (const auto *Child : D->specializations())
133*0b57cec5SDimitry Andric     dumpTemplateDeclSpecialization(Child, DumpExplicitInst,
134*0b57cec5SDimitry Andric                                    !D->isCanonicalDecl());
135*0b57cec5SDimitry Andric }
136*0b57cec5SDimitry Andric 
137*0b57cec5SDimitry Andric void ASTDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
138*0b57cec5SDimitry Andric   // FIXME: We don't add a declaration of a function template specialization
139*0b57cec5SDimitry Andric   // to its context when it's explicitly instantiated, so dump explicit
140*0b57cec5SDimitry Andric   // instantiations when we dump the template itself.
141*0b57cec5SDimitry Andric   dumpTemplateDecl(D, true);
142*0b57cec5SDimitry Andric }
143*0b57cec5SDimitry Andric 
144*0b57cec5SDimitry Andric void ASTDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) {
145*0b57cec5SDimitry Andric   dumpTemplateDecl(D, false);
146*0b57cec5SDimitry Andric }
147*0b57cec5SDimitry Andric 
148*0b57cec5SDimitry Andric void ASTDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) {
149*0b57cec5SDimitry Andric   dumpTemplateDecl(D, false);
150*0b57cec5SDimitry Andric }
151*0b57cec5SDimitry Andric 
152*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
153*0b57cec5SDimitry Andric // Type method implementations
154*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
155*0b57cec5SDimitry Andric 
156*0b57cec5SDimitry Andric void QualType::dump(const char *msg) const {
157*0b57cec5SDimitry Andric   if (msg)
158*0b57cec5SDimitry Andric     llvm::errs() << msg << ": ";
159*0b57cec5SDimitry Andric   dump();
160*0b57cec5SDimitry Andric }
161*0b57cec5SDimitry Andric 
162*0b57cec5SDimitry Andric LLVM_DUMP_METHOD void QualType::dump() const { dump(llvm::errs()); }
163*0b57cec5SDimitry Andric 
164*0b57cec5SDimitry Andric LLVM_DUMP_METHOD void QualType::dump(llvm::raw_ostream &OS) const {
165*0b57cec5SDimitry Andric   ASTDumper Dumper(OS, nullptr, nullptr);
166*0b57cec5SDimitry Andric   Dumper.Visit(*this);
167*0b57cec5SDimitry Andric }
168*0b57cec5SDimitry Andric 
169*0b57cec5SDimitry Andric LLVM_DUMP_METHOD void Type::dump() const { dump(llvm::errs()); }
170*0b57cec5SDimitry Andric 
171*0b57cec5SDimitry Andric LLVM_DUMP_METHOD void Type::dump(llvm::raw_ostream &OS) const {
172*0b57cec5SDimitry Andric   QualType(this, 0).dump(OS);
173*0b57cec5SDimitry Andric }
174*0b57cec5SDimitry Andric 
175*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
176*0b57cec5SDimitry Andric // Decl method implementations
177*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
178*0b57cec5SDimitry Andric 
179*0b57cec5SDimitry Andric LLVM_DUMP_METHOD void Decl::dump() const { dump(llvm::errs()); }
180*0b57cec5SDimitry Andric 
181*0b57cec5SDimitry Andric LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS, bool Deserialize,
182*0b57cec5SDimitry Andric                                  ASTDumpOutputFormat Format) const {
183*0b57cec5SDimitry Andric   ASTContext &Ctx = getASTContext();
184*0b57cec5SDimitry Andric   const SourceManager &SM = Ctx.getSourceManager();
185*0b57cec5SDimitry Andric 
186*0b57cec5SDimitry Andric   if (ADOF_JSON == Format) {
187*0b57cec5SDimitry Andric     JSONDumper P(OS, SM, Ctx, Ctx.getPrintingPolicy(),
188*0b57cec5SDimitry Andric                  &Ctx.getCommentCommandTraits());
189*0b57cec5SDimitry Andric     (void)Deserialize; // FIXME?
190*0b57cec5SDimitry Andric     P.Visit(this);
191*0b57cec5SDimitry Andric   } else {
192*0b57cec5SDimitry Andric     ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &SM,
193*0b57cec5SDimitry Andric                 SM.getDiagnostics().getShowColors(), Ctx.getPrintingPolicy());
194*0b57cec5SDimitry Andric     P.setDeserialize(Deserialize);
195*0b57cec5SDimitry Andric     P.Visit(this);
196*0b57cec5SDimitry Andric   }
197*0b57cec5SDimitry Andric }
198*0b57cec5SDimitry Andric 
199*0b57cec5SDimitry Andric LLVM_DUMP_METHOD void Decl::dumpColor() const {
200*0b57cec5SDimitry Andric   const ASTContext &Ctx = getASTContext();
201*0b57cec5SDimitry Andric   ASTDumper P(llvm::errs(), &Ctx.getCommentCommandTraits(),
202*0b57cec5SDimitry Andric               &Ctx.getSourceManager(), /*ShowColors*/ true,
203*0b57cec5SDimitry Andric               Ctx.getPrintingPolicy());
204*0b57cec5SDimitry Andric   P.Visit(this);
205*0b57cec5SDimitry Andric }
206*0b57cec5SDimitry Andric 
207*0b57cec5SDimitry Andric LLVM_DUMP_METHOD void DeclContext::dumpLookups() const {
208*0b57cec5SDimitry Andric   dumpLookups(llvm::errs());
209*0b57cec5SDimitry Andric }
210*0b57cec5SDimitry Andric 
211*0b57cec5SDimitry Andric LLVM_DUMP_METHOD void DeclContext::dumpLookups(raw_ostream &OS,
212*0b57cec5SDimitry Andric                                                bool DumpDecls,
213*0b57cec5SDimitry Andric                                                bool Deserialize) const {
214*0b57cec5SDimitry Andric   const DeclContext *DC = this;
215*0b57cec5SDimitry Andric   while (!DC->isTranslationUnit())
216*0b57cec5SDimitry Andric     DC = DC->getParent();
217*0b57cec5SDimitry Andric   ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext();
218*0b57cec5SDimitry Andric   const SourceManager &SM = Ctx.getSourceManager();
219*0b57cec5SDimitry Andric   ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &Ctx.getSourceManager(),
220*0b57cec5SDimitry Andric               SM.getDiagnostics().getShowColors(), Ctx.getPrintingPolicy());
221*0b57cec5SDimitry Andric   P.setDeserialize(Deserialize);
222*0b57cec5SDimitry Andric   P.dumpLookups(this, DumpDecls);
223*0b57cec5SDimitry Andric }
224*0b57cec5SDimitry Andric 
225*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
226*0b57cec5SDimitry Andric // Stmt method implementations
227*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
228*0b57cec5SDimitry Andric 
229*0b57cec5SDimitry Andric LLVM_DUMP_METHOD void Stmt::dump(SourceManager &SM) const {
230*0b57cec5SDimitry Andric   dump(llvm::errs(), SM);
231*0b57cec5SDimitry Andric }
232*0b57cec5SDimitry Andric 
233*0b57cec5SDimitry Andric LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS, SourceManager &SM) const {
234*0b57cec5SDimitry Andric   ASTDumper P(OS, nullptr, &SM);
235*0b57cec5SDimitry Andric   P.Visit(this);
236*0b57cec5SDimitry Andric }
237*0b57cec5SDimitry Andric 
238*0b57cec5SDimitry Andric LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS) const {
239*0b57cec5SDimitry Andric   ASTDumper P(OS, nullptr, nullptr);
240*0b57cec5SDimitry Andric   P.Visit(this);
241*0b57cec5SDimitry Andric }
242*0b57cec5SDimitry Andric 
243*0b57cec5SDimitry Andric LLVM_DUMP_METHOD void Stmt::dump() const {
244*0b57cec5SDimitry Andric   ASTDumper P(llvm::errs(), nullptr, nullptr);
245*0b57cec5SDimitry Andric   P.Visit(this);
246*0b57cec5SDimitry Andric }
247*0b57cec5SDimitry Andric 
248*0b57cec5SDimitry Andric LLVM_DUMP_METHOD void Stmt::dumpColor() const {
249*0b57cec5SDimitry Andric   ASTDumper P(llvm::errs(), nullptr, nullptr, /*ShowColors*/true);
250*0b57cec5SDimitry Andric   P.Visit(this);
251*0b57cec5SDimitry Andric }
252*0b57cec5SDimitry Andric 
253*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
254*0b57cec5SDimitry Andric // Comment method implementations
255*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
256*0b57cec5SDimitry Andric 
257*0b57cec5SDimitry Andric LLVM_DUMP_METHOD void Comment::dump() const {
258*0b57cec5SDimitry Andric   dump(llvm::errs(), nullptr, nullptr);
259*0b57cec5SDimitry Andric }
260*0b57cec5SDimitry Andric 
261*0b57cec5SDimitry Andric LLVM_DUMP_METHOD void Comment::dump(const ASTContext &Context) const {
262*0b57cec5SDimitry Andric   dump(llvm::errs(), &Context.getCommentCommandTraits(),
263*0b57cec5SDimitry Andric        &Context.getSourceManager());
264*0b57cec5SDimitry Andric }
265*0b57cec5SDimitry Andric 
266*0b57cec5SDimitry Andric void Comment::dump(raw_ostream &OS, const CommandTraits *Traits,
267*0b57cec5SDimitry Andric                    const SourceManager *SM) const {
268*0b57cec5SDimitry Andric   const FullComment *FC = dyn_cast<FullComment>(this);
269*0b57cec5SDimitry Andric   if (!FC)
270*0b57cec5SDimitry Andric     return;
271*0b57cec5SDimitry Andric   ASTDumper D(OS, Traits, SM);
272*0b57cec5SDimitry Andric   D.Visit(FC, FC);
273*0b57cec5SDimitry Andric }
274*0b57cec5SDimitry Andric 
275*0b57cec5SDimitry Andric LLVM_DUMP_METHOD void Comment::dumpColor() const {
276*0b57cec5SDimitry Andric   const FullComment *FC = dyn_cast<FullComment>(this);
277*0b57cec5SDimitry Andric   if (!FC)
278*0b57cec5SDimitry Andric     return;
279*0b57cec5SDimitry Andric   ASTDumper D(llvm::errs(), nullptr, nullptr, /*ShowColors*/true);
280*0b57cec5SDimitry Andric   D.Visit(FC, FC);
281*0b57cec5SDimitry Andric }
282