1//===--- ASTConsumers.cpp - ASTConsumer implementations -------------------===//
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// AST Consumer Implementations.
10//
11//===----------------------------------------------------------------------===//
12
13#include "clang/Frontend/ASTConsumers.h"
14#include "clang/AST/AST.h"
15#include "clang/AST/ASTConsumer.h"
16#include "clang/AST/ASTContext.h"
17#include "clang/AST/PrettyPrinter.h"
18#include "clang/AST/RecordLayout.h"
19#include "clang/AST/RecursiveASTVisitor.h"
20#include "clang/Basic/Diagnostic.h"
21#include "clang/Basic/SourceManager.h"
22#include "llvm/Support/Path.h"
23#include "llvm/Support/Timer.h"
24#include "llvm/Support/raw_ostream.h"
25using namespace clang;
26
27//===----------------------------------------------------------------------===//
28/// ASTPrinter - Pretty-printer and dumper of ASTs
29
30namespace {
31  class ASTPrinter : public ASTConsumer,
32                     public RecursiveASTVisitor<ASTPrinter> {
33    typedef RecursiveASTVisitor<ASTPrinter> base;
34
35  public:
36    enum Kind { DumpFull, Dump, Print, None };
37    ASTPrinter(std::unique_ptr<raw_ostream> Out, Kind K,
38               ASTDumpOutputFormat Format, StringRef FilterString,
39               bool DumpLookups = false, bool DumpDeclTypes = false)
40        : Out(Out ? *Out : llvm::outs()), OwnedOut(std::move(Out)),
41          OutputKind(K), OutputFormat(Format), FilterString(FilterString),
42          DumpLookups(DumpLookups), DumpDeclTypes(DumpDeclTypes) {}
43
44    void HandleTranslationUnit(ASTContext &Context) override {
45      TranslationUnitDecl *D = Context.getTranslationUnitDecl();
46
47      if (FilterString.empty())
48        return print(D);
49
50      TraverseDecl(D);
51    }
52
53    bool shouldWalkTypesOfTypeLocs() const { return false; }
54
55    bool TraverseDecl(Decl *D) {
56      if (D && filterMatches(D)) {
57        bool ShowColors = Out.has_colors();
58        if (ShowColors)
59          Out.changeColor(raw_ostream::BLUE);
60
61        if (OutputFormat == ADOF_Default)
62          Out << (OutputKind != Print ? "Dumping " : "Printing ") << getName(D)
63              << ":\n";
64
65        if (ShowColors)
66          Out.resetColor();
67        print(D);
68        Out << "\n";
69        // Don't traverse child nodes to avoid output duplication.
70        return true;
71      }
72      return base::TraverseDecl(D);
73    }
74
75  private:
76    std::string getName(Decl *D) {
77      if (isa<NamedDecl>(D))
78        return cast<NamedDecl>(D)->getQualifiedNameAsString();
79      return "";
80    }
81    bool filterMatches(Decl *D) {
82      return getName(D).find(FilterString) != std::string::npos;
83    }
84    void print(Decl *D) {
85      if (DumpLookups) {
86        if (DeclContext *DC = dyn_cast<DeclContext>(D)) {
87          if (DC == DC->getPrimaryContext())
88            DC->dumpLookups(Out, OutputKind != None, OutputKind == DumpFull);
89          else
90            Out << "Lookup map is in primary DeclContext "
91                << DC->getPrimaryContext() << "\n";
92        } else
93          Out << "Not a DeclContext\n";
94      } else if (OutputKind == Print) {
95        PrintingPolicy Policy(D->getASTContext().getLangOpts());
96        D->print(Out, Policy, /*Indentation=*/0, /*PrintInstantiation=*/true);
97      } else if (OutputKind != None) {
98        D->dump(Out, OutputKind == DumpFull, OutputFormat);
99      }
100
101      if (DumpDeclTypes) {
102        Decl *InnerD = D;
103        if (auto *TD = dyn_cast<TemplateDecl>(D))
104          InnerD = TD->getTemplatedDecl();
105
106        // FIXME: Support OutputFormat in type dumping.
107        // FIXME: Support combining -ast-dump-decl-types with -ast-dump-lookups.
108        if (auto *VD = dyn_cast<ValueDecl>(InnerD))
109          VD->getType().dump(Out, VD->getASTContext());
110        if (auto *TD = dyn_cast<TypeDecl>(InnerD))
111          TD->getTypeForDecl()->dump(Out, TD->getASTContext());
112      }
113    }
114
115    raw_ostream &Out;
116    std::unique_ptr<raw_ostream> OwnedOut;
117
118    /// How to output individual declarations.
119    Kind OutputKind;
120
121    /// What format should the output take?
122    ASTDumpOutputFormat OutputFormat;
123
124    /// Which declarations or DeclContexts to display.
125    std::string FilterString;
126
127    /// Whether the primary output is lookup results or declarations. Individual
128    /// results will be output with a format determined by OutputKind. This is
129    /// incompatible with OutputKind == Print.
130    bool DumpLookups;
131
132    /// Whether to dump the type for each declaration dumped.
133    bool DumpDeclTypes;
134  };
135
136  class ASTDeclNodeLister : public ASTConsumer,
137                     public RecursiveASTVisitor<ASTDeclNodeLister> {
138  public:
139    ASTDeclNodeLister(raw_ostream *Out = nullptr)
140        : Out(Out ? *Out : llvm::outs()) {}
141
142    void HandleTranslationUnit(ASTContext &Context) override {
143      TraverseDecl(Context.getTranslationUnitDecl());
144    }
145
146    bool shouldWalkTypesOfTypeLocs() const { return false; }
147
148    bool VisitNamedDecl(NamedDecl *D) {
149      D->printQualifiedName(Out);
150      Out << '\n';
151      return true;
152    }
153
154  private:
155    raw_ostream &Out;
156  };
157} // end anonymous namespace
158
159std::unique_ptr<ASTConsumer>
160clang::CreateASTPrinter(std::unique_ptr<raw_ostream> Out,
161                        StringRef FilterString) {
162  return std::make_unique<ASTPrinter>(std::move(Out), ASTPrinter::Print,
163                                       ADOF_Default, FilterString);
164}
165
166std::unique_ptr<ASTConsumer>
167clang::CreateASTDumper(std::unique_ptr<raw_ostream> Out, StringRef FilterString,
168                       bool DumpDecls, bool Deserialize, bool DumpLookups,
169                       bool DumpDeclTypes, ASTDumpOutputFormat Format) {
170  assert((DumpDecls || Deserialize || DumpLookups) && "nothing to dump");
171  return std::make_unique<ASTPrinter>(
172      std::move(Out),
173      Deserialize ? ASTPrinter::DumpFull
174                  : DumpDecls ? ASTPrinter::Dump : ASTPrinter::None,
175      Format, FilterString, DumpLookups, DumpDeclTypes);
176}
177
178std::unique_ptr<ASTConsumer> clang::CreateASTDeclNodeLister() {
179  return std::make_unique<ASTDeclNodeLister>(nullptr);
180}
181
182//===----------------------------------------------------------------------===//
183/// ASTViewer - AST Visualization
184
185namespace {
186  class ASTViewer : public ASTConsumer {
187    ASTContext *Context;
188  public:
189    void Initialize(ASTContext &Context) override {
190      this->Context = &Context;
191    }
192
193    bool HandleTopLevelDecl(DeclGroupRef D) override {
194      for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
195        HandleTopLevelSingleDecl(*I);
196      return true;
197    }
198
199    void HandleTopLevelSingleDecl(Decl *D);
200  };
201}
202
203void ASTViewer::HandleTopLevelSingleDecl(Decl *D) {
204  if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
205    D->print(llvm::errs());
206
207    if (Stmt *Body = D->getBody()) {
208      llvm::errs() << '\n';
209      Body->viewAST();
210      llvm::errs() << '\n';
211    }
212  }
213}
214
215std::unique_ptr<ASTConsumer> clang::CreateASTViewer() {
216  return std::make_unique<ASTViewer>();
217}
218