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"
25using namespace clang;
26
27//===----------------------------------------------------------------------===//
28/// ASTPrinter - Pretty-printer and dumper of ASTs
29
30namespace {
31 class ASTPrinter : public ASTConsumer,
32 public RecursiveASTVisitor<ASTPrinter> {
33 typedef RecursiveASTVisitor<ASTPrinter> base;
34
35 public:
36 enum Kind { DumpFull, Dump, Print, None };
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
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
53 bool shouldWalkTypesOfTypeLocs() const { return false; }
54
55 bool TraverseDecl(Decl *D) {
56 if (D && filterMatches(D)) {
57 bool ShowColors = Out.has_colors();
58 if (ShowColors)
59 Out.changeColor(Color: 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:
76 std::string getName(Decl *D) {
77 if (isa<NamedDecl>(Val: D))
78 return cast<NamedDecl>(Val: D)->getQualifiedNameAsString();
79 return "";
80 }
81 bool filterMatches(Decl *D) {
82 return getName(D).find(str: FilterString) != std::string::npos;
83 }
84 void print(Decl *D) {
85 if (DumpLookups) {
86 if (DeclContext *DC = dyn_cast<DeclContext>(Val: D)) {
87 if (DC == DC->getPrimaryContext())
88 DC->dumpLookups(OS&: Out, DumpDecls: OutputKind != None, Deserialize: 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, Deserialize: OutputKind == DumpFull, OutputFormat);
99 }
100
101 if (DumpDeclTypes) {
102 Decl *InnerD = D;
103 if (auto *TD = dyn_cast<TemplateDecl>(Val: 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>(Val: InnerD))
109 VD->getType().dump(OS&: Out, Context: VD->getASTContext());
110 if (auto *TD = dyn_cast<TypeDecl>(Val: InnerD))
111 TD->getTypeForDecl()->dump(OS&: Out, Context: 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:
139 ASTDeclNodeLister(raw_ostream *Out = nullptr)
140 : Out(Out ? *Out : llvm::outs()) {}
141
142 void HandleTranslationUnit(ASTContext &Context) override {
143 TraverseDecl(D: Context.getTranslationUnitDecl());
144 }
145
146 bool shouldWalkTypesOfTypeLocs() const { return false; }
147
148 bool VisitNamedDecl(NamedDecl *D) {
149 D->printQualifiedName(OS&: Out);
150 Out << '\n';
151 return true;
152 }
153
154 private:
155 raw_ostream &Out;
156 };
157} // end anonymous namespace
158
159std::unique_ptr<ASTConsumer>
160clang::CreateASTPrinter(std::unique_ptr<raw_ostream> Out,
161 StringRef FilterString) {
162 return std::make_unique<ASTPrinter>(args: std::move(Out), args: ASTPrinter::Print,
163 args: ADOF_Default, args&: FilterString);
164}
165
166std::unique_ptr<ASTConsumer>
167clang::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 args: std::move(Out),
173 args: Deserialize ? ASTPrinter::DumpFull
174 : DumpDecls ? ASTPrinter::Dump : ASTPrinter::None,
175 args&: Format, args&: FilterString, args&: DumpLookups, args&: DumpDeclTypes);
176}
177
178std::unique_ptr<ASTConsumer> clang::CreateASTDeclNodeLister() {
179 return std::make_unique<ASTDeclNodeLister>(args: nullptr);
180}
181
182//===----------------------------------------------------------------------===//
183/// ASTViewer - AST Visualization
184
185namespace {
186class ASTViewer : public ASTConsumer {
187 ASTContext *Context = nullptr;
188
189public:
190 void Initialize(ASTContext &Context) override { this->Context = &Context; }
191
192 bool HandleTopLevelDecl(DeclGroupRef D) override {
193 for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
194 HandleTopLevelSingleDecl(D: *I);
195 return true;
196 }
197
198 void HandleTopLevelSingleDecl(Decl *D);
199};
200}
201
202void ASTViewer::HandleTopLevelSingleDecl(Decl *D) {
203 if (isa<FunctionDecl>(Val: D) || isa<ObjCMethodDecl>(Val: D)) {
204 D->print(Out&: llvm::errs());
205
206 if (Stmt *Body = D->getBody()) {
207 llvm::errs() << '\n';
208 Body->viewAST();
209 llvm::errs() << '\n';
210 }
211 }
212}
213
214std::unique_ptr<ASTConsumer> clang::CreateASTViewer() {
215 return std::make_unique<ASTViewer>();
216}
217