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