1e5dd7070Spatrick //===--- ASTDumper.cpp - Dumping implementation for ASTs ------------------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This file implements the AST dump methods, which dump out the
10e5dd7070Spatrick // AST in a form that exposes type details and other fields.
11e5dd7070Spatrick //
12e5dd7070Spatrick //===----------------------------------------------------------------------===//
13e5dd7070Spatrick
14e5dd7070Spatrick #include "clang/AST/ASTDumper.h"
15e5dd7070Spatrick #include "clang/AST/ASTContext.h"
16e5dd7070Spatrick #include "clang/AST/DeclLookups.h"
17e5dd7070Spatrick #include "clang/AST/JSONNodeDumper.h"
18e5dd7070Spatrick #include "clang/Basic/Builtins.h"
19e5dd7070Spatrick #include "clang/Basic/Module.h"
20e5dd7070Spatrick #include "clang/Basic/SourceManager.h"
21e5dd7070Spatrick #include "llvm/Support/raw_ostream.h"
22*12c85518Srobert
23e5dd7070Spatrick using namespace clang;
24e5dd7070Spatrick using namespace clang::comments;
25e5dd7070Spatrick
dumpInvalidDeclContext(const DeclContext * DC)26*12c85518Srobert void ASTDumper::dumpInvalidDeclContext(const DeclContext *DC) {
27*12c85518Srobert NodeDumper.AddChild([=] {
28*12c85518Srobert if (!DC) {
29*12c85518Srobert ColorScope Color(OS, ShowColors, NullColor);
30*12c85518Srobert OS << "<<<NULL>>>";
31*12c85518Srobert return;
32*12c85518Srobert }
33*12c85518Srobert // An invalid DeclContext is one for which a dyn_cast() from a DeclContext
34*12c85518Srobert // pointer to a Decl pointer would fail an assertion or otherwise fall prey
35*12c85518Srobert // to undefined behavior as a result of an invalid associated DeclKind.
36*12c85518Srobert // Such invalidity is not supposed to happen of course, but, when it does,
37*12c85518Srobert // the information provided below is intended to provide some hints about
38*12c85518Srobert // what might have gone awry.
39*12c85518Srobert {
40*12c85518Srobert ColorScope Color(OS, ShowColors, DeclKindNameColor);
41*12c85518Srobert OS << "DeclContext";
42*12c85518Srobert }
43*12c85518Srobert NodeDumper.dumpPointer(DC);
44*12c85518Srobert OS << " <";
45*12c85518Srobert {
46*12c85518Srobert ColorScope Color(OS, ShowColors, DeclNameColor);
47*12c85518Srobert OS << "unrecognized Decl kind " << (unsigned)DC->getDeclKind();
48*12c85518Srobert }
49*12c85518Srobert OS << ">";
50*12c85518Srobert });
51*12c85518Srobert }
52*12c85518Srobert
dumpLookups(const DeclContext * DC,bool DumpDecls)53e5dd7070Spatrick void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) {
54e5dd7070Spatrick NodeDumper.AddChild([=] {
55e5dd7070Spatrick OS << "StoredDeclsMap ";
56e5dd7070Spatrick NodeDumper.dumpBareDeclRef(cast<Decl>(DC));
57e5dd7070Spatrick
58e5dd7070Spatrick const DeclContext *Primary = DC->getPrimaryContext();
59e5dd7070Spatrick if (Primary != DC) {
60e5dd7070Spatrick OS << " primary";
61e5dd7070Spatrick NodeDumper.dumpPointer(cast<Decl>(Primary));
62e5dd7070Spatrick }
63e5dd7070Spatrick
64e5dd7070Spatrick bool HasUndeserializedLookups = Primary->hasExternalVisibleStorage();
65e5dd7070Spatrick
66e5dd7070Spatrick auto Range = getDeserialize()
67e5dd7070Spatrick ? Primary->lookups()
68e5dd7070Spatrick : Primary->noload_lookups(/*PreserveInternalState=*/true);
69e5dd7070Spatrick for (auto I = Range.begin(), E = Range.end(); I != E; ++I) {
70e5dd7070Spatrick DeclarationName Name = I.getLookupName();
71e5dd7070Spatrick DeclContextLookupResult R = *I;
72e5dd7070Spatrick
73e5dd7070Spatrick NodeDumper.AddChild([=] {
74e5dd7070Spatrick OS << "DeclarationName ";
75e5dd7070Spatrick {
76e5dd7070Spatrick ColorScope Color(OS, ShowColors, DeclNameColor);
77e5dd7070Spatrick OS << '\'' << Name << '\'';
78e5dd7070Spatrick }
79e5dd7070Spatrick
80e5dd7070Spatrick for (DeclContextLookupResult::iterator RI = R.begin(), RE = R.end();
81e5dd7070Spatrick RI != RE; ++RI) {
82e5dd7070Spatrick NodeDumper.AddChild([=] {
83e5dd7070Spatrick NodeDumper.dumpBareDeclRef(*RI);
84e5dd7070Spatrick
85ec727ea7Spatrick if (!(*RI)->isUnconditionallyVisible())
86e5dd7070Spatrick OS << " hidden";
87e5dd7070Spatrick
88e5dd7070Spatrick // If requested, dump the redecl chain for this lookup.
89e5dd7070Spatrick if (DumpDecls) {
90e5dd7070Spatrick // Dump earliest decl first.
91e5dd7070Spatrick std::function<void(Decl *)> DumpWithPrev = [&](Decl *D) {
92e5dd7070Spatrick if (Decl *Prev = D->getPreviousDecl())
93e5dd7070Spatrick DumpWithPrev(Prev);
94e5dd7070Spatrick Visit(D);
95e5dd7070Spatrick };
96e5dd7070Spatrick DumpWithPrev(*RI);
97e5dd7070Spatrick }
98e5dd7070Spatrick });
99e5dd7070Spatrick }
100e5dd7070Spatrick });
101e5dd7070Spatrick }
102e5dd7070Spatrick
103e5dd7070Spatrick if (HasUndeserializedLookups) {
104e5dd7070Spatrick NodeDumper.AddChild([=] {
105e5dd7070Spatrick ColorScope Color(OS, ShowColors, UndeserializedColor);
106e5dd7070Spatrick OS << "<undeserialized lookups>";
107e5dd7070Spatrick });
108e5dd7070Spatrick }
109e5dd7070Spatrick });
110e5dd7070Spatrick }
111e5dd7070Spatrick
112e5dd7070Spatrick template <typename SpecializationDecl>
dumpTemplateDeclSpecialization(const SpecializationDecl * D,bool DumpExplicitInst,bool DumpRefOnly)113e5dd7070Spatrick void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl *D,
114e5dd7070Spatrick bool DumpExplicitInst,
115e5dd7070Spatrick bool DumpRefOnly) {
116e5dd7070Spatrick bool DumpedAny = false;
117e5dd7070Spatrick for (const auto *RedeclWithBadType : D->redecls()) {
118e5dd7070Spatrick // FIXME: The redecls() range sometimes has elements of a less-specific
119e5dd7070Spatrick // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives
120e5dd7070Spatrick // us TagDecls, and should give CXXRecordDecls).
121*12c85518Srobert auto *Redecl = cast<SpecializationDecl>(RedeclWithBadType);
122e5dd7070Spatrick switch (Redecl->getTemplateSpecializationKind()) {
123e5dd7070Spatrick case TSK_ExplicitInstantiationDeclaration:
124e5dd7070Spatrick case TSK_ExplicitInstantiationDefinition:
125e5dd7070Spatrick if (!DumpExplicitInst)
126e5dd7070Spatrick break;
127*12c85518Srobert [[fallthrough]];
128e5dd7070Spatrick case TSK_Undeclared:
129e5dd7070Spatrick case TSK_ImplicitInstantiation:
130e5dd7070Spatrick if (DumpRefOnly)
131e5dd7070Spatrick NodeDumper.dumpDeclRef(Redecl);
132e5dd7070Spatrick else
133e5dd7070Spatrick Visit(Redecl);
134e5dd7070Spatrick DumpedAny = true;
135e5dd7070Spatrick break;
136e5dd7070Spatrick case TSK_ExplicitSpecialization:
137e5dd7070Spatrick break;
138e5dd7070Spatrick }
139e5dd7070Spatrick }
140e5dd7070Spatrick
141e5dd7070Spatrick // Ensure we dump at least one decl for each specialization.
142e5dd7070Spatrick if (!DumpedAny)
143e5dd7070Spatrick NodeDumper.dumpDeclRef(D);
144e5dd7070Spatrick }
145e5dd7070Spatrick
146e5dd7070Spatrick template <typename TemplateDecl>
dumpTemplateDecl(const TemplateDecl * D,bool DumpExplicitInst)147e5dd7070Spatrick void ASTDumper::dumpTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst) {
148e5dd7070Spatrick dumpTemplateParameters(D->getTemplateParameters());
149e5dd7070Spatrick
150e5dd7070Spatrick Visit(D->getTemplatedDecl());
151e5dd7070Spatrick
152a9ac8606Spatrick if (GetTraversalKind() == TK_AsIs) {
153e5dd7070Spatrick for (const auto *Child : D->specializations())
154e5dd7070Spatrick dumpTemplateDeclSpecialization(Child, DumpExplicitInst,
155e5dd7070Spatrick !D->isCanonicalDecl());
156e5dd7070Spatrick }
157a9ac8606Spatrick }
158e5dd7070Spatrick
VisitFunctionTemplateDecl(const FunctionTemplateDecl * D)159e5dd7070Spatrick void ASTDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
160e5dd7070Spatrick // FIXME: We don't add a declaration of a function template specialization
161e5dd7070Spatrick // to its context when it's explicitly instantiated, so dump explicit
162e5dd7070Spatrick // instantiations when we dump the template itself.
163e5dd7070Spatrick dumpTemplateDecl(D, true);
164e5dd7070Spatrick }
165e5dd7070Spatrick
VisitClassTemplateDecl(const ClassTemplateDecl * D)166e5dd7070Spatrick void ASTDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) {
167e5dd7070Spatrick dumpTemplateDecl(D, false);
168e5dd7070Spatrick }
169e5dd7070Spatrick
VisitVarTemplateDecl(const VarTemplateDecl * D)170e5dd7070Spatrick void ASTDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) {
171e5dd7070Spatrick dumpTemplateDecl(D, false);
172e5dd7070Spatrick }
173e5dd7070Spatrick
174e5dd7070Spatrick //===----------------------------------------------------------------------===//
175e5dd7070Spatrick // Type method implementations
176e5dd7070Spatrick //===----------------------------------------------------------------------===//
177e5dd7070Spatrick
dump(const char * msg) const178e5dd7070Spatrick void QualType::dump(const char *msg) const {
179e5dd7070Spatrick if (msg)
180e5dd7070Spatrick llvm::errs() << msg << ": ";
181e5dd7070Spatrick dump();
182e5dd7070Spatrick }
183e5dd7070Spatrick
dump() const184ec727ea7Spatrick LLVM_DUMP_METHOD void QualType::dump() const {
185ec727ea7Spatrick ASTDumper Dumper(llvm::errs(), /*ShowColors=*/false);
186e5dd7070Spatrick Dumper.Visit(*this);
187e5dd7070Spatrick }
188e5dd7070Spatrick
dump(llvm::raw_ostream & OS,const ASTContext & Context) const189ec727ea7Spatrick LLVM_DUMP_METHOD void QualType::dump(llvm::raw_ostream &OS,
190ec727ea7Spatrick const ASTContext &Context) const {
191ec727ea7Spatrick ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors());
192ec727ea7Spatrick Dumper.Visit(*this);
193ec727ea7Spatrick }
194e5dd7070Spatrick
dump() const195ec727ea7Spatrick LLVM_DUMP_METHOD void Type::dump() const { QualType(this, 0).dump(); }
196ec727ea7Spatrick
dump(llvm::raw_ostream & OS,const ASTContext & Context) const197ec727ea7Spatrick LLVM_DUMP_METHOD void Type::dump(llvm::raw_ostream &OS,
198ec727ea7Spatrick const ASTContext &Context) const {
199ec727ea7Spatrick QualType(this, 0).dump(OS, Context);
200e5dd7070Spatrick }
201e5dd7070Spatrick
202e5dd7070Spatrick //===----------------------------------------------------------------------===//
203e5dd7070Spatrick // Decl method implementations
204e5dd7070Spatrick //===----------------------------------------------------------------------===//
205e5dd7070Spatrick
dump() const206e5dd7070Spatrick LLVM_DUMP_METHOD void Decl::dump() const { dump(llvm::errs()); }
207e5dd7070Spatrick
dump(raw_ostream & OS,bool Deserialize,ASTDumpOutputFormat Format) const208e5dd7070Spatrick LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS, bool Deserialize,
209e5dd7070Spatrick ASTDumpOutputFormat Format) const {
210e5dd7070Spatrick ASTContext &Ctx = getASTContext();
211e5dd7070Spatrick const SourceManager &SM = Ctx.getSourceManager();
212e5dd7070Spatrick
213e5dd7070Spatrick if (ADOF_JSON == Format) {
214e5dd7070Spatrick JSONDumper P(OS, SM, Ctx, Ctx.getPrintingPolicy(),
215e5dd7070Spatrick &Ctx.getCommentCommandTraits());
216e5dd7070Spatrick (void)Deserialize; // FIXME?
217e5dd7070Spatrick P.Visit(this);
218e5dd7070Spatrick } else {
219ec727ea7Spatrick ASTDumper P(OS, Ctx, Ctx.getDiagnostics().getShowColors());
220e5dd7070Spatrick P.setDeserialize(Deserialize);
221e5dd7070Spatrick P.Visit(this);
222e5dd7070Spatrick }
223e5dd7070Spatrick }
224e5dd7070Spatrick
dumpColor() const225e5dd7070Spatrick LLVM_DUMP_METHOD void Decl::dumpColor() const {
226e5dd7070Spatrick const ASTContext &Ctx = getASTContext();
227ec727ea7Spatrick ASTDumper P(llvm::errs(), Ctx, /*ShowColors=*/true);
228e5dd7070Spatrick P.Visit(this);
229e5dd7070Spatrick }
230e5dd7070Spatrick
dumpAsDecl() const231*12c85518Srobert LLVM_DUMP_METHOD void DeclContext::dumpAsDecl() const {
232*12c85518Srobert dumpAsDecl(nullptr);
233*12c85518Srobert }
234*12c85518Srobert
dumpAsDecl(const ASTContext * Ctx) const235*12c85518Srobert LLVM_DUMP_METHOD void DeclContext::dumpAsDecl(const ASTContext *Ctx) const {
236*12c85518Srobert // By design, DeclContext is required to be a base class of some class that
237*12c85518Srobert // derives from Decl. Thus, it should always be possible to dyn_cast() from
238*12c85518Srobert // a DeclContext pointer to a Decl pointer and Decl::castFromDeclContext()
239*12c85518Srobert // asserts that to be the case. Since this function is intended for use in a
240*12c85518Srobert // debugger, it performs an additional check in order to prevent a failed
241*12c85518Srobert // cast and assertion. If that check fails, then the (invalid) DeclContext
242*12c85518Srobert // is dumped with an indication of its invalidity.
243*12c85518Srobert if (hasValidDeclKind()) {
244*12c85518Srobert const auto *D = cast<Decl>(this);
245*12c85518Srobert D->dump();
246*12c85518Srobert } else {
247*12c85518Srobert // If an ASTContext is not available, a less capable ASTDumper is
248*12c85518Srobert // constructed for which color diagnostics are, regrettably, disabled.
249*12c85518Srobert ASTDumper P = Ctx ? ASTDumper(llvm::errs(), *Ctx,
250*12c85518Srobert Ctx->getDiagnostics().getShowColors())
251*12c85518Srobert : ASTDumper(llvm::errs(), /*ShowColors*/ false);
252*12c85518Srobert P.dumpInvalidDeclContext(this);
253*12c85518Srobert }
254*12c85518Srobert }
255*12c85518Srobert
dumpLookups() const256e5dd7070Spatrick LLVM_DUMP_METHOD void DeclContext::dumpLookups() const {
257e5dd7070Spatrick dumpLookups(llvm::errs());
258e5dd7070Spatrick }
259e5dd7070Spatrick
dumpLookups(raw_ostream & OS,bool DumpDecls,bool Deserialize) const260e5dd7070Spatrick LLVM_DUMP_METHOD void DeclContext::dumpLookups(raw_ostream &OS,
261e5dd7070Spatrick bool DumpDecls,
262e5dd7070Spatrick bool Deserialize) const {
263e5dd7070Spatrick const DeclContext *DC = this;
264e5dd7070Spatrick while (!DC->isTranslationUnit())
265e5dd7070Spatrick DC = DC->getParent();
266ec727ea7Spatrick const ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext();
267ec727ea7Spatrick ASTDumper P(OS, Ctx, Ctx.getDiagnostics().getShowColors());
268e5dd7070Spatrick P.setDeserialize(Deserialize);
269e5dd7070Spatrick P.dumpLookups(this, DumpDecls);
270e5dd7070Spatrick }
271e5dd7070Spatrick
272e5dd7070Spatrick //===----------------------------------------------------------------------===//
273e5dd7070Spatrick // Stmt method implementations
274e5dd7070Spatrick //===----------------------------------------------------------------------===//
275e5dd7070Spatrick
dump() const276e5dd7070Spatrick LLVM_DUMP_METHOD void Stmt::dump() const {
277ec727ea7Spatrick ASTDumper P(llvm::errs(), /*ShowColors=*/false);
278ec727ea7Spatrick P.Visit(this);
279ec727ea7Spatrick }
280ec727ea7Spatrick
dump(raw_ostream & OS,const ASTContext & Context) const281ec727ea7Spatrick LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS,
282ec727ea7Spatrick const ASTContext &Context) const {
283ec727ea7Spatrick ASTDumper P(OS, Context, Context.getDiagnostics().getShowColors());
284e5dd7070Spatrick P.Visit(this);
285e5dd7070Spatrick }
286e5dd7070Spatrick
dumpColor() const287e5dd7070Spatrick LLVM_DUMP_METHOD void Stmt::dumpColor() const {
288ec727ea7Spatrick ASTDumper P(llvm::errs(), /*ShowColors=*/true);
289e5dd7070Spatrick P.Visit(this);
290e5dd7070Spatrick }
291e5dd7070Spatrick
292e5dd7070Spatrick //===----------------------------------------------------------------------===//
293e5dd7070Spatrick // Comment method implementations
294e5dd7070Spatrick //===----------------------------------------------------------------------===//
295e5dd7070Spatrick
dump() const296e5dd7070Spatrick LLVM_DUMP_METHOD void Comment::dump() const {
297ec727ea7Spatrick const auto *FC = dyn_cast<FullComment>(this);
298e5dd7070Spatrick if (!FC)
299e5dd7070Spatrick return;
300ec727ea7Spatrick ASTDumper Dumper(llvm::errs(), /*ShowColors=*/false);
301ec727ea7Spatrick Dumper.Visit(FC, FC);
302ec727ea7Spatrick }
303ec727ea7Spatrick
dump(raw_ostream & OS,const ASTContext & Context) const304ec727ea7Spatrick LLVM_DUMP_METHOD void Comment::dump(raw_ostream &OS,
305ec727ea7Spatrick const ASTContext &Context) const {
306ec727ea7Spatrick const auto *FC = dyn_cast<FullComment>(this);
307ec727ea7Spatrick if (!FC)
308ec727ea7Spatrick return;
309ec727ea7Spatrick ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors());
310ec727ea7Spatrick Dumper.Visit(FC, FC);
311e5dd7070Spatrick }
312e5dd7070Spatrick
dumpColor() const313e5dd7070Spatrick LLVM_DUMP_METHOD void Comment::dumpColor() const {
314ec727ea7Spatrick const auto *FC = dyn_cast<FullComment>(this);
315e5dd7070Spatrick if (!FC)
316e5dd7070Spatrick return;
317ec727ea7Spatrick ASTDumper Dumper(llvm::errs(), /*ShowColors=*/true);
318ec727ea7Spatrick Dumper.Visit(FC, FC);
319ec727ea7Spatrick }
320ec727ea7Spatrick
321ec727ea7Spatrick //===----------------------------------------------------------------------===//
322ec727ea7Spatrick // APValue method implementations
323ec727ea7Spatrick //===----------------------------------------------------------------------===//
324ec727ea7Spatrick
dump() const325ec727ea7Spatrick LLVM_DUMP_METHOD void APValue::dump() const {
326ec727ea7Spatrick ASTDumper Dumper(llvm::errs(), /*ShowColors=*/false);
327ec727ea7Spatrick Dumper.Visit(*this, /*Ty=*/QualType());
328ec727ea7Spatrick }
329ec727ea7Spatrick
dump(raw_ostream & OS,const ASTContext & Context) const330ec727ea7Spatrick LLVM_DUMP_METHOD void APValue::dump(raw_ostream &OS,
331ec727ea7Spatrick const ASTContext &Context) const {
332ec727ea7Spatrick ASTDumper Dumper(llvm::errs(), Context,
333ec727ea7Spatrick Context.getDiagnostics().getShowColors());
334ec727ea7Spatrick Dumper.Visit(*this, /*Ty=*/Context.getPointerType(Context.CharTy));
335e5dd7070Spatrick }
336