ASTConsumers.cpp revision 202379
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 default: 425 Out << "DeclKind: " << DK << '"' << I->getDeclKindName() << "\"\n"; 426 assert(0 && "decl unhandled"); 427 } 428 } 429} 430ASTConsumer *clang::CreateDeclContextPrinter() { 431 return new DeclContextPrinter(); 432} 433 434//===----------------------------------------------------------------------===// 435/// RecordLayoutDumper - C++ Record Layout Dumping. 436namespace { 437class RecordLayoutDumper : public ASTConsumer { 438 llvm::raw_ostream& Out; 439 440 void PrintOffset(uint64_t Offset, unsigned IndentLevel) { 441 Out << llvm::format("%4d | ", Offset); 442 for (unsigned I = 0; I < IndentLevel * 2; ++I) Out << ' '; 443 } 444 445 void DumpRecordLayoutOffsets(const CXXRecordDecl *RD, ASTContext &C, 446 uint64_t Offset, 447 unsigned IndentLevel, const char* Description, 448 bool IncludeVirtualBases) { 449 const ASTRecordLayout &Info = C.getASTRecordLayout(RD); 450 451 PrintOffset(Offset, IndentLevel); 452 Out << C.getTypeDeclType((CXXRecordDecl *)RD).getAsString(); 453 if (Description) 454 Out << ' ' << Description; 455 if (RD->isEmpty()) 456 Out << " (empty)"; 457 Out << '\n'; 458 459 IndentLevel++; 460 461 const CXXRecordDecl *PrimaryBase = Info.getPrimaryBase(); 462 463 // Vtable pointer. 464 if (RD->isDynamicClass() && !PrimaryBase) { 465 PrintOffset(Offset, IndentLevel); 466 Out << '(' << RD->getNameAsString() << " vtable pointer)\n"; 467 } 468 // Dump (non-virtual) bases 469 for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), 470 E = RD->bases_end(); I != E; ++I) { 471 assert(!I->getType()->isDependentType() && 472 "Cannot layout class with dependent bases."); 473 if (I->isVirtual()) 474 continue; 475 476 const CXXRecordDecl *Base = 477 cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); 478 479 uint64_t BaseOffset = Offset + Info.getBaseClassOffset(Base) / 8; 480 481 DumpRecordLayoutOffsets(Base, C, BaseOffset, IndentLevel, 482 Base == PrimaryBase ? "(primary base)" : "(base)", 483 /*IncludeVirtualBases=*/false); 484 } 485 486 // Dump fields. 487 uint64_t FieldNo = 0; 488 for (CXXRecordDecl::field_iterator I = RD->field_begin(), 489 E = RD->field_end(); I != E; ++I, ++FieldNo) { 490 const FieldDecl *Field = *I; 491 uint64_t FieldOffset = Offset + Info.getFieldOffset(FieldNo) / 8; 492 493 if (const RecordType *RT = Field->getType()->getAs<RecordType>()) { 494 if (const CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(RT->getDecl())) { 495 DumpRecordLayoutOffsets(D, C, FieldOffset, IndentLevel, 496 Field->getNameAsCString(), 497 /*IncludeVirtualBases=*/true); 498 continue; 499 } 500 } 501 502 PrintOffset(FieldOffset, IndentLevel); 503 Out << Field->getType().getAsString() << ' '; 504 Out << Field->getNameAsString() << '\n'; 505 } 506 507 if (!IncludeVirtualBases) 508 return; 509 510 // Dump virtual bases. 511 for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), 512 E = RD->vbases_end(); I != E; ++I) { 513 assert(I->isVirtual() && "Found non-virtual class!"); 514 const CXXRecordDecl *VBase = 515 cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); 516 517 uint64_t VBaseOffset = Offset + Info.getVBaseClassOffset(VBase) / 8; 518 DumpRecordLayoutOffsets(VBase, C, VBaseOffset, IndentLevel, 519 VBase == PrimaryBase ? 520 "(primary virtual base)" : "(virtual base)", 521 /*IncludeVirtualBases=*/false); 522 } 523 } 524 525 // FIXME: Maybe this could be useful in ASTContext.cpp. 526 void DumpRecordLayout(const CXXRecordDecl *RD, ASTContext &C) { 527 const ASTRecordLayout &Info = C.getASTRecordLayout(RD); 528 529 DumpRecordLayoutOffsets(RD, C, 0, 0, 0, 530 /*IncludeVirtualBases=*/true); 531 Out << " sizeof=" << Info.getSize() / 8; 532 Out << ", dsize=" << Info.getDataSize() / 8; 533 Out << ", align=" << Info.getAlignment() / 8 << '\n'; 534 Out << " nvsize=" << Info.getNonVirtualSize() / 8; 535 Out << ", nvalign=" << Info.getNonVirtualAlign() / 8 << '\n'; 536 Out << '\n'; 537 } 538 539public: 540 RecordLayoutDumper() : Out(llvm::errs()) {} 541 542 void HandleTranslationUnit(ASTContext &C) { 543 for (ASTContext::type_iterator I = C.types_begin(), E = C.types_end(); 544 I != E; ++I) { 545 const RecordType *RT = dyn_cast<RecordType>(*I); 546 if (!RT) 547 continue; 548 549 const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); 550 if (!RD) 551 continue; 552 553 if (RD->isImplicit()) 554 continue; 555 556 if (RD->isDependentType()) 557 continue; 558 559 if (RD->isInvalidDecl()) 560 continue; 561 562 if (!RD->getDefinition(C)) 563 continue; 564 565 // FIXME: Do we really need to hard code this? 566 if (RD->getQualifiedNameAsString() == "__va_list_tag") 567 continue; 568 569 DumpRecordLayout(RD, C); 570 } 571 } 572}; 573} // end anonymous namespace 574ASTConsumer *clang::CreateRecordLayoutDumper() { 575 return new RecordLayoutDumper(); 576} 577 578//===----------------------------------------------------------------------===// 579/// InheritanceViewer - C++ Inheritance Visualization 580 581namespace { 582class InheritanceViewer : public ASTConsumer { 583 const std::string clsname; 584public: 585 InheritanceViewer(const std::string& cname) : clsname(cname) {} 586 587 void HandleTranslationUnit(ASTContext &C) { 588 for (ASTContext::type_iterator I=C.types_begin(),E=C.types_end(); I!=E; ++I) 589 if (RecordType *T = dyn_cast<RecordType>(*I)) { 590 if (CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(T->getDecl())) { 591 // FIXME: This lookup needs to be generalized to handle namespaces and 592 // (when we support them) templates. 593 if (D->getNameAsString() == clsname) { 594 D->viewInheritance(C); 595 } 596 } 597 } 598 } 599}; 600} 601 602ASTConsumer *clang::CreateInheritanceViewer(const std::string& clsname) { 603 return new InheritanceViewer(clsname); 604} 605