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