1 //===--- ASTDumper.cpp - Dumping implementation for ASTs ------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements the AST dump methods, which dump out the
10 // AST in a form that exposes type details and other fields.
12 //===----------------------------------------------------------------------===//
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"
24 using namespace clang
;
25 using namespace clang::comments
;
27 void ASTDumper::dumpInvalidDeclContext(const DeclContext
*DC
) {
28 NodeDumper
.AddChild([=] {
30 ColorScope
Color(OS
, ShowColors
, NullColor
);
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.
41 ColorScope
Color(OS
, ShowColors
, DeclKindNameColor
);
44 NodeDumper
.dumpPointer(DC
);
47 ColorScope
Color(OS
, ShowColors
, DeclNameColor
);
48 OS
<< "unrecognized Decl kind " << (unsigned)DC
->getDeclKind();
54 void ASTDumper::dumpLookups(const DeclContext
*DC
, bool DumpDecls
) {
55 NodeDumper
.AddChild([=] {
56 OS
<< "StoredDeclsMap ";
57 NodeDumper
.dumpBareDeclRef(cast
<Decl
>(DC
));
59 const DeclContext
*Primary
= DC
->getPrimaryContext();
62 NodeDumper
.dumpPointer(cast
<Decl
>(Primary
));
65 bool HasUndeserializedLookups
= Primary
->hasExternalVisibleStorage();
67 auto Range
= getDeserialize()
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
;
74 NodeDumper
.AddChild([=] {
75 OS
<< "DeclarationName ";
77 ColorScope
Color(OS
, ShowColors
, DeclNameColor
);
78 OS
<< '\'' << Name
<< '\'';
81 for (DeclContextLookupResult::iterator RI
= R
.begin(), RE
= R
.end();
83 NodeDumper
.AddChild([=] {
84 NodeDumper
.dumpBareDeclRef(*RI
);
86 if (!(*RI
)->isUnconditionallyVisible())
89 // If requested, dump the redecl chain for this lookup.
91 // Dump earliest decl first.
92 std::function
<void(Decl
*)> DumpWithPrev
= [&](Decl
*D
) {
93 if (Decl
*Prev
= D
->getPreviousDecl())
104 if (HasUndeserializedLookups
) {
105 NodeDumper
.AddChild([=] {
106 ColorScope
Color(OS
, ShowColors
, UndeserializedColor
);
107 OS
<< "<undeserialized lookups>";
113 template <typename SpecializationDecl
>
114 void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl
*D
,
115 bool DumpExplicitInst
,
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
)
130 case TSK_ImplicitInstantiation
:
132 NodeDumper
.dumpDeclRef(Redecl
);
137 case TSK_ExplicitSpecialization
:
142 // Ensure we dump at least one decl for each specialization.
144 NodeDumper
.dumpDeclRef(D
);
147 template <typename TemplateDecl
>
148 void ASTDumper::dumpTemplateDecl(const TemplateDecl
*D
, bool DumpExplicitInst
) {
149 dumpTemplateParameters(D
->getTemplateParameters());
151 Visit(D
->getTemplatedDecl());
153 if (GetTraversalKind() == TK_AsIs
) {
154 for (const auto *Child
: D
->specializations())
155 dumpTemplateDeclSpecialization(Child
, DumpExplicitInst
,
156 !D
->isCanonicalDecl());
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);
167 void ASTDumper::VisitClassTemplateDecl(const ClassTemplateDecl
*D
) {
168 dumpTemplateDecl(D
, false);
171 void ASTDumper::VisitVarTemplateDecl(const VarTemplateDecl
*D
) {
172 dumpTemplateDecl(D
, false);
175 //===----------------------------------------------------------------------===//
176 // Type method implementations
177 //===----------------------------------------------------------------------===//
179 void QualType::dump(const char *msg
) const {
181 llvm::errs() << msg
<< ": ";
185 LLVM_DUMP_METHOD
void QualType::dump() const {
186 ASTDumper
Dumper(llvm::errs(), /*ShowColors=*/false);
190 LLVM_DUMP_METHOD
void QualType::dump(llvm::raw_ostream
&OS
,
191 const ASTContext
&Context
) const {
192 ASTDumper
Dumper(OS
, Context
, Context
.getDiagnostics().getShowColors());
196 LLVM_DUMP_METHOD
void Type::dump() const { QualType(this, 0).dump(); }
198 LLVM_DUMP_METHOD
void Type::dump(llvm::raw_ostream
&OS
,
199 const ASTContext
&Context
) const {
200 QualType(this, 0).dump(OS
, Context
);
203 //===----------------------------------------------------------------------===//
204 // Decl method implementations
205 //===----------------------------------------------------------------------===//
207 LLVM_DUMP_METHOD
void Decl::dump() const { dump(llvm::errs()); }
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();
214 if (ADOF_JSON
== Format
) {
215 JSONDumper
P(OS
, SM
, Ctx
, Ctx
.getPrintingPolicy(),
216 &Ctx
.getCommentCommandTraits());
217 (void)Deserialize
; // FIXME?
220 ASTDumper
P(OS
, Ctx
, Ctx
.getDiagnostics().getShowColors());
221 P
.setDeserialize(Deserialize
);
226 LLVM_DUMP_METHOD
void Decl::dumpColor() const {
227 const ASTContext
&Ctx
= getASTContext();
228 ASTDumper
P(llvm::errs(), Ctx
, /*ShowColors=*/true);
232 LLVM_DUMP_METHOD
void DeclContext::dumpAsDecl() const {
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);
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);
257 LLVM_DUMP_METHOD
void DeclContext::dumpLookups() const {
258 dumpLookups(llvm::errs());
261 LLVM_DUMP_METHOD
void DeclContext::dumpLookups(raw_ostream
&OS
,
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
);
273 //===----------------------------------------------------------------------===//
274 // Stmt method implementations
275 //===----------------------------------------------------------------------===//
277 LLVM_DUMP_METHOD
void Stmt::dump() const {
278 ASTDumper
P(llvm::errs(), /*ShowColors=*/false);
282 LLVM_DUMP_METHOD
void Stmt::dump(raw_ostream
&OS
,
283 const ASTContext
&Context
) const {
284 ASTDumper
P(OS
, Context
, Context
.getDiagnostics().getShowColors());
288 LLVM_DUMP_METHOD
void Stmt::dumpColor() const {
289 ASTDumper
P(llvm::errs(), /*ShowColors=*/true);
293 //===----------------------------------------------------------------------===//
294 // Comment method implementations
295 //===----------------------------------------------------------------------===//
297 LLVM_DUMP_METHOD
void Comment::dump() const {
298 const auto *FC
= dyn_cast
<FullComment
>(this);
301 ASTDumper
Dumper(llvm::errs(), /*ShowColors=*/false);
302 Dumper
.Visit(FC
, FC
);
305 LLVM_DUMP_METHOD
void Comment::dump(raw_ostream
&OS
,
306 const ASTContext
&Context
) const {
307 const auto *FC
= dyn_cast
<FullComment
>(this);
310 ASTDumper
Dumper(OS
, Context
, Context
.getDiagnostics().getShowColors());
311 Dumper
.Visit(FC
, FC
);
314 LLVM_DUMP_METHOD
void Comment::dumpColor() const {
315 const auto *FC
= dyn_cast
<FullComment
>(this);
318 ASTDumper
Dumper(llvm::errs(), /*ShowColors=*/true);
319 Dumper
.Visit(FC
, FC
);
322 //===----------------------------------------------------------------------===//
323 // APValue method implementations
324 //===----------------------------------------------------------------------===//
326 LLVM_DUMP_METHOD
void APValue::dump() const {
327 ASTDumper
Dumper(llvm::errs(), /*ShowColors=*/false);
328 Dumper
.Visit(*this, /*Ty=*/QualType());
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
));
338 //===----------------------------------------------------------------------===//
339 // ConceptReference method implementations
340 //===----------------------------------------------------------------------===//
342 LLVM_DUMP_METHOD
void ConceptReference::dump() const {
346 LLVM_DUMP_METHOD
void ConceptReference::dump(raw_ostream
&OS
) const {
347 auto &Ctx
= getNamedConcept()->getASTContext();
348 ASTDumper
P(OS
, Ctx
, Ctx
.getDiagnostics().getShowColors());