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   if (GetTraversalKind() == TK_AsIs) {
133     for (const auto *Child : D->specializations())
134       dumpTemplateDeclSpecialization(Child, DumpExplicitInst,
135                                      !D->isCanonicalDecl());
136   }
137 }
138 
139 void ASTDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
140   // FIXME: We don't add a declaration of a function template specialization
141   // to its context when it's explicitly instantiated, so dump explicit
142   // instantiations when we dump the template itself.
143   dumpTemplateDecl(D, true);
144 }
145 
146 void ASTDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) {
147   dumpTemplateDecl(D, false);
148 }
149 
150 void ASTDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) {
151   dumpTemplateDecl(D, false);
152 }
153 
154 //===----------------------------------------------------------------------===//
155 // Type method implementations
156 //===----------------------------------------------------------------------===//
157 
158 void QualType::dump(const char *msg) const {
159   if (msg)
160     llvm::errs() << msg << ": ";
161   dump();
162 }
163 
164 LLVM_DUMP_METHOD void QualType::dump() const {
165   ASTDumper Dumper(llvm::errs(), /*ShowColors=*/false);
166   Dumper.Visit(*this);
167 }
168 
169 LLVM_DUMP_METHOD void QualType::dump(llvm::raw_ostream &OS,
170                                      const ASTContext &Context) const {
171   ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors());
172   Dumper.Visit(*this);
173 }
174 
175 LLVM_DUMP_METHOD void Type::dump() const { QualType(this, 0).dump(); }
176 
177 LLVM_DUMP_METHOD void Type::dump(llvm::raw_ostream &OS,
178                                  const ASTContext &Context) const {
179   QualType(this, 0).dump(OS, Context);
180 }
181 
182 //===----------------------------------------------------------------------===//
183 // Decl method implementations
184 //===----------------------------------------------------------------------===//
185 
186 LLVM_DUMP_METHOD void Decl::dump() const { dump(llvm::errs()); }
187 
188 LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS, bool Deserialize,
189                                  ASTDumpOutputFormat Format) const {
190   ASTContext &Ctx = getASTContext();
191   const SourceManager &SM = Ctx.getSourceManager();
192 
193   if (ADOF_JSON == Format) {
194     JSONDumper P(OS, SM, Ctx, Ctx.getPrintingPolicy(),
195                  &Ctx.getCommentCommandTraits());
196     (void)Deserialize; // FIXME?
197     P.Visit(this);
198   } else {
199     ASTDumper P(OS, Ctx, Ctx.getDiagnostics().getShowColors());
200     P.setDeserialize(Deserialize);
201     P.Visit(this);
202   }
203 }
204 
205 LLVM_DUMP_METHOD void Decl::dumpColor() const {
206   const ASTContext &Ctx = getASTContext();
207   ASTDumper P(llvm::errs(), Ctx, /*ShowColors=*/true);
208   P.Visit(this);
209 }
210 
211 LLVM_DUMP_METHOD void DeclContext::dumpLookups() const {
212   dumpLookups(llvm::errs());
213 }
214 
215 LLVM_DUMP_METHOD void DeclContext::dumpLookups(raw_ostream &OS,
216                                                bool DumpDecls,
217                                                bool Deserialize) const {
218   const DeclContext *DC = this;
219   while (!DC->isTranslationUnit())
220     DC = DC->getParent();
221   const ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext();
222   ASTDumper P(OS, Ctx, Ctx.getDiagnostics().getShowColors());
223   P.setDeserialize(Deserialize);
224   P.dumpLookups(this, DumpDecls);
225 }
226 
227 //===----------------------------------------------------------------------===//
228 // Stmt method implementations
229 //===----------------------------------------------------------------------===//
230 
231 LLVM_DUMP_METHOD void Stmt::dump() const {
232   ASTDumper P(llvm::errs(), /*ShowColors=*/false);
233   P.Visit(this);
234 }
235 
236 LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS,
237                                  const ASTContext &Context) const {
238   ASTDumper P(OS, Context, Context.getDiagnostics().getShowColors());
239   P.Visit(this);
240 }
241 
242 LLVM_DUMP_METHOD void Stmt::dumpColor() const {
243   ASTDumper P(llvm::errs(), /*ShowColors=*/true);
244   P.Visit(this);
245 }
246 
247 //===----------------------------------------------------------------------===//
248 // Comment method implementations
249 //===----------------------------------------------------------------------===//
250 
251 LLVM_DUMP_METHOD void Comment::dump() const {
252   const auto *FC = dyn_cast<FullComment>(this);
253   if (!FC)
254     return;
255   ASTDumper Dumper(llvm::errs(), /*ShowColors=*/false);
256   Dumper.Visit(FC, FC);
257 }
258 
259 LLVM_DUMP_METHOD void Comment::dump(raw_ostream &OS,
260                                     const ASTContext &Context) const {
261   const auto *FC = dyn_cast<FullComment>(this);
262   if (!FC)
263     return;
264   ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors());
265   Dumper.Visit(FC, FC);
266 }
267 
268 LLVM_DUMP_METHOD void Comment::dumpColor() const {
269   const auto *FC = dyn_cast<FullComment>(this);
270   if (!FC)
271     return;
272   ASTDumper Dumper(llvm::errs(), /*ShowColors=*/true);
273   Dumper.Visit(FC, FC);
274 }
275 
276 //===----------------------------------------------------------------------===//
277 // APValue method implementations
278 //===----------------------------------------------------------------------===//
279 
280 LLVM_DUMP_METHOD void APValue::dump() const {
281   ASTDumper Dumper(llvm::errs(), /*ShowColors=*/false);
282   Dumper.Visit(*this, /*Ty=*/QualType());
283 }
284 
285 LLVM_DUMP_METHOD void APValue::dump(raw_ostream &OS,
286                                     const ASTContext &Context) const {
287   ASTDumper Dumper(llvm::errs(), Context,
288                    Context.getDiagnostics().getShowColors());
289   Dumper.Visit(*this, /*Ty=*/Context.getPointerType(Context.CharTy));
290 }
291