ASTConsumers.cpp revision 11cb5fb202107a6beb7c86ff7e94ecb04e0ed423
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