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