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 = cast<SpecializationDecl>(RedeclWithBadType);
94     switch (Redecl->getTemplateSpecializationKind()) {
95     case TSK_ExplicitInstantiationDeclaration:
96     case TSK_ExplicitInstantiationDefinition:
97       if (!DumpExplicitInst)
98         break;
99       LLVM_FALLTHROUGH;
100     case TSK_Undeclared:
101     case TSK_ImplicitInstantiation:
102       if (DumpRefOnly)
103         NodeDumper.dumpDeclRef(Redecl);
104       else
105         Visit(Redecl);
106       DumpedAny = true;
107       break;
108     case TSK_ExplicitSpecialization:
109       break;
110     }
111   }
112 
113   // Ensure we dump at least one decl for each specialization.
114   if (!DumpedAny)
115     NodeDumper.dumpDeclRef(D);
116 }
117 
118 template <typename TemplateDecl>
119 void ASTDumper::dumpTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst) {
120   dumpTemplateParameters(D->getTemplateParameters());
121 
122   Visit(D->getTemplatedDecl());
123 
124   if (GetTraversalKind() == TK_AsIs) {
125     for (const auto *Child : D->specializations())
126       dumpTemplateDeclSpecialization(Child, DumpExplicitInst,
127                                      !D->isCanonicalDecl());
128   }
129 }
130 
131 void ASTDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
132   // FIXME: We don't add a declaration of a function template specialization
133   // to its context when it's explicitly instantiated, so dump explicit
134   // instantiations when we dump the template itself.
135   dumpTemplateDecl(D, true);
136 }
137 
138 void ASTDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) {
139   dumpTemplateDecl(D, false);
140 }
141 
142 void ASTDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) {
143   dumpTemplateDecl(D, false);
144 }
145 
146 //===----------------------------------------------------------------------===//
147 // Type method implementations
148 //===----------------------------------------------------------------------===//
149 
150 void QualType::dump(const char *msg) const {
151   if (msg)
152     llvm::errs() << msg << ": ";
153   dump();
154 }
155 
156 LLVM_DUMP_METHOD void QualType::dump() const {
157   ASTDumper Dumper(llvm::errs(), /*ShowColors=*/false);
158   Dumper.Visit(*this);
159 }
160 
161 LLVM_DUMP_METHOD void QualType::dump(llvm::raw_ostream &OS,
162                                      const ASTContext &Context) const {
163   ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors());
164   Dumper.Visit(*this);
165 }
166 
167 LLVM_DUMP_METHOD void Type::dump() const { QualType(this, 0).dump(); }
168 
169 LLVM_DUMP_METHOD void Type::dump(llvm::raw_ostream &OS,
170                                  const ASTContext &Context) const {
171   QualType(this, 0).dump(OS, Context);
172 }
173 
174 //===----------------------------------------------------------------------===//
175 // Decl method implementations
176 //===----------------------------------------------------------------------===//
177 
178 LLVM_DUMP_METHOD void Decl::dump() const { dump(llvm::errs()); }
179 
180 LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS, bool Deserialize,
181                                  ASTDumpOutputFormat Format) const {
182   ASTContext &Ctx = getASTContext();
183   const SourceManager &SM = Ctx.getSourceManager();
184 
185   if (ADOF_JSON == Format) {
186     JSONDumper P(OS, SM, Ctx, Ctx.getPrintingPolicy(),
187                  &Ctx.getCommentCommandTraits());
188     (void)Deserialize; // FIXME?
189     P.Visit(this);
190   } else {
191     ASTDumper P(OS, Ctx, Ctx.getDiagnostics().getShowColors());
192     P.setDeserialize(Deserialize);
193     P.Visit(this);
194   }
195 }
196 
197 LLVM_DUMP_METHOD void Decl::dumpColor() const {
198   const ASTContext &Ctx = getASTContext();
199   ASTDumper P(llvm::errs(), Ctx, /*ShowColors=*/true);
200   P.Visit(this);
201 }
202 
203 LLVM_DUMP_METHOD void DeclContext::dumpLookups() const {
204   dumpLookups(llvm::errs());
205 }
206 
207 LLVM_DUMP_METHOD void DeclContext::dumpLookups(raw_ostream &OS,
208                                                bool DumpDecls,
209                                                bool Deserialize) const {
210   const DeclContext *DC = this;
211   while (!DC->isTranslationUnit())
212     DC = DC->getParent();
213   const ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext();
214   ASTDumper P(OS, Ctx, Ctx.getDiagnostics().getShowColors());
215   P.setDeserialize(Deserialize);
216   P.dumpLookups(this, DumpDecls);
217 }
218 
219 //===----------------------------------------------------------------------===//
220 // Stmt method implementations
221 //===----------------------------------------------------------------------===//
222 
223 LLVM_DUMP_METHOD void Stmt::dump() const {
224   ASTDumper P(llvm::errs(), /*ShowColors=*/false);
225   P.Visit(this);
226 }
227 
228 LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS,
229                                  const ASTContext &Context) const {
230   ASTDumper P(OS, Context, Context.getDiagnostics().getShowColors());
231   P.Visit(this);
232 }
233 
234 LLVM_DUMP_METHOD void Stmt::dumpColor() const {
235   ASTDumper P(llvm::errs(), /*ShowColors=*/true);
236   P.Visit(this);
237 }
238 
239 //===----------------------------------------------------------------------===//
240 // Comment method implementations
241 //===----------------------------------------------------------------------===//
242 
243 LLVM_DUMP_METHOD void Comment::dump() const {
244   const auto *FC = dyn_cast<FullComment>(this);
245   if (!FC)
246     return;
247   ASTDumper Dumper(llvm::errs(), /*ShowColors=*/false);
248   Dumper.Visit(FC, FC);
249 }
250 
251 LLVM_DUMP_METHOD void Comment::dump(raw_ostream &OS,
252                                     const ASTContext &Context) const {
253   const auto *FC = dyn_cast<FullComment>(this);
254   if (!FC)
255     return;
256   ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors());
257   Dumper.Visit(FC, FC);
258 }
259 
260 LLVM_DUMP_METHOD void Comment::dumpColor() const {
261   const auto *FC = dyn_cast<FullComment>(this);
262   if (!FC)
263     return;
264   ASTDumper Dumper(llvm::errs(), /*ShowColors=*/true);
265   Dumper.Visit(FC, FC);
266 }
267 
268 //===----------------------------------------------------------------------===//
269 // APValue method implementations
270 //===----------------------------------------------------------------------===//
271 
272 LLVM_DUMP_METHOD void APValue::dump() const {
273   ASTDumper Dumper(llvm::errs(), /*ShowColors=*/false);
274   Dumper.Visit(*this, /*Ty=*/QualType());
275 }
276 
277 LLVM_DUMP_METHOD void APValue::dump(raw_ostream &OS,
278                                     const ASTContext &Context) const {
279   ASTDumper Dumper(llvm::errs(), Context,
280                    Context.getDiagnostics().getShowColors());
281   Dumper.Visit(*this, /*Ty=*/Context.getPointerType(Context.CharTy));
282 }
283