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