/src/llvm-project/clang/lib/AST/ASTDumper.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 0 | void ASTDumper::dumpInvalidDeclContext(const DeclContext *DC) { |
28 | 0 | NodeDumper.AddChild([=] { |
29 | 0 | if (!DC) { |
30 | 0 | ColorScope Color(OS, ShowColors, NullColor); |
31 | 0 | OS << "<<<NULL>>>"; |
32 | 0 | return; |
33 | 0 | } |
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 | 0 | { |
41 | 0 | ColorScope Color(OS, ShowColors, DeclKindNameColor); |
42 | 0 | OS << "DeclContext"; |
43 | 0 | } |
44 | 0 | NodeDumper.dumpPointer(DC); |
45 | 0 | OS << " <"; |
46 | 0 | { |
47 | 0 | ColorScope Color(OS, ShowColors, DeclNameColor); |
48 | 0 | OS << "unrecognized Decl kind " << (unsigned)DC->getDeclKind(); |
49 | 0 | } |
50 | 0 | OS << ">"; |
51 | 0 | }); |
52 | 0 | } |
53 | | |
54 | 0 | void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) { |
55 | 0 | NodeDumper.AddChild([=] { |
56 | 0 | OS << "StoredDeclsMap "; |
57 | 0 | NodeDumper.dumpBareDeclRef(cast<Decl>(DC)); |
58 | |
|
59 | 0 | const DeclContext *Primary = DC->getPrimaryContext(); |
60 | 0 | if (Primary != DC) { |
61 | 0 | OS << " primary"; |
62 | 0 | NodeDumper.dumpPointer(cast<Decl>(Primary)); |
63 | 0 | } |
64 | |
|
65 | 0 | bool HasUndeserializedLookups = Primary->hasExternalVisibleStorage(); |
66 | |
|
67 | 0 | auto Range = getDeserialize() |
68 | 0 | ? Primary->lookups() |
69 | 0 | : Primary->noload_lookups(/*PreserveInternalState=*/true); |
70 | 0 | for (auto I = Range.begin(), E = Range.end(); I != E; ++I) { |
71 | 0 | DeclarationName Name = I.getLookupName(); |
72 | 0 | DeclContextLookupResult R = *I; |
73 | |
|
74 | 0 | NodeDumper.AddChild([=] { |
75 | 0 | OS << "DeclarationName "; |
76 | 0 | { |
77 | 0 | ColorScope Color(OS, ShowColors, DeclNameColor); |
78 | 0 | OS << '\'' << Name << '\''; |
79 | 0 | } |
80 | |
|
81 | 0 | for (DeclContextLookupResult::iterator RI = R.begin(), RE = R.end(); |
82 | 0 | RI != RE; ++RI) { |
83 | 0 | NodeDumper.AddChild([=] { |
84 | 0 | NodeDumper.dumpBareDeclRef(*RI); |
85 | |
|
86 | 0 | if (!(*RI)->isUnconditionallyVisible()) |
87 | 0 | OS << " hidden"; |
88 | | |
89 | | // If requested, dump the redecl chain for this lookup. |
90 | 0 | if (DumpDecls) { |
91 | | // Dump earliest decl first. |
92 | 0 | std::function<void(Decl *)> DumpWithPrev = [&](Decl *D) { |
93 | 0 | if (Decl *Prev = D->getPreviousDecl()) |
94 | 0 | DumpWithPrev(Prev); |
95 | 0 | Visit(D); |
96 | 0 | }; |
97 | 0 | DumpWithPrev(*RI); |
98 | 0 | } |
99 | 0 | }); |
100 | 0 | } |
101 | 0 | }); |
102 | 0 | } |
103 | |
|
104 | 0 | if (HasUndeserializedLookups) { |
105 | 0 | NodeDumper.AddChild([=] { |
106 | 0 | ColorScope Color(OS, ShowColors, UndeserializedColor); |
107 | 0 | OS << "<undeserialized lookups>"; |
108 | 0 | }); |
109 | 0 | } |
110 | 0 | }); |
111 | 0 | } |
112 | | |
113 | | template <typename SpecializationDecl> |
114 | | void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl *D, |
115 | | bool DumpExplicitInst, |
116 | 0 | bool DumpRefOnly) { |
117 | 0 | bool DumpedAny = false; |
118 | 0 | 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 | 0 | auto *Redecl = cast<SpecializationDecl>(RedeclWithBadType); |
123 | 0 | switch (Redecl->getTemplateSpecializationKind()) { |
124 | 0 | case TSK_ExplicitInstantiationDeclaration: |
125 | 0 | case TSK_ExplicitInstantiationDefinition: |
126 | 0 | if (!DumpExplicitInst) |
127 | 0 | break; |
128 | 0 | [[fallthrough]]; |
129 | 0 | case TSK_Undeclared: |
130 | 0 | case TSK_ImplicitInstantiation: |
131 | 0 | if (DumpRefOnly) |
132 | 0 | NodeDumper.dumpDeclRef(Redecl); |
133 | 0 | else |
134 | 0 | Visit(Redecl); |
135 | 0 | DumpedAny = true; |
136 | 0 | break; |
137 | 0 | case TSK_ExplicitSpecialization: |
138 | 0 | break; |
139 | 0 | } |
140 | 0 | } |
141 | | |
142 | | // Ensure we dump at least one decl for each specialization. |
143 | 0 | if (!DumpedAny) |
144 | 0 | NodeDumper.dumpDeclRef(D); |
145 | 0 | } Unexecuted instantiation: void clang::ASTDumper::dumpTemplateDeclSpecialization<clang::FunctionDecl>(clang::FunctionDecl const*, bool, bool) Unexecuted instantiation: void clang::ASTDumper::dumpTemplateDeclSpecialization<clang::ClassTemplateSpecializationDecl>(clang::ClassTemplateSpecializationDecl const*, bool, bool) Unexecuted instantiation: void clang::ASTDumper::dumpTemplateDeclSpecialization<clang::VarTemplateSpecializationDecl>(clang::VarTemplateSpecializationDecl const*, bool, bool) |
146 | | |
147 | | template <typename TemplateDecl> |
148 | 0 | void ASTDumper::dumpTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst) { |
149 | 0 | dumpTemplateParameters(D->getTemplateParameters()); |
150 | |
|
151 | 0 | Visit(D->getTemplatedDecl()); |
152 | |
|
153 | 0 | if (GetTraversalKind() == TK_AsIs) { |
154 | 0 | for (const auto *Child : D->specializations()) |
155 | 0 | dumpTemplateDeclSpecialization(Child, DumpExplicitInst, |
156 | 0 | !D->isCanonicalDecl()); |
157 | 0 | } |
158 | 0 | } Unexecuted instantiation: void clang::ASTDumper::dumpTemplateDecl<clang::FunctionTemplateDecl>(clang::FunctionTemplateDecl const*, bool) Unexecuted instantiation: void clang::ASTDumper::dumpTemplateDecl<clang::ClassTemplateDecl>(clang::ClassTemplateDecl const*, bool) Unexecuted instantiation: void clang::ASTDumper::dumpTemplateDecl<clang::VarTemplateDecl>(clang::VarTemplateDecl const*, bool) |
159 | | |
160 | 0 | 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 | 0 | dumpTemplateDecl(D, true); |
165 | 0 | } |
166 | | |
167 | 0 | void ASTDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) { |
168 | 0 | dumpTemplateDecl(D, false); |
169 | 0 | } |
170 | | |
171 | 0 | void ASTDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) { |
172 | 0 | dumpTemplateDecl(D, false); |
173 | 0 | } |
174 | | |
175 | | //===----------------------------------------------------------------------===// |
176 | | // Type method implementations |
177 | | //===----------------------------------------------------------------------===// |
178 | | |
179 | 0 | void QualType::dump(const char *msg) const { |
180 | 0 | if (msg) |
181 | 0 | llvm::errs() << msg << ": "; |
182 | 0 | dump(); |
183 | 0 | } |
184 | | |
185 | 0 | LLVM_DUMP_METHOD void QualType::dump() const { |
186 | 0 | ASTDumper Dumper(llvm::errs(), /*ShowColors=*/false); |
187 | 0 | Dumper.Visit(*this); |
188 | 0 | } |
189 | | |
190 | | LLVM_DUMP_METHOD void QualType::dump(llvm::raw_ostream &OS, |
191 | 0 | const ASTContext &Context) const { |
192 | 0 | ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors()); |
193 | 0 | Dumper.Visit(*this); |
194 | 0 | } |
195 | | |
196 | 0 | LLVM_DUMP_METHOD void Type::dump() const { QualType(this, 0).dump(); } |
197 | | |
198 | | LLVM_DUMP_METHOD void Type::dump(llvm::raw_ostream &OS, |
199 | 0 | const ASTContext &Context) const { |
200 | 0 | QualType(this, 0).dump(OS, Context); |
201 | 0 | } |
202 | | |
203 | | //===----------------------------------------------------------------------===// |
204 | | // Decl method implementations |
205 | | //===----------------------------------------------------------------------===// |
206 | | |
207 | 0 | LLVM_DUMP_METHOD void Decl::dump() const { dump(llvm::errs()); } |
208 | | |
209 | | LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS, bool Deserialize, |
210 | 0 | ASTDumpOutputFormat Format) const { |
211 | 0 | ASTContext &Ctx = getASTContext(); |
212 | 0 | const SourceManager &SM = Ctx.getSourceManager(); |
213 | |
|
214 | 0 | if (ADOF_JSON == Format) { |
215 | 0 | JSONDumper P(OS, SM, Ctx, Ctx.getPrintingPolicy(), |
216 | 0 | &Ctx.getCommentCommandTraits()); |
217 | 0 | (void)Deserialize; // FIXME? |
218 | 0 | P.Visit(this); |
219 | 0 | } else { |
220 | 0 | ASTDumper P(OS, Ctx, Ctx.getDiagnostics().getShowColors()); |
221 | 0 | P.setDeserialize(Deserialize); |
222 | 0 | P.Visit(this); |
223 | 0 | } |
224 | 0 | } |
225 | | |
226 | 0 | LLVM_DUMP_METHOD void Decl::dumpColor() const { |
227 | 0 | const ASTContext &Ctx = getASTContext(); |
228 | 0 | ASTDumper P(llvm::errs(), Ctx, /*ShowColors=*/true); |
229 | 0 | P.Visit(this); |
230 | 0 | } |
231 | | |
232 | 0 | LLVM_DUMP_METHOD void DeclContext::dumpAsDecl() const { |
233 | 0 | dumpAsDecl(nullptr); |
234 | 0 | } |
235 | | |
236 | 0 | 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 | 0 | if (hasValidDeclKind()) { |
245 | 0 | const auto *D = cast<Decl>(this); |
246 | 0 | D->dump(); |
247 | 0 | } else { |
248 | | // If an ASTContext is not available, a less capable ASTDumper is |
249 | | // constructed for which color diagnostics are, regrettably, disabled. |
250 | 0 | ASTDumper P = Ctx ? ASTDumper(llvm::errs(), *Ctx, |
251 | 0 | Ctx->getDiagnostics().getShowColors()) |
252 | 0 | : ASTDumper(llvm::errs(), /*ShowColors*/ false); |
253 | 0 | P.dumpInvalidDeclContext(this); |
254 | 0 | } |
255 | 0 | } |
256 | | |
257 | 0 | LLVM_DUMP_METHOD void DeclContext::dumpLookups() const { |
258 | 0 | dumpLookups(llvm::errs()); |
259 | 0 | } |
260 | | |
261 | | LLVM_DUMP_METHOD void DeclContext::dumpLookups(raw_ostream &OS, |
262 | | bool DumpDecls, |
263 | 0 | bool Deserialize) const { |
264 | 0 | const DeclContext *DC = this; |
265 | 0 | while (!DC->isTranslationUnit()) |
266 | 0 | DC = DC->getParent(); |
267 | 0 | const ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext(); |
268 | 0 | ASTDumper P(OS, Ctx, Ctx.getDiagnostics().getShowColors()); |
269 | 0 | P.setDeserialize(Deserialize); |
270 | 0 | P.dumpLookups(this, DumpDecls); |
271 | 0 | } |
272 | | |
273 | | //===----------------------------------------------------------------------===// |
274 | | // Stmt method implementations |
275 | | //===----------------------------------------------------------------------===// |
276 | | |
277 | 0 | LLVM_DUMP_METHOD void Stmt::dump() const { |
278 | 0 | ASTDumper P(llvm::errs(), /*ShowColors=*/false); |
279 | 0 | P.Visit(this); |
280 | 0 | } |
281 | | |
282 | | LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS, |
283 | 0 | const ASTContext &Context) const { |
284 | 0 | ASTDumper P(OS, Context, Context.getDiagnostics().getShowColors()); |
285 | 0 | P.Visit(this); |
286 | 0 | } |
287 | | |
288 | 0 | LLVM_DUMP_METHOD void Stmt::dumpColor() const { |
289 | 0 | ASTDumper P(llvm::errs(), /*ShowColors=*/true); |
290 | 0 | P.Visit(this); |
291 | 0 | } |
292 | | |
293 | | //===----------------------------------------------------------------------===// |
294 | | // Comment method implementations |
295 | | //===----------------------------------------------------------------------===// |
296 | | |
297 | 0 | LLVM_DUMP_METHOD void Comment::dump() const { |
298 | 0 | const auto *FC = dyn_cast<FullComment>(this); |
299 | 0 | if (!FC) |
300 | 0 | return; |
301 | 0 | ASTDumper Dumper(llvm::errs(), /*ShowColors=*/false); |
302 | 0 | Dumper.Visit(FC, FC); |
303 | 0 | } |
304 | | |
305 | | LLVM_DUMP_METHOD void Comment::dump(raw_ostream &OS, |
306 | 0 | const ASTContext &Context) const { |
307 | 0 | const auto *FC = dyn_cast<FullComment>(this); |
308 | 0 | if (!FC) |
309 | 0 | return; |
310 | 0 | ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors()); |
311 | 0 | Dumper.Visit(FC, FC); |
312 | 0 | } |
313 | | |
314 | 0 | LLVM_DUMP_METHOD void Comment::dumpColor() const { |
315 | 0 | const auto *FC = dyn_cast<FullComment>(this); |
316 | 0 | if (!FC) |
317 | 0 | return; |
318 | 0 | ASTDumper Dumper(llvm::errs(), /*ShowColors=*/true); |
319 | 0 | Dumper.Visit(FC, FC); |
320 | 0 | } |
321 | | |
322 | | //===----------------------------------------------------------------------===// |
323 | | // APValue method implementations |
324 | | //===----------------------------------------------------------------------===// |
325 | | |
326 | 0 | LLVM_DUMP_METHOD void APValue::dump() const { |
327 | 0 | ASTDumper Dumper(llvm::errs(), /*ShowColors=*/false); |
328 | 0 | Dumper.Visit(*this, /*Ty=*/QualType()); |
329 | 0 | } |
330 | | |
331 | | LLVM_DUMP_METHOD void APValue::dump(raw_ostream &OS, |
332 | 0 | const ASTContext &Context) const { |
333 | 0 | ASTDumper Dumper(llvm::errs(), Context, |
334 | 0 | Context.getDiagnostics().getShowColors()); |
335 | 0 | Dumper.Visit(*this, /*Ty=*/Context.getPointerType(Context.CharTy)); |
336 | 0 | } |
337 | | |
338 | | //===----------------------------------------------------------------------===// |
339 | | // ConceptReference method implementations |
340 | | //===----------------------------------------------------------------------===// |
341 | | |
342 | 0 | LLVM_DUMP_METHOD void ConceptReference::dump() const { |
343 | 0 | dump(llvm::errs()); |
344 | 0 | } |
345 | | |
346 | 0 | LLVM_DUMP_METHOD void ConceptReference::dump(raw_ostream &OS) const { |
347 | 0 | auto &Ctx = getNamedConcept()->getASTContext(); |
348 | 0 | ASTDumper P(OS, Ctx, Ctx.getDiagnostics().getShowColors()); |
349 | 0 | P.Visit(this); |
350 | 0 | } |