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 };
ASTPrinter(std::unique_ptr<raw_ostream> Out,Kind K,ASTDumpOutputFormat Format,StringRef FilterString,bool DumpLookups=false,bool DumpDeclTypes=false)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
ASTPrinter(raw_ostream & Out,Kind K,ASTDumpOutputFormat Format,StringRef FilterString,bool DumpLookups=false,bool DumpDeclTypes=false)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
HandleTranslationUnit(ASTContext & Context)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
shouldWalkTypesOfTypeLocs() const57 bool shouldWalkTypesOfTypeLocs() const { return false; }
58
TraverseDecl(Decl * D)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:
getName(Decl * D)80 std::string getName(Decl *D) {
81 if (isa<NamedDecl>(D))
82 return cast<NamedDecl>(D)->getQualifiedNameAsString();
83 return "";
84 }
filterMatches(Decl * D)85 bool filterMatches(Decl *D) {
86 return getName(D).find(FilterString) != std::string::npos;
87 }
print(Decl * D)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:
ASTDeclNodeLister(raw_ostream * Out=nullptr)144 ASTDeclNodeLister(raw_ostream *Out = nullptr)
145 : Out(Out ? *Out : llvm::outs()) {}
146
HandleTranslationUnit(ASTContext & Context)147 void HandleTranslationUnit(ASTContext &Context) override {
148 TraverseDecl(Context.getTranslationUnitDecl());
149 }
150
shouldWalkTypesOfTypeLocs() const151 bool shouldWalkTypesOfTypeLocs() const { return false; }
152
VisitNamedDecl(NamedDecl * D)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>
CreateASTPrinter(std::unique_ptr<raw_ostream> Out,StringRef FilterString)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>
CreateASTDumper(std::unique_ptr<raw_ostream> Out,StringRef FilterString,bool DumpDecls,bool Deserialize,bool DumpLookups,bool DumpDeclTypes,ASTDumpOutputFormat Format)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>
CreateASTDumper(raw_ostream & Out,StringRef FilterString,bool DumpDecls,bool Deserialize,bool DumpLookups,bool DumpDeclTypes,ASTDumpOutputFormat Format)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
CreateASTDeclNodeLister()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:
Initialize(ASTContext & Context)208 void Initialize(ASTContext &Context) override { this->Context = &Context; }
209
HandleTopLevelDecl(DeclGroupRef D)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
HandleTopLevelSingleDecl(Decl * D)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
CreateASTViewer()232 std::unique_ptr<ASTConsumer> clang::CreateASTViewer() {
233 return std::make_unique<ASTViewer>();
234 }
235