xref: /llvm-project/clang/lib/Frontend/ASTConsumers.cpp (revision 258fc7f582877d3bc2a26e62da4f50e467d8c640)
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"
25 using namespace clang;
26 
27 //===----------------------------------------------------------------------===//
28 /// ASTPrinter - Pretty-printer and dumper of ASTs
29 
30 namespace {
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(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>(D))
78         return cast<NamedDecl>(D)->getQualifiedNameAsString();
79       return "";
80     }
81     bool filterMatches(Decl *D) {
82       return getName(D).find(FilterString) != std::string::npos;
83     }
84     void print(Decl *D) {
85       if (DumpLookups) {
86         if (DeclContext *DC = dyn_cast<DeclContext>(D)) {
87           if (DC == DC->getPrimaryContext())
88             DC->dumpLookups(Out, OutputKind != None, 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, OutputKind == DumpFull, OutputFormat);
99       }
100 
101       if (DumpDeclTypes) {
102         Decl *InnerD = D;
103         if (auto *TD = dyn_cast<TemplateDecl>(D))
104           if (Decl *TempD = TD->getTemplatedDecl())
105             InnerD = TempD;
106 
107         // FIXME: Support OutputFormat in type dumping.
108         // FIXME: Support combining -ast-dump-decl-types with -ast-dump-lookups.
109         if (auto *VD = dyn_cast<ValueDecl>(InnerD))
110           VD->getType().dump(Out, VD->getASTContext());
111         if (auto *TD = dyn_cast<TypeDecl>(InnerD))
112           TD->getTypeForDecl()->dump(Out, TD->getASTContext());
113       }
114     }
115 
116     raw_ostream &Out;
117     std::unique_ptr<raw_ostream> OwnedOut;
118 
119     /// How to output individual declarations.
120     Kind OutputKind;
121 
122     /// What format should the output take?
123     ASTDumpOutputFormat OutputFormat;
124 
125     /// Which declarations or DeclContexts to display.
126     std::string FilterString;
127 
128     /// Whether the primary output is lookup results or declarations. Individual
129     /// results will be output with a format determined by OutputKind. This is
130     /// incompatible with OutputKind == Print.
131     bool DumpLookups;
132 
133     /// Whether to dump the type for each declaration dumped.
134     bool DumpDeclTypes;
135   };
136 
137   class ASTDeclNodeLister : public ASTConsumer,
138                      public RecursiveASTVisitor<ASTDeclNodeLister> {
139   public:
140     ASTDeclNodeLister(raw_ostream *Out = nullptr)
141         : Out(Out ? *Out : llvm::outs()) {}
142 
143     void HandleTranslationUnit(ASTContext &Context) override {
144       TraverseDecl(Context.getTranslationUnitDecl());
145     }
146 
147     bool shouldWalkTypesOfTypeLocs() const { return false; }
148 
149     bool VisitNamedDecl(NamedDecl *D) {
150       D->printQualifiedName(Out);
151       Out << '\n';
152       return true;
153     }
154 
155   private:
156     raw_ostream &Out;
157   };
158 } // end anonymous namespace
159 
160 std::unique_ptr<ASTConsumer>
161 clang::CreateASTPrinter(std::unique_ptr<raw_ostream> Out,
162                         StringRef FilterString) {
163   return std::make_unique<ASTPrinter>(std::move(Out), ASTPrinter::Print,
164                                        ADOF_Default, FilterString);
165 }
166 
167 std::unique_ptr<ASTConsumer>
168 clang::CreateASTDumper(std::unique_ptr<raw_ostream> Out, StringRef FilterString,
169                        bool DumpDecls, bool Deserialize, bool DumpLookups,
170                        bool DumpDeclTypes, ASTDumpOutputFormat Format) {
171   assert((DumpDecls || Deserialize || DumpLookups) && "nothing to dump");
172   return std::make_unique<ASTPrinter>(
173       std::move(Out),
174       Deserialize ? ASTPrinter::DumpFull
175                   : DumpDecls ? ASTPrinter::Dump : ASTPrinter::None,
176       Format, FilterString, DumpLookups, DumpDeclTypes);
177 }
178 
179 std::unique_ptr<ASTConsumer> clang::CreateASTDeclNodeLister() {
180   return std::make_unique<ASTDeclNodeLister>(nullptr);
181 }
182 
183 //===----------------------------------------------------------------------===//
184 /// ASTViewer - AST Visualization
185 
186 namespace {
187 class ASTViewer : public ASTConsumer {
188   ASTContext *Context = nullptr;
189 
190 public:
191   void Initialize(ASTContext &Context) override { this->Context = &Context; }
192 
193   bool HandleTopLevelDecl(DeclGroupRef D) override {
194     for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
195       HandleTopLevelSingleDecl(*I);
196     return true;
197   }
198 
199   void HandleTopLevelSingleDecl(Decl *D);
200 };
201 }
202 
203 void ASTViewer::HandleTopLevelSingleDecl(Decl *D) {
204   if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
205     D->print(llvm::errs());
206 
207     if (Stmt *Body = D->getBody()) {
208       llvm::errs() << '\n';
209       Body->viewAST();
210       llvm::errs() << '\n';
211     }
212   }
213 }
214 
215 std::unique_ptr<ASTConsumer> clang::CreateASTViewer() {
216   return std::make_unique<ASTViewer>();
217 }
218