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