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/ASTContext.h"
15 #include "clang/AST/ASTNodeTraverser.h"
16 #include "clang/AST/DeclLookups.h"
17 #include "clang/AST/TextNodeDumper.h"
18 #include "clang/Basic/Builtins.h"
19 #include "clang/Basic/Module.h"
20 #include "clang/Basic/SourceManager.h"
21 #include "llvm/Support/raw_ostream.h"
22 using namespace clang;
23 using namespace clang::comments;
24 
25 //===----------------------------------------------------------------------===//
26 // ASTDumper Visitor
27 //===----------------------------------------------------------------------===//
28 
29 namespace  {
30 
31 class ASTDumper : public ASTNodeTraverser<ASTDumper, TextNodeDumper> {
32 
33   TextNodeDumper NodeDumper;
34 
35   raw_ostream &OS;
36 
37   const bool ShowColors;
38 
39 public:
40   ASTDumper(raw_ostream &OS, const CommandTraits *Traits,
41             const SourceManager *SM)
42       : ASTDumper(OS, Traits, SM, SM && SM->getDiagnostics().getShowColors()) {}
43 
44   ASTDumper(raw_ostream &OS, const CommandTraits *Traits,
45             const SourceManager *SM, bool ShowColors)
46       : ASTDumper(OS, Traits, SM, ShowColors, LangOptions()) {}
47   ASTDumper(raw_ostream &OS, const CommandTraits *Traits,
48             const SourceManager *SM, bool ShowColors,
49             const PrintingPolicy &PrintPolicy)
50       : NodeDumper(OS, ShowColors, SM, PrintPolicy, Traits), OS(OS),
51         ShowColors(ShowColors) {}
52 
53   TextNodeDumper &doGetNodeDelegate() { return NodeDumper; }
54 
55   void dumpLookups(const DeclContext *DC, bool DumpDecls);
56 
57   template <typename SpecializationDecl>
58   void dumpTemplateDeclSpecialization(const SpecializationDecl *D,
59                                       bool DumpExplicitInst, bool DumpRefOnly);
60   template <typename TemplateDecl>
61   void dumpTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst);
62 
63   void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D);
64   void VisitClassTemplateDecl(const ClassTemplateDecl *D);
65   void VisitVarTemplateDecl(const VarTemplateDecl *D);
66 };
67 } // namespace
68 
69 void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) {
70   NodeDumper.AddChild([=] {
71     OS << "StoredDeclsMap ";
72     NodeDumper.dumpBareDeclRef(cast<Decl>(DC));
73 
74     const DeclContext *Primary = DC->getPrimaryContext();
75     if (Primary != DC) {
76       OS << " primary";
77       NodeDumper.dumpPointer(cast<Decl>(Primary));
78     }
79 
80     bool HasUndeserializedLookups = Primary->hasExternalVisibleStorage();
81 
82     auto Range = getDeserialize()
83                      ? Primary->lookups()
84                      : Primary->noload_lookups(/*PreserveInternalState=*/true);
85     for (auto I = Range.begin(), E = Range.end(); I != E; ++I) {
86       DeclarationName Name = I.getLookupName();
87       DeclContextLookupResult R = *I;
88 
89       NodeDumper.AddChild([=] {
90         OS << "DeclarationName ";
91         {
92           ColorScope Color(OS, ShowColors, DeclNameColor);
93           OS << '\'' << Name << '\'';
94         }
95 
96         for (DeclContextLookupResult::iterator RI = R.begin(), RE = R.end();
97              RI != RE; ++RI) {
98           NodeDumper.AddChild([=] {
99             NodeDumper.dumpBareDeclRef(*RI);
100 
101             if ((*RI)->isHidden())
102               OS << " hidden";
103 
104             // If requested, dump the redecl chain for this lookup.
105             if (DumpDecls) {
106               // Dump earliest decl first.
107               std::function<void(Decl *)> DumpWithPrev = [&](Decl *D) {
108                 if (Decl *Prev = D->getPreviousDecl())
109                   DumpWithPrev(Prev);
110                 Visit(D);
111               };
112               DumpWithPrev(*RI);
113             }
114           });
115         }
116       });
117     }
118 
119     if (HasUndeserializedLookups) {
120       NodeDumper.AddChild([=] {
121         ColorScope Color(OS, ShowColors, UndeserializedColor);
122         OS << "<undeserialized lookups>";
123       });
124     }
125   });
126 }
127 
128 template <typename SpecializationDecl>
129 void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl *D,
130                                                bool DumpExplicitInst,
131                                                bool DumpRefOnly) {
132   bool DumpedAny = false;
133   for (const auto *RedeclWithBadType : D->redecls()) {
134     // FIXME: The redecls() range sometimes has elements of a less-specific
135     // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives
136     // us TagDecls, and should give CXXRecordDecls).
137     auto *Redecl = dyn_cast<SpecializationDecl>(RedeclWithBadType);
138     if (!Redecl) {
139       // Found the injected-class-name for a class template. This will be dumped
140       // as part of its surrounding class so we don't need to dump it here.
141       assert(isa<CXXRecordDecl>(RedeclWithBadType) &&
142              "expected an injected-class-name");
143       continue;
144     }
145 
146     switch (Redecl->getTemplateSpecializationKind()) {
147     case TSK_ExplicitInstantiationDeclaration:
148     case TSK_ExplicitInstantiationDefinition:
149       if (!DumpExplicitInst)
150         break;
151       LLVM_FALLTHROUGH;
152     case TSK_Undeclared:
153     case TSK_ImplicitInstantiation:
154       if (DumpRefOnly)
155         NodeDumper.dumpDeclRef(Redecl);
156       else
157         Visit(Redecl);
158       DumpedAny = true;
159       break;
160     case TSK_ExplicitSpecialization:
161       break;
162     }
163   }
164 
165   // Ensure we dump at least one decl for each specialization.
166   if (!DumpedAny)
167     NodeDumper.dumpDeclRef(D);
168 }
169 
170 template <typename TemplateDecl>
171 void ASTDumper::dumpTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst) {
172   dumpTemplateParameters(D->getTemplateParameters());
173 
174   Visit(D->getTemplatedDecl());
175 
176   for (const auto *Child : D->specializations())
177     dumpTemplateDeclSpecialization(Child, DumpExplicitInst,
178                                    !D->isCanonicalDecl());
179 }
180 
181 void ASTDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
182   // FIXME: We don't add a declaration of a function template specialization
183   // to its context when it's explicitly instantiated, so dump explicit
184   // instantiations when we dump the template itself.
185   dumpTemplateDecl(D, true);
186 }
187 
188 void ASTDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) {
189   dumpTemplateDecl(D, false);
190 }
191 
192 void ASTDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) {
193   dumpTemplateDecl(D, false);
194 }
195 
196 //===----------------------------------------------------------------------===//
197 // Type method implementations
198 //===----------------------------------------------------------------------===//
199 
200 void QualType::dump(const char *msg) const {
201   if (msg)
202     llvm::errs() << msg << ": ";
203   dump();
204 }
205 
206 LLVM_DUMP_METHOD void QualType::dump() const { dump(llvm::errs()); }
207 
208 LLVM_DUMP_METHOD void QualType::dump(llvm::raw_ostream &OS) const {
209   ASTDumper Dumper(OS, nullptr, nullptr);
210   Dumper.Visit(*this);
211 }
212 
213 LLVM_DUMP_METHOD void Type::dump() const { dump(llvm::errs()); }
214 
215 LLVM_DUMP_METHOD void Type::dump(llvm::raw_ostream &OS) const {
216   QualType(this, 0).dump(OS);
217 }
218 
219 //===----------------------------------------------------------------------===//
220 // Decl method implementations
221 //===----------------------------------------------------------------------===//
222 
223 LLVM_DUMP_METHOD void Decl::dump() const { dump(llvm::errs()); }
224 
225 LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS, bool Deserialize) const {
226   const ASTContext &Ctx = getASTContext();
227   const SourceManager &SM = Ctx.getSourceManager();
228   ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &SM,
229               SM.getDiagnostics().getShowColors(), Ctx.getPrintingPolicy());
230   P.setDeserialize(Deserialize);
231   P.Visit(this);
232 }
233 
234 LLVM_DUMP_METHOD void Decl::dumpColor() const {
235   const ASTContext &Ctx = getASTContext();
236   ASTDumper P(llvm::errs(), &Ctx.getCommentCommandTraits(),
237               &Ctx.getSourceManager(), /*ShowColors*/ true,
238               Ctx.getPrintingPolicy());
239   P.Visit(this);
240 }
241 
242 LLVM_DUMP_METHOD void DeclContext::dumpLookups() const {
243   dumpLookups(llvm::errs());
244 }
245 
246 LLVM_DUMP_METHOD void DeclContext::dumpLookups(raw_ostream &OS,
247                                                bool DumpDecls,
248                                                bool Deserialize) const {
249   const DeclContext *DC = this;
250   while (!DC->isTranslationUnit())
251     DC = DC->getParent();
252   ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext();
253   const SourceManager &SM = Ctx.getSourceManager();
254   ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &Ctx.getSourceManager(),
255               SM.getDiagnostics().getShowColors(), Ctx.getPrintingPolicy());
256   P.setDeserialize(Deserialize);
257   P.dumpLookups(this, DumpDecls);
258 }
259 
260 //===----------------------------------------------------------------------===//
261 // Stmt method implementations
262 //===----------------------------------------------------------------------===//
263 
264 LLVM_DUMP_METHOD void Stmt::dump(SourceManager &SM) const {
265   dump(llvm::errs(), SM);
266 }
267 
268 LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS, SourceManager &SM) const {
269   ASTDumper P(OS, nullptr, &SM);
270   P.Visit(this);
271 }
272 
273 LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS) const {
274   ASTDumper P(OS, nullptr, nullptr);
275   P.Visit(this);
276 }
277 
278 LLVM_DUMP_METHOD void Stmt::dump() const {
279   ASTDumper P(llvm::errs(), nullptr, nullptr);
280   P.Visit(this);
281 }
282 
283 LLVM_DUMP_METHOD void Stmt::dumpColor() const {
284   ASTDumper P(llvm::errs(), nullptr, nullptr, /*ShowColors*/true);
285   P.Visit(this);
286 }
287 
288 //===----------------------------------------------------------------------===//
289 // Comment method implementations
290 //===----------------------------------------------------------------------===//
291 
292 LLVM_DUMP_METHOD void Comment::dump() const {
293   dump(llvm::errs(), nullptr, nullptr);
294 }
295 
296 LLVM_DUMP_METHOD void Comment::dump(const ASTContext &Context) const {
297   dump(llvm::errs(), &Context.getCommentCommandTraits(),
298        &Context.getSourceManager());
299 }
300 
301 void Comment::dump(raw_ostream &OS, const CommandTraits *Traits,
302                    const SourceManager *SM) const {
303   const FullComment *FC = dyn_cast<FullComment>(this);
304   if (!FC)
305     return;
306   ASTDumper D(OS, Traits, SM);
307   D.Visit(FC, FC);
308 }
309 
310 LLVM_DUMP_METHOD void Comment::dumpColor() const {
311   const FullComment *FC = dyn_cast<FullComment>(this);
312   if (!FC)
313     return;
314   ASTDumper D(llvm::errs(), nullptr, nullptr, /*ShowColors*/true);
315   D.Visit(FC, FC);
316 }
317