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