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