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
23using namespace clang;
24using namespace clang::comments;
25
26void ASTDumper::dumpInvalidDeclContext(const DeclContext *DC) {
27  NodeDumper.AddChild([=] {
28    if (!DC) {
29      ColorScope Color(OS, ShowColors, NullColor);
30      OS << "<<<NULL>>>";
31      return;
32    }
33    // An invalid DeclContext is one for which a dyn_cast() from a DeclContext
34    // pointer to a Decl pointer would fail an assertion or otherwise fall prey
35    // to undefined behavior as a result of an invalid associated DeclKind.
36    // Such invalidity is not supposed to happen of course, but, when it does,
37    // the information provided below is intended to provide some hints about
38    // what might have gone awry.
39    {
40      ColorScope Color(OS, ShowColors, DeclKindNameColor);
41      OS << "DeclContext";
42    }
43    NodeDumper.dumpPointer(DC);
44    OS << " <";
45    {
46      ColorScope Color(OS, ShowColors, DeclNameColor);
47      OS << "unrecognized Decl kind " << (unsigned)DC->getDeclKind();
48    }
49    OS << ">";
50  });
51}
52
53void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) {
54  NodeDumper.AddChild([=] {
55    OS << "StoredDeclsMap ";
56    NodeDumper.dumpBareDeclRef(cast<Decl>(DC));
57
58    const DeclContext *Primary = DC->getPrimaryContext();
59    if (Primary != DC) {
60      OS << " primary";
61      NodeDumper.dumpPointer(cast<Decl>(Primary));
62    }
63
64    bool HasUndeserializedLookups = Primary->hasExternalVisibleStorage();
65
66    auto Range = getDeserialize()
67                     ? Primary->lookups()
68                     : Primary->noload_lookups(/*PreserveInternalState=*/true);
69    for (auto I = Range.begin(), E = Range.end(); I != E; ++I) {
70      DeclarationName Name = I.getLookupName();
71      DeclContextLookupResult R = *I;
72
73      NodeDumper.AddChild([=] {
74        OS << "DeclarationName ";
75        {
76          ColorScope Color(OS, ShowColors, DeclNameColor);
77          OS << '\'' << Name << '\'';
78        }
79
80        for (DeclContextLookupResult::iterator RI = R.begin(), RE = R.end();
81             RI != RE; ++RI) {
82          NodeDumper.AddChild([=] {
83            NodeDumper.dumpBareDeclRef(*RI);
84
85            if (!(*RI)->isUnconditionallyVisible())
86              OS << " hidden";
87
88            // If requested, dump the redecl chain for this lookup.
89            if (DumpDecls) {
90              // Dump earliest decl first.
91              std::function<void(Decl *)> DumpWithPrev = [&](Decl *D) {
92                if (Decl *Prev = D->getPreviousDecl())
93                  DumpWithPrev(Prev);
94                Visit(D);
95              };
96              DumpWithPrev(*RI);
97            }
98          });
99        }
100      });
101    }
102
103    if (HasUndeserializedLookups) {
104      NodeDumper.AddChild([=] {
105        ColorScope Color(OS, ShowColors, UndeserializedColor);
106        OS << "<undeserialized lookups>";
107      });
108    }
109  });
110}
111
112template <typename SpecializationDecl>
113void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl *D,
114                                               bool DumpExplicitInst,
115                                               bool DumpRefOnly) {
116  bool DumpedAny = false;
117  for (const auto *RedeclWithBadType : D->redecls()) {
118    // FIXME: The redecls() range sometimes has elements of a less-specific
119    // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives
120    // us TagDecls, and should give CXXRecordDecls).
121    auto *Redecl = cast<SpecializationDecl>(RedeclWithBadType);
122    switch (Redecl->getTemplateSpecializationKind()) {
123    case TSK_ExplicitInstantiationDeclaration:
124    case TSK_ExplicitInstantiationDefinition:
125      if (!DumpExplicitInst)
126        break;
127      [[fallthrough]];
128    case TSK_Undeclared:
129    case TSK_ImplicitInstantiation:
130      if (DumpRefOnly)
131        NodeDumper.dumpDeclRef(Redecl);
132      else
133        Visit(Redecl);
134      DumpedAny = true;
135      break;
136    case TSK_ExplicitSpecialization:
137      break;
138    }
139  }
140
141  // Ensure we dump at least one decl for each specialization.
142  if (!DumpedAny)
143    NodeDumper.dumpDeclRef(D);
144}
145
146template <typename TemplateDecl>
147void ASTDumper::dumpTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst) {
148  dumpTemplateParameters(D->getTemplateParameters());
149
150  Visit(D->getTemplatedDecl());
151
152  if (GetTraversalKind() == TK_AsIs) {
153    for (const auto *Child : D->specializations())
154      dumpTemplateDeclSpecialization(Child, DumpExplicitInst,
155                                     !D->isCanonicalDecl());
156  }
157}
158
159void ASTDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
160  // FIXME: We don't add a declaration of a function template specialization
161  // to its context when it's explicitly instantiated, so dump explicit
162  // instantiations when we dump the template itself.
163  dumpTemplateDecl(D, true);
164}
165
166void ASTDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) {
167  dumpTemplateDecl(D, false);
168}
169
170void ASTDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) {
171  dumpTemplateDecl(D, false);
172}
173
174//===----------------------------------------------------------------------===//
175// Type method implementations
176//===----------------------------------------------------------------------===//
177
178void QualType::dump(const char *msg) const {
179  if (msg)
180    llvm::errs() << msg << ": ";
181  dump();
182}
183
184LLVM_DUMP_METHOD void QualType::dump() const {
185  ASTDumper Dumper(llvm::errs(), /*ShowColors=*/false);
186  Dumper.Visit(*this);
187}
188
189LLVM_DUMP_METHOD void QualType::dump(llvm::raw_ostream &OS,
190                                     const ASTContext &Context) const {
191  ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors());
192  Dumper.Visit(*this);
193}
194
195LLVM_DUMP_METHOD void Type::dump() const { QualType(this, 0).dump(); }
196
197LLVM_DUMP_METHOD void Type::dump(llvm::raw_ostream &OS,
198                                 const ASTContext &Context) const {
199  QualType(this, 0).dump(OS, Context);
200}
201
202//===----------------------------------------------------------------------===//
203// Decl method implementations
204//===----------------------------------------------------------------------===//
205
206LLVM_DUMP_METHOD void Decl::dump() const { dump(llvm::errs()); }
207
208LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS, bool Deserialize,
209                                 ASTDumpOutputFormat Format) const {
210  ASTContext &Ctx = getASTContext();
211  const SourceManager &SM = Ctx.getSourceManager();
212
213  if (ADOF_JSON == Format) {
214    JSONDumper P(OS, SM, Ctx, Ctx.getPrintingPolicy(),
215                 &Ctx.getCommentCommandTraits());
216    (void)Deserialize; // FIXME?
217    P.Visit(this);
218  } else {
219    ASTDumper P(OS, Ctx, Ctx.getDiagnostics().getShowColors());
220    P.setDeserialize(Deserialize);
221    P.Visit(this);
222  }
223}
224
225LLVM_DUMP_METHOD void Decl::dumpColor() const {
226  const ASTContext &Ctx = getASTContext();
227  ASTDumper P(llvm::errs(), Ctx, /*ShowColors=*/true);
228  P.Visit(this);
229}
230
231LLVM_DUMP_METHOD void DeclContext::dumpAsDecl() const {
232  dumpAsDecl(nullptr);
233}
234
235LLVM_DUMP_METHOD void DeclContext::dumpAsDecl(const ASTContext *Ctx) const {
236  // By design, DeclContext is required to be a base class of some class that
237  // derives from Decl. Thus, it should always be possible to dyn_cast() from
238  // a DeclContext pointer to a Decl pointer and Decl::castFromDeclContext()
239  // asserts that to be the case. Since this function is intended for use in a
240  // debugger, it performs an additional check in order to prevent a failed
241  // cast and assertion. If that check fails, then the (invalid) DeclContext
242  // is dumped with an indication of its invalidity.
243  if (hasValidDeclKind()) {
244    const auto *D = cast<Decl>(this);
245    D->dump();
246  } else {
247    // If an ASTContext is not available, a less capable ASTDumper is
248    // constructed for which color diagnostics are, regrettably, disabled.
249    ASTDumper P = Ctx ? ASTDumper(llvm::errs(), *Ctx,
250                                  Ctx->getDiagnostics().getShowColors())
251                      : ASTDumper(llvm::errs(), /*ShowColors*/ false);
252    P.dumpInvalidDeclContext(this);
253  }
254}
255
256LLVM_DUMP_METHOD void DeclContext::dumpLookups() const {
257  dumpLookups(llvm::errs());
258}
259
260LLVM_DUMP_METHOD void DeclContext::dumpLookups(raw_ostream &OS,
261                                               bool DumpDecls,
262                                               bool Deserialize) const {
263  const DeclContext *DC = this;
264  while (!DC->isTranslationUnit())
265    DC = DC->getParent();
266  const ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext();
267  ASTDumper P(OS, Ctx, Ctx.getDiagnostics().getShowColors());
268  P.setDeserialize(Deserialize);
269  P.dumpLookups(this, DumpDecls);
270}
271
272//===----------------------------------------------------------------------===//
273// Stmt method implementations
274//===----------------------------------------------------------------------===//
275
276LLVM_DUMP_METHOD void Stmt::dump() const {
277  ASTDumper P(llvm::errs(), /*ShowColors=*/false);
278  P.Visit(this);
279}
280
281LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS,
282                                 const ASTContext &Context) const {
283  ASTDumper P(OS, Context, Context.getDiagnostics().getShowColors());
284  P.Visit(this);
285}
286
287LLVM_DUMP_METHOD void Stmt::dumpColor() const {
288  ASTDumper P(llvm::errs(), /*ShowColors=*/true);
289  P.Visit(this);
290}
291
292//===----------------------------------------------------------------------===//
293// Comment method implementations
294//===----------------------------------------------------------------------===//
295
296LLVM_DUMP_METHOD void Comment::dump() const {
297  const auto *FC = dyn_cast<FullComment>(this);
298  if (!FC)
299    return;
300  ASTDumper Dumper(llvm::errs(), /*ShowColors=*/false);
301  Dumper.Visit(FC, FC);
302}
303
304LLVM_DUMP_METHOD void Comment::dump(raw_ostream &OS,
305                                    const ASTContext &Context) const {
306  const auto *FC = dyn_cast<FullComment>(this);
307  if (!FC)
308    return;
309  ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors());
310  Dumper.Visit(FC, FC);
311}
312
313LLVM_DUMP_METHOD void Comment::dumpColor() const {
314  const auto *FC = dyn_cast<FullComment>(this);
315  if (!FC)
316    return;
317  ASTDumper Dumper(llvm::errs(), /*ShowColors=*/true);
318  Dumper.Visit(FC, FC);
319}
320
321//===----------------------------------------------------------------------===//
322// APValue method implementations
323//===----------------------------------------------------------------------===//
324
325LLVM_DUMP_METHOD void APValue::dump() const {
326  ASTDumper Dumper(llvm::errs(), /*ShowColors=*/false);
327  Dumper.Visit(*this, /*Ty=*/QualType());
328}
329
330LLVM_DUMP_METHOD void APValue::dump(raw_ostream &OS,
331                                    const ASTContext &Context) const {
332  ASTDumper Dumper(llvm::errs(), Context,
333                   Context.getDiagnostics().getShowColors());
334  Dumper.Visit(*this, /*Ty=*/Context.getPointerType(Context.CharTy));
335}
336