xref: /freebsd/contrib/llvm-project/clang/lib/Frontend/ASTConsumers.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
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"
25  using namespace clang;
26  
27  //===----------------------------------------------------------------------===//
28  /// ASTPrinter - Pretty-printer and dumper of ASTs
29  
30  namespace {
31    class ASTPrinter : public ASTConsumer,
32                       public RecursiveASTVisitor<ASTPrinter> {
33      typedef RecursiveASTVisitor<ASTPrinter> base;
34  
35    public:
36      enum Kind { DumpFull, Dump, Print, None };
ASTPrinter(std::unique_ptr<raw_ostream> Out,Kind K,ASTDumpOutputFormat Format,StringRef FilterString,bool DumpLookups=false,bool DumpDeclTypes=false)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  
HandleTranslationUnit(ASTContext & Context)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  
shouldWalkTypesOfTypeLocs() const53      bool shouldWalkTypesOfTypeLocs() const { return false; }
54  
TraverseDecl(Decl * D)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:
getName(Decl * D)76      std::string getName(Decl *D) {
77        if (isa<NamedDecl>(D))
78          return cast<NamedDecl>(D)->getQualifiedNameAsString();
79        return "";
80      }
filterMatches(Decl * D)81      bool filterMatches(Decl *D) {
82        return getName(D).find(FilterString) != std::string::npos;
83      }
print(Decl * D)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:
ASTDeclNodeLister(raw_ostream * Out=nullptr)139      ASTDeclNodeLister(raw_ostream *Out = nullptr)
140          : Out(Out ? *Out : llvm::outs()) {}
141  
HandleTranslationUnit(ASTContext & Context)142      void HandleTranslationUnit(ASTContext &Context) override {
143        TraverseDecl(Context.getTranslationUnitDecl());
144      }
145  
shouldWalkTypesOfTypeLocs() const146      bool shouldWalkTypesOfTypeLocs() const { return false; }
147  
VisitNamedDecl(NamedDecl * D)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  
159  std::unique_ptr<ASTConsumer>
CreateASTPrinter(std::unique_ptr<raw_ostream> Out,StringRef FilterString)160  clang::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  
166  std::unique_ptr<ASTConsumer>
CreateASTDumper(std::unique_ptr<raw_ostream> Out,StringRef FilterString,bool DumpDecls,bool Deserialize,bool DumpLookups,bool DumpDeclTypes,ASTDumpOutputFormat Format)167  clang::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  
CreateASTDeclNodeLister()178  std::unique_ptr<ASTConsumer> clang::CreateASTDeclNodeLister() {
179    return std::make_unique<ASTDeclNodeLister>(nullptr);
180  }
181  
182  //===----------------------------------------------------------------------===//
183  /// ASTViewer - AST Visualization
184  
185  namespace {
186  class ASTViewer : public ASTConsumer {
187    ASTContext *Context = nullptr;
188  
189  public:
Initialize(ASTContext & Context)190    void Initialize(ASTContext &Context) override { this->Context = &Context; }
191  
HandleTopLevelDecl(DeclGroupRef D)192    bool HandleTopLevelDecl(DeclGroupRef D) override {
193      for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
194        HandleTopLevelSingleDecl(*I);
195      return true;
196    }
197  
198    void HandleTopLevelSingleDecl(Decl *D);
199  };
200  }
201  
HandleTopLevelSingleDecl(Decl * D)202  void ASTViewer::HandleTopLevelSingleDecl(Decl *D) {
203    if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
204      D->print(llvm::errs());
205  
206      if (Stmt *Body = D->getBody()) {
207        llvm::errs() << '\n';
208        Body->viewAST();
209        llvm::errs() << '\n';
210      }
211    }
212  }
213  
CreateASTViewer()214  std::unique_ptr<ASTConsumer> clang::CreateASTViewer() {
215    return std::make_unique<ASTViewer>();
216  }
217