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