1//===--- ASTConsumers.cpp - ASTConsumer implementations -------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// AST Consumer Implementations.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Frontend/ASTConsumers.h"
15#include "clang/Basic/FileManager.h"
16#include "clang/Basic/Diagnostic.h"
17#include "clang/Basic/SourceManager.h"
18#include "clang/AST/AST.h"
19#include "clang/AST/ASTConsumer.h"
20#include "clang/AST/ASTContext.h"
21#include "clang/AST/PrettyPrinter.h"
22#include "clang/AST/RecordLayout.h"
23#include "clang/AST/RecursiveASTVisitor.h"
24#include "llvm/Module.h"
25#include "llvm/Support/Path.h"
26#include "llvm/Support/raw_ostream.h"
27#include "llvm/Support/Timer.h"
28using namespace clang;
29
30//===----------------------------------------------------------------------===//
31/// ASTPrinter - Pretty-printer and dumper of ASTs
32
33namespace {
34  class ASTPrinter : public ASTConsumer,
35                     public RecursiveASTVisitor<ASTPrinter> {
36    typedef RecursiveASTVisitor<ASTPrinter> base;
37
38  public:
39    ASTPrinter(raw_ostream *Out = NULL, bool Dump = false,
40               StringRef FilterString = "")
41        : Out(Out ? *Out : llvm::outs()), Dump(Dump),
42          FilterString(FilterString) {}
43
44    virtual void HandleTranslationUnit(ASTContext &Context) {
45      TranslationUnitDecl *D = Context.getTranslationUnitDecl();
46
47      if (FilterString.empty()) {
48        if (Dump)
49          D->dump(Out);
50        else
51          D->print(Out, /*Indentation=*/0, /*PrintInstantiation=*/true);
52        return;
53      }
54
55      TraverseDecl(D);
56    }
57
58    bool shouldWalkTypesOfTypeLocs() const { return false; }
59
60    bool TraverseDecl(Decl *D) {
61      if (D == NULL)
62        return false;
63      if (filterMatches(D)) {
64        Out.changeColor(llvm::raw_ostream::BLUE) <<
65            (Dump ? "Dumping " : "Printing ") << getName(D) << ":\n";
66        Out.resetColor();
67        if (Dump)
68          D->dump(Out);
69        else
70          D->print(Out, /*Indentation=*/0, /*PrintInstantiation=*/true);
71        Out << "\n";
72        // Don't traverse child nodes to avoid output duplication.
73        return true;
74      }
75      return base::TraverseDecl(D);
76    }
77
78  private:
79    std::string getName(Decl *D) {
80      if (isa<NamedDecl>(D))
81        return cast<NamedDecl>(D)->getQualifiedNameAsString();
82      return "";
83    }
84    bool filterMatches(Decl *D) {
85      return getName(D).find(FilterString) != std::string::npos;
86    }
87
88    raw_ostream &Out;
89    bool Dump;
90    std::string FilterString;
91  };
92
93  class ASTDeclNodeLister : public ASTConsumer,
94                     public RecursiveASTVisitor<ASTDeclNodeLister> {
95  public:
96    ASTDeclNodeLister(raw_ostream *Out = NULL)
97        : Out(Out ? *Out : llvm::outs()) {}
98
99    virtual void HandleTranslationUnit(ASTContext &Context) {
100      TraverseDecl(Context.getTranslationUnitDecl());
101    }
102
103    bool shouldWalkTypesOfTypeLocs() const { return false; }
104
105    virtual bool VisitNamedDecl(NamedDecl *D) {
106      Out << D->getQualifiedNameAsString() << "\n";
107      return true;
108    }
109
110  private:
111    raw_ostream &Out;
112  };
113} // end anonymous namespace
114
115ASTConsumer *clang::CreateASTPrinter(raw_ostream *Out,
116                                     StringRef FilterString) {
117  return new ASTPrinter(Out, /*Dump=*/ false, FilterString);
118}
119
120ASTConsumer *clang::CreateASTDumper(StringRef FilterString) {
121  return new ASTPrinter(0, /*Dump=*/ true, FilterString);
122}
123
124ASTConsumer *clang::CreateASTDeclNodeLister() {
125  return new ASTDeclNodeLister(0);
126}
127
128//===----------------------------------------------------------------------===//
129/// ASTViewer - AST Visualization
130
131namespace {
132  class ASTViewer : public ASTConsumer {
133    ASTContext *Context;
134  public:
135    void Initialize(ASTContext &Context) {
136      this->Context = &Context;
137    }
138
139    virtual bool HandleTopLevelDecl(DeclGroupRef D) {
140      for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
141        HandleTopLevelSingleDecl(*I);
142      return true;
143    }
144
145    void HandleTopLevelSingleDecl(Decl *D);
146  };
147}
148
149void ASTViewer::HandleTopLevelSingleDecl(Decl *D) {
150  if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
151    D->print(llvm::errs());
152
153    if (Stmt *Body = D->getBody()) {
154      llvm::errs() << '\n';
155      Body->viewAST();
156      llvm::errs() << '\n';
157    }
158  }
159}
160
161
162ASTConsumer *clang::CreateASTViewer() { return new ASTViewer(); }
163
164//===----------------------------------------------------------------------===//
165/// DeclContextPrinter - Decl and DeclContext Visualization
166
167namespace {
168
169class DeclContextPrinter : public ASTConsumer {
170  raw_ostream& Out;
171public:
172  DeclContextPrinter() : Out(llvm::errs()) {}
173
174  void HandleTranslationUnit(ASTContext &C) {
175    PrintDeclContext(C.getTranslationUnitDecl(), 4);
176  }
177
178  void PrintDeclContext(const DeclContext* DC, unsigned Indentation);
179};
180}  // end anonymous namespace
181
182void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
183                                          unsigned Indentation) {
184  // Print DeclContext name.
185  switch (DC->getDeclKind()) {
186  case Decl::TranslationUnit:
187    Out << "[translation unit] " << DC;
188    break;
189  case Decl::Namespace: {
190    Out << "[namespace] ";
191    const NamespaceDecl* ND = cast<NamespaceDecl>(DC);
192    Out << *ND;
193    break;
194  }
195  case Decl::Enum: {
196    const EnumDecl* ED = cast<EnumDecl>(DC);
197    if (ED->isCompleteDefinition())
198      Out << "[enum] ";
199    else
200      Out << "<enum> ";
201    Out << *ED;
202    break;
203  }
204  case Decl::Record: {
205    const RecordDecl* RD = cast<RecordDecl>(DC);
206    if (RD->isCompleteDefinition())
207      Out << "[struct] ";
208    else
209      Out << "<struct> ";
210    Out << *RD;
211    break;
212  }
213  case Decl::CXXRecord: {
214    const CXXRecordDecl* RD = cast<CXXRecordDecl>(DC);
215    if (RD->isCompleteDefinition())
216      Out << "[class] ";
217    else
218      Out << "<class> ";
219    Out << *RD << ' ' << DC;
220    break;
221  }
222  case Decl::ObjCMethod:
223    Out << "[objc method]";
224    break;
225  case Decl::ObjCInterface:
226    Out << "[objc interface]";
227    break;
228  case Decl::ObjCCategory:
229    Out << "[objc category]";
230    break;
231  case Decl::ObjCProtocol:
232    Out << "[objc protocol]";
233    break;
234  case Decl::ObjCImplementation:
235    Out << "[objc implementation]";
236    break;
237  case Decl::ObjCCategoryImpl:
238    Out << "[objc categoryimpl]";
239    break;
240  case Decl::LinkageSpec:
241    Out << "[linkage spec]";
242    break;
243  case Decl::Block:
244    Out << "[block]";
245    break;
246  case Decl::Function: {
247    const FunctionDecl* FD = cast<FunctionDecl>(DC);
248    if (FD->doesThisDeclarationHaveABody())
249      Out << "[function] ";
250    else
251      Out << "<function> ";
252    Out << *FD;
253    // Print the parameters.
254    Out << "(";
255    bool PrintComma = false;
256    for (FunctionDecl::param_const_iterator I = FD->param_begin(),
257           E = FD->param_end(); I != E; ++I) {
258      if (PrintComma)
259        Out << ", ";
260      else
261        PrintComma = true;
262      Out << **I;
263    }
264    Out << ")";
265    break;
266  }
267  case Decl::CXXMethod: {
268    const CXXMethodDecl* D = cast<CXXMethodDecl>(DC);
269    if (D->isOutOfLine())
270      Out << "[c++ method] ";
271    else if (D->isImplicit())
272      Out << "(c++ method) ";
273    else
274      Out << "<c++ method> ";
275    Out << *D;
276    // Print the parameters.
277    Out << "(";
278    bool PrintComma = false;
279    for (FunctionDecl::param_const_iterator I = D->param_begin(),
280           E = D->param_end(); I != E; ++I) {
281      if (PrintComma)
282        Out << ", ";
283      else
284        PrintComma = true;
285      Out << **I;
286    }
287    Out << ")";
288
289    // Check the semantic DeclContext.
290    const DeclContext* SemaDC = D->getDeclContext();
291    const DeclContext* LexicalDC = D->getLexicalDeclContext();
292    if (SemaDC != LexicalDC)
293      Out << " [[" << SemaDC << "]]";
294
295    break;
296  }
297  case Decl::CXXConstructor: {
298    const CXXConstructorDecl* D = cast<CXXConstructorDecl>(DC);
299    if (D->isOutOfLine())
300      Out << "[c++ ctor] ";
301    else if (D->isImplicit())
302      Out << "(c++ ctor) ";
303    else
304      Out << "<c++ ctor> ";
305    Out << *D;
306    // Print the parameters.
307    Out << "(";
308    bool PrintComma = false;
309    for (FunctionDecl::param_const_iterator I = D->param_begin(),
310           E = D->param_end(); I != E; ++I) {
311      if (PrintComma)
312        Out << ", ";
313      else
314        PrintComma = true;
315      Out << **I;
316    }
317    Out << ")";
318
319    // Check the semantic DC.
320    const DeclContext* SemaDC = D->getDeclContext();
321    const DeclContext* LexicalDC = D->getLexicalDeclContext();
322    if (SemaDC != LexicalDC)
323      Out << " [[" << SemaDC << "]]";
324    break;
325  }
326  case Decl::CXXDestructor: {
327    const CXXDestructorDecl* D = cast<CXXDestructorDecl>(DC);
328    if (D->isOutOfLine())
329      Out << "[c++ dtor] ";
330    else if (D->isImplicit())
331      Out << "(c++ dtor) ";
332    else
333      Out << "<c++ dtor> ";
334    Out << *D;
335    // Check the semantic DC.
336    const DeclContext* SemaDC = D->getDeclContext();
337    const DeclContext* LexicalDC = D->getLexicalDeclContext();
338    if (SemaDC != LexicalDC)
339      Out << " [[" << SemaDC << "]]";
340    break;
341  }
342  case Decl::CXXConversion: {
343    const CXXConversionDecl* D = cast<CXXConversionDecl>(DC);
344    if (D->isOutOfLine())
345      Out << "[c++ conversion] ";
346    else if (D->isImplicit())
347      Out << "(c++ conversion) ";
348    else
349      Out << "<c++ conversion> ";
350    Out << *D;
351    // Check the semantic DC.
352    const DeclContext* SemaDC = D->getDeclContext();
353    const DeclContext* LexicalDC = D->getLexicalDeclContext();
354    if (SemaDC != LexicalDC)
355      Out << " [[" << SemaDC << "]]";
356    break;
357  }
358
359  default:
360    llvm_unreachable("a decl that inherits DeclContext isn't handled");
361  }
362
363  Out << "\n";
364
365  // Print decls in the DeclContext.
366  for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
367       I != E; ++I) {
368    for (unsigned i = 0; i < Indentation; ++i)
369      Out << "  ";
370
371    Decl::Kind DK = I->getKind();
372    switch (DK) {
373    case Decl::Namespace:
374    case Decl::Enum:
375    case Decl::Record:
376    case Decl::CXXRecord:
377    case Decl::ObjCMethod:
378    case Decl::ObjCInterface:
379    case Decl::ObjCCategory:
380    case Decl::ObjCProtocol:
381    case Decl::ObjCImplementation:
382    case Decl::ObjCCategoryImpl:
383    case Decl::LinkageSpec:
384    case Decl::Block:
385    case Decl::Function:
386    case Decl::CXXMethod:
387    case Decl::CXXConstructor:
388    case Decl::CXXDestructor:
389    case Decl::CXXConversion:
390    {
391      DeclContext* DC = cast<DeclContext>(*I);
392      PrintDeclContext(DC, Indentation+2);
393      break;
394    }
395    case Decl::IndirectField: {
396      IndirectFieldDecl* IFD = cast<IndirectFieldDecl>(*I);
397      Out << "<IndirectField> " << *IFD << '\n';
398      break;
399    }
400    case Decl::Label: {
401      LabelDecl *LD = cast<LabelDecl>(*I);
402      Out << "<Label> " << *LD << '\n';
403      break;
404    }
405    case Decl::Field: {
406      FieldDecl *FD = cast<FieldDecl>(*I);
407      Out << "<field> " << *FD << '\n';
408      break;
409    }
410    case Decl::Typedef:
411    case Decl::TypeAlias: {
412      TypedefNameDecl* TD = cast<TypedefNameDecl>(*I);
413      Out << "<typedef> " << *TD << '\n';
414      break;
415    }
416    case Decl::EnumConstant: {
417      EnumConstantDecl* ECD = cast<EnumConstantDecl>(*I);
418      Out << "<enum constant> " << *ECD << '\n';
419      break;
420    }
421    case Decl::Var: {
422      VarDecl* VD = cast<VarDecl>(*I);
423      Out << "<var> " << *VD << '\n';
424      break;
425    }
426    case Decl::ImplicitParam: {
427      ImplicitParamDecl* IPD = cast<ImplicitParamDecl>(*I);
428      Out << "<implicit parameter> " << *IPD << '\n';
429      break;
430    }
431    case Decl::ParmVar: {
432      ParmVarDecl* PVD = cast<ParmVarDecl>(*I);
433      Out << "<parameter> " << *PVD << '\n';
434      break;
435    }
436    case Decl::ObjCProperty: {
437      ObjCPropertyDecl* OPD = cast<ObjCPropertyDecl>(*I);
438      Out << "<objc property> " << *OPD << '\n';
439      break;
440    }
441    case Decl::FunctionTemplate: {
442      FunctionTemplateDecl* FTD = cast<FunctionTemplateDecl>(*I);
443      Out << "<function template> " << *FTD << '\n';
444      break;
445    }
446    case Decl::FileScopeAsm: {
447      Out << "<file-scope asm>\n";
448      break;
449    }
450    case Decl::UsingDirective: {
451      Out << "<using directive>\n";
452      break;
453    }
454    case Decl::NamespaceAlias: {
455      NamespaceAliasDecl* NAD = cast<NamespaceAliasDecl>(*I);
456      Out << "<namespace alias> " << *NAD << '\n';
457      break;
458    }
459    case Decl::ClassTemplate: {
460      ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(*I);
461      Out << "<class template> " << *CTD << '\n';
462      break;
463    }
464    default:
465      Out << "DeclKind: " << DK << '"' << *I << "\"\n";
466      llvm_unreachable("decl unhandled");
467    }
468  }
469}
470ASTConsumer *clang::CreateDeclContextPrinter() {
471  return new DeclContextPrinter();
472}
473
474//===----------------------------------------------------------------------===//
475/// ASTDumperXML - In-depth XML dumping.
476
477namespace {
478class ASTDumpXML : public ASTConsumer {
479  raw_ostream &OS;
480
481public:
482  ASTDumpXML(raw_ostream &OS) : OS(OS) {}
483
484  void HandleTranslationUnit(ASTContext &C) {
485    C.getTranslationUnitDecl()->dumpXML(OS);
486  }
487};
488}
489
490ASTConsumer *clang::CreateASTDumperXML(raw_ostream &OS) {
491  return new ASTDumpXML(OS);
492}
493