ASTConsumers.cpp revision 198893
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/Frontend/DocumentXML.h"
16#include "clang/Frontend/PathDiagnosticClients.h"
17#include "clang/Basic/Diagnostic.h"
18#include "clang/Basic/SourceManager.h"
19#include "clang/Basic/FileManager.h"
20#include "clang/AST/AST.h"
21#include "clang/AST/ASTConsumer.h"
22#include "clang/AST/ASTContext.h"
23#include "clang/AST/RecordLayout.h"
24#include "clang/AST/PrettyPrinter.h"
25#include "clang/CodeGen/ModuleBuilder.h"
26#include "llvm/Module.h"
27#include "llvm/Support/Format.h"
28#include "llvm/Support/Timer.h"
29#include "llvm/Support/raw_ostream.h"
30#include "llvm/System/Path.h"
31#include <cstdio>
32
33using namespace clang;
34
35//===----------------------------------------------------------------------===//
36/// ASTPrinter - Pretty-printer and dumper of ASTs
37
38namespace {
39  class ASTPrinter : public ASTConsumer {
40    llvm::raw_ostream &Out;
41    bool Dump;
42
43  public:
44    ASTPrinter(llvm::raw_ostream* o = NULL, bool Dump = false)
45      : Out(o? *o : llvm::errs()), Dump(Dump) { }
46
47    virtual void HandleTranslationUnit(ASTContext &Context) {
48      PrintingPolicy Policy = Context.PrintingPolicy;
49      Policy.Dump = Dump;
50      Context.getTranslationUnitDecl()->print(Out, Policy);
51    }
52  };
53} // end anonymous namespace
54
55ASTConsumer *clang::CreateASTPrinter(llvm::raw_ostream* out) {
56  return new ASTPrinter(out);
57}
58
59//===----------------------------------------------------------------------===//
60/// ASTPrinterXML - XML-printer of ASTs
61
62namespace {
63  class ASTPrinterXML : public ASTConsumer {
64    DocumentXML         Doc;
65
66  public:
67    ASTPrinterXML(llvm::raw_ostream& o) : Doc("CLANG_XML", o) {}
68
69    void Initialize(ASTContext &Context) {
70      Doc.initialize(Context);
71    }
72
73    virtual void HandleTranslationUnit(ASTContext &Ctx) {
74      Doc.addSubNode("TranslationUnit");
75      for (DeclContext::decl_iterator
76             D = Ctx.getTranslationUnitDecl()->decls_begin(),
77             DEnd = Ctx.getTranslationUnitDecl()->decls_end();
78           D != DEnd;
79           ++D)
80        Doc.PrintDecl(*D);
81      Doc.toParent();
82      Doc.finalize();
83    }
84  };
85} // end anonymous namespace
86
87
88ASTConsumer *clang::CreateASTPrinterXML(llvm::raw_ostream* out) {
89  return new ASTPrinterXML(out ? *out : llvm::outs());
90}
91
92ASTConsumer *clang::CreateASTDumper() {
93  return new ASTPrinter(0, true);
94}
95
96//===----------------------------------------------------------------------===//
97/// ASTViewer - AST Visualization
98
99namespace {
100  class ASTViewer : public ASTConsumer {
101    ASTContext *Context;
102  public:
103    void Initialize(ASTContext &Context) {
104      this->Context = &Context;
105    }
106
107    virtual void HandleTopLevelDecl(DeclGroupRef D) {
108      for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
109        HandleTopLevelSingleDecl(*I);
110    }
111
112    void HandleTopLevelSingleDecl(Decl *D);
113  };
114}
115
116void ASTViewer::HandleTopLevelSingleDecl(Decl *D) {
117  if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
118    FD->print(llvm::errs());
119
120    if (Stmt *Body = FD->getBody()) {
121      llvm::errs() << '\n';
122      Body->viewAST();
123      llvm::errs() << '\n';
124    }
125    return;
126  }
127
128  if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
129    MD->print(llvm::errs());
130
131    if (MD->getBody()) {
132      llvm::errs() << '\n';
133      MD->getBody()->viewAST();
134      llvm::errs() << '\n';
135    }
136  }
137}
138
139
140ASTConsumer *clang::CreateASTViewer() { return new ASTViewer(); }
141
142//===----------------------------------------------------------------------===//
143/// DeclContextPrinter - Decl and DeclContext Visualization
144
145namespace {
146
147class DeclContextPrinter : public ASTConsumer {
148  llvm::raw_ostream& Out;
149public:
150  DeclContextPrinter() : Out(llvm::errs()) {}
151
152  void HandleTranslationUnit(ASTContext &C) {
153    PrintDeclContext(C.getTranslationUnitDecl(), 4);
154  }
155
156  void PrintDeclContext(const DeclContext* DC, unsigned Indentation);
157};
158}  // end anonymous namespace
159
160void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
161                                          unsigned Indentation) {
162  // Print DeclContext name.
163  switch (DC->getDeclKind()) {
164  case Decl::TranslationUnit:
165    Out << "[translation unit] " << DC;
166    break;
167  case Decl::Namespace: {
168    Out << "[namespace] ";
169    const NamespaceDecl* ND = cast<NamespaceDecl>(DC);
170    Out << ND->getNameAsString();
171    break;
172  }
173  case Decl::Enum: {
174    const EnumDecl* ED = cast<EnumDecl>(DC);
175    if (ED->isDefinition())
176      Out << "[enum] ";
177    else
178      Out << "<enum> ";
179    Out << ED->getNameAsString();
180    break;
181  }
182  case Decl::Record: {
183    const RecordDecl* RD = cast<RecordDecl>(DC);
184    if (RD->isDefinition())
185      Out << "[struct] ";
186    else
187      Out << "<struct> ";
188    Out << RD->getNameAsString();
189    break;
190  }
191  case Decl::CXXRecord: {
192    const CXXRecordDecl* RD = cast<CXXRecordDecl>(DC);
193    if (RD->isDefinition())
194      Out << "[class] ";
195    else
196      Out << "<class> ";
197    Out << RD->getNameAsString() << " " << DC;
198    break;
199  }
200  case Decl::ObjCMethod:
201    Out << "[objc method]";
202    break;
203  case Decl::ObjCInterface:
204    Out << "[objc interface]";
205    break;
206  case Decl::ObjCCategory:
207    Out << "[objc category]";
208    break;
209  case Decl::ObjCProtocol:
210    Out << "[objc protocol]";
211    break;
212  case Decl::ObjCImplementation:
213    Out << "[objc implementation]";
214    break;
215  case Decl::ObjCCategoryImpl:
216    Out << "[objc categoryimpl]";
217    break;
218  case Decl::LinkageSpec:
219    Out << "[linkage spec]";
220    break;
221  case Decl::Block:
222    Out << "[block]";
223    break;
224  case Decl::Function: {
225    const FunctionDecl* FD = cast<FunctionDecl>(DC);
226    if (FD->isThisDeclarationADefinition())
227      Out << "[function] ";
228    else
229      Out << "<function> ";
230    Out << FD->getNameAsString();
231    // Print the parameters.
232    Out << "(";
233    bool PrintComma = false;
234    for (FunctionDecl::param_const_iterator I = FD->param_begin(),
235           E = FD->param_end(); I != E; ++I) {
236      if (PrintComma)
237        Out << ", ";
238      else
239        PrintComma = true;
240      Out << (*I)->getNameAsString();
241    }
242    Out << ")";
243    break;
244  }
245  case Decl::CXXMethod: {
246    const CXXMethodDecl* D = cast<CXXMethodDecl>(DC);
247    if (D->isOutOfLine())
248      Out << "[c++ method] ";
249    else if (D->isImplicit())
250      Out << "(c++ method) ";
251    else
252      Out << "<c++ method> ";
253    Out << D->getNameAsString();
254    // Print the parameters.
255    Out << "(";
256    bool PrintComma = false;
257    for (FunctionDecl::param_const_iterator I = D->param_begin(),
258           E = D->param_end(); I != E; ++I) {
259      if (PrintComma)
260        Out << ", ";
261      else
262        PrintComma = true;
263      Out << (*I)->getNameAsString();
264    }
265    Out << ")";
266
267    // Check the semantic DeclContext.
268    const DeclContext* SemaDC = D->getDeclContext();
269    const DeclContext* LexicalDC = D->getLexicalDeclContext();
270    if (SemaDC != LexicalDC)
271      Out << " [[" << SemaDC << "]]";
272
273    break;
274  }
275  case Decl::CXXConstructor: {
276    const CXXConstructorDecl* D = cast<CXXConstructorDecl>(DC);
277    if (D->isOutOfLine())
278      Out << "[c++ ctor] ";
279    else if (D->isImplicit())
280      Out << "(c++ ctor) ";
281    else
282      Out << "<c++ ctor> ";
283    Out << D->getNameAsString();
284    // Print the parameters.
285    Out << "(";
286    bool PrintComma = false;
287    for (FunctionDecl::param_const_iterator I = D->param_begin(),
288           E = D->param_end(); I != E; ++I) {
289      if (PrintComma)
290        Out << ", ";
291      else
292        PrintComma = true;
293      Out << (*I)->getNameAsString();
294    }
295    Out << ")";
296
297    // Check the semantic DC.
298    const DeclContext* SemaDC = D->getDeclContext();
299    const DeclContext* LexicalDC = D->getLexicalDeclContext();
300    if (SemaDC != LexicalDC)
301      Out << " [[" << SemaDC << "]]";
302    break;
303  }
304  case Decl::CXXDestructor: {
305    const CXXDestructorDecl* D = cast<CXXDestructorDecl>(DC);
306    if (D->isOutOfLine())
307      Out << "[c++ dtor] ";
308    else if (D->isImplicit())
309      Out << "(c++ dtor) ";
310    else
311      Out << "<c++ dtor> ";
312    Out << D->getNameAsString();
313    // Check the semantic DC.
314    const DeclContext* SemaDC = D->getDeclContext();
315    const DeclContext* LexicalDC = D->getLexicalDeclContext();
316    if (SemaDC != LexicalDC)
317      Out << " [[" << SemaDC << "]]";
318    break;
319  }
320  case Decl::CXXConversion: {
321    const CXXConversionDecl* D = cast<CXXConversionDecl>(DC);
322    if (D->isOutOfLine())
323      Out << "[c++ conversion] ";
324    else if (D->isImplicit())
325      Out << "(c++ conversion) ";
326    else
327      Out << "<c++ conversion> ";
328    Out << D->getNameAsString();
329    // Check the semantic DC.
330    const DeclContext* SemaDC = D->getDeclContext();
331    const DeclContext* LexicalDC = D->getLexicalDeclContext();
332    if (SemaDC != LexicalDC)
333      Out << " [[" << SemaDC << "]]";
334    break;
335  }
336
337  default:
338    assert(0 && "a decl that inherits DeclContext isn't handled");
339  }
340
341  Out << "\n";
342
343  // Print decls in the DeclContext.
344  for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
345       I != E; ++I) {
346    for (unsigned i = 0; i < Indentation; ++i)
347      Out << "  ";
348
349    Decl::Kind DK = I->getKind();
350    switch (DK) {
351    case Decl::Namespace:
352    case Decl::Enum:
353    case Decl::Record:
354    case Decl::CXXRecord:
355    case Decl::ObjCMethod:
356    case Decl::ObjCInterface:
357    case Decl::ObjCCategory:
358    case Decl::ObjCProtocol:
359    case Decl::ObjCImplementation:
360    case Decl::ObjCCategoryImpl:
361    case Decl::LinkageSpec:
362    case Decl::Block:
363    case Decl::Function:
364    case Decl::CXXMethod:
365    case Decl::CXXConstructor:
366    case Decl::CXXDestructor:
367    case Decl::CXXConversion:
368    {
369      DeclContext* DC = cast<DeclContext>(*I);
370      PrintDeclContext(DC, Indentation+2);
371      break;
372    }
373    case Decl::Field: {
374      FieldDecl* FD = cast<FieldDecl>(*I);
375      Out << "<field> " << FD->getNameAsString() << "\n";
376      break;
377    }
378    case Decl::Typedef: {
379      TypedefDecl* TD = cast<TypedefDecl>(*I);
380      Out << "<typedef> " << TD->getNameAsString() << "\n";
381      break;
382    }
383    case Decl::EnumConstant: {
384      EnumConstantDecl* ECD = cast<EnumConstantDecl>(*I);
385      Out << "<enum constant> " << ECD->getNameAsString() << "\n";
386      break;
387    }
388    case Decl::Var: {
389      VarDecl* VD = cast<VarDecl>(*I);
390      Out << "<var> " << VD->getNameAsString() << "\n";
391      break;
392    }
393    case Decl::ImplicitParam: {
394      ImplicitParamDecl* IPD = cast<ImplicitParamDecl>(*I);
395      Out << "<implicit parameter> " << IPD->getNameAsString() << "\n";
396      break;
397    }
398    case Decl::ParmVar: {
399      ParmVarDecl* PVD = cast<ParmVarDecl>(*I);
400      Out << "<parameter> " << PVD->getNameAsString() << "\n";
401      break;
402    }
403    case Decl::ObjCProperty: {
404      ObjCPropertyDecl* OPD = cast<ObjCPropertyDecl>(*I);
405      Out << "<objc property> " << OPD->getNameAsString() << "\n";
406      break;
407    }
408    default:
409      fprintf(stderr, "DeclKind: %d \"%s\"\n", DK, I->getDeclKindName());
410      assert(0 && "decl unhandled");
411    }
412  }
413}
414ASTConsumer *clang::CreateDeclContextPrinter() {
415  return new DeclContextPrinter();
416}
417
418//===----------------------------------------------------------------------===//
419/// RecordLayoutDumper - C++ Record Layout Dumping.
420namespace {
421class RecordLayoutDumper : public ASTConsumer {
422  llvm::raw_ostream& Out;
423
424  void PrintOffset(uint64_t Offset, unsigned IndentLevel) {
425    Out << llvm::format("%4d | ", Offset);
426    for (unsigned I = 0; I < IndentLevel * 2; ++I) Out << ' ';
427  }
428
429  void DumpRecordLayoutOffsets(const CXXRecordDecl *RD, ASTContext &C,
430                               uint64_t Offset,
431                               unsigned IndentLevel, const char* Description,
432                               bool IncludeVirtualBases) {
433    const ASTRecordLayout &Info = C.getASTRecordLayout(RD);
434
435    PrintOffset(Offset, IndentLevel);
436    Out << C.getTypeDeclType((CXXRecordDecl *)RD).getAsString();
437    if (Description)
438      Out << ' ' << Description;
439    if (RD->isEmpty())
440      Out << " (empty)";
441    Out << '\n';
442
443    IndentLevel++;
444
445    const CXXRecordDecl *PrimaryBase = Info.getPrimaryBase();
446
447    // Vtable pointer.
448    if (RD->isDynamicClass() && !PrimaryBase) {
449      PrintOffset(Offset, IndentLevel);
450      Out << '(' << RD->getNameAsString() << " vtable pointer)\n";
451    }
452    // Dump (non-virtual) bases
453    for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
454         E = RD->bases_end(); I != E; ++I) {
455      assert(!I->getType()->isDependentType() &&
456             "Cannot layout class with dependent bases.");
457      if (I->isVirtual())
458        continue;
459
460      const CXXRecordDecl *Base =
461        cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
462
463      uint64_t BaseOffset = Offset + Info.getBaseClassOffset(Base) / 8;
464
465      DumpRecordLayoutOffsets(Base, C, BaseOffset, IndentLevel,
466                              Base == PrimaryBase ? "(primary base)" : "(base)",
467                              /*IncludeVirtualBases=*/false);
468    }
469
470    // Dump fields.
471    uint64_t FieldNo = 0;
472    for (CXXRecordDecl::field_iterator I = RD->field_begin(),
473         E = RD->field_end(); I != E; ++I, ++FieldNo) {
474      const FieldDecl *Field = *I;
475      uint64_t FieldOffset = Offset + Info.getFieldOffset(FieldNo) / 8;
476
477      if (const RecordType *RT = Field->getType()->getAs<RecordType>()) {
478        if (const CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
479          DumpRecordLayoutOffsets(D, C, FieldOffset, IndentLevel,
480                                  Field->getNameAsCString(),
481                                  /*IncludeVirtualBases=*/true);
482          continue;
483        }
484      }
485
486      PrintOffset(FieldOffset, IndentLevel);
487      Out << Field->getType().getAsString() << ' ';
488      Out << Field->getNameAsString() << '\n';
489    }
490
491    if (!IncludeVirtualBases)
492      return;
493
494    // Dump virtual bases.
495    for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
496         E = RD->vbases_end(); I != E; ++I) {
497      assert(I->isVirtual() && "Found non-virtual class!");
498      const CXXRecordDecl *VBase =
499        cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
500
501      uint64_t VBaseOffset = Offset + Info.getVBaseClassOffset(VBase) / 8;
502      DumpRecordLayoutOffsets(VBase, C, VBaseOffset, IndentLevel,
503                              VBase == PrimaryBase ?
504                              "(primary virtual base)" : "(virtual base)",
505                              /*IncludeVirtualBases=*/false);
506    }
507  }
508
509  // FIXME: Maybe this could be useful in ASTContext.cpp.
510  void DumpRecordLayout(const CXXRecordDecl *RD, ASTContext &C) {
511    const ASTRecordLayout &Info = C.getASTRecordLayout(RD);
512
513    DumpRecordLayoutOffsets(RD, C, 0, 0, 0,
514                            /*IncludeVirtualBases=*/true);
515    Out << "  sizeof=" << Info.getSize() / 8;
516    Out << ", dsize=" << Info.getDataSize() / 8;
517    Out << ", align=" << Info.getAlignment() / 8 << '\n';
518    Out << "  nvsize=" << Info.getNonVirtualSize() / 8;
519    Out << ", nvalign=" << Info.getNonVirtualAlign() / 8 << '\n';
520    Out << '\n';
521  }
522
523public:
524  RecordLayoutDumper() : Out(llvm::errs()) {}
525
526  void HandleTranslationUnit(ASTContext &C) {
527    for (ASTContext::type_iterator I = C.types_begin(), E = C.types_end();
528         I != E; ++I) {
529      const RecordType *RT = dyn_cast<RecordType>(*I);
530      if (!RT)
531        continue;
532
533      const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
534      if (!RD)
535        continue;
536
537      if (RD->isImplicit())
538        continue;
539
540      if (RD->isDependentType())
541        continue;
542
543      if (RD->isInvalidDecl())
544        continue;
545
546      if (!RD->getDefinition(C))
547        continue;
548
549      // FIXME: Do we really need to hard code this?
550      if (RD->getQualifiedNameAsString() == "__va_list_tag")
551        continue;
552
553      DumpRecordLayout(RD, C);
554   }
555  }
556};
557} // end anonymous namespace
558ASTConsumer *clang::CreateRecordLayoutDumper() {
559  return new RecordLayoutDumper();
560}
561
562//===----------------------------------------------------------------------===//
563/// InheritanceViewer - C++ Inheritance Visualization
564
565namespace {
566class InheritanceViewer : public ASTConsumer {
567  const std::string clsname;
568public:
569  InheritanceViewer(const std::string& cname) : clsname(cname) {}
570
571  void HandleTranslationUnit(ASTContext &C) {
572    for (ASTContext::type_iterator I=C.types_begin(),E=C.types_end(); I!=E; ++I)
573      if (RecordType *T = dyn_cast<RecordType>(*I)) {
574        if (CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(T->getDecl())) {
575          // FIXME: This lookup needs to be generalized to handle namespaces and
576          // (when we support them) templates.
577          if (D->getNameAsString() == clsname) {
578            D->viewInheritance(C);
579          }
580        }
581      }
582  }
583};
584}
585
586ASTConsumer *clang::CreateInheritanceViewer(const std::string& clsname) {
587  return new InheritanceViewer(clsname);
588}
589