DeclPrinter.cpp revision 193326
1//===--- DeclPrinter.cpp - Printing implementation for Decl ASTs ----------===// 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// This file implements the Decl::dump method, which pretty print the 11// AST back out to C/Objective-C/C++/Objective-C++ code. 12// 13//===----------------------------------------------------------------------===// 14#include "clang/AST/ASTContext.h" 15#include "clang/AST/DeclVisitor.h" 16#include "clang/AST/Decl.h" 17#include "clang/AST/DeclCXX.h" 18#include "clang/AST/DeclObjC.h" 19#include "clang/AST/Expr.h" 20#include "clang/AST/PrettyPrinter.h" 21#include "llvm/Support/Compiler.h" 22#include "llvm/Support/Streams.h" 23#include "llvm/Support/Format.h" 24#include "llvm/Support/raw_ostream.h" 25using namespace clang; 26 27namespace { 28 class VISIBILITY_HIDDEN DeclPrinter : public DeclVisitor<DeclPrinter> { 29 llvm::raw_ostream &Out; 30 ASTContext &Context; 31 PrintingPolicy Policy; 32 unsigned Indentation; 33 34 llvm::raw_ostream& Indent(); 35 void ProcessDeclGroup(llvm::SmallVectorImpl<Decl*>& Decls); 36 37 public: 38 DeclPrinter(llvm::raw_ostream &Out, ASTContext &Context, 39 const PrintingPolicy &Policy, 40 unsigned Indentation = 0) 41 : Out(Out), Context(Context), Policy(Policy), Indentation(Indentation) { } 42 43 void VisitDeclContext(DeclContext *DC, bool Indent = true); 44 45 void VisitTranslationUnitDecl(TranslationUnitDecl *D); 46 void VisitTypedefDecl(TypedefDecl *D); 47 void VisitEnumDecl(EnumDecl *D); 48 void VisitRecordDecl(RecordDecl *D); 49 void VisitEnumConstantDecl(EnumConstantDecl *D); 50 void VisitFunctionDecl(FunctionDecl *D); 51 void VisitFieldDecl(FieldDecl *D); 52 void VisitVarDecl(VarDecl *D); 53 void VisitParmVarDecl(ParmVarDecl *D); 54 void VisitOriginalParmVarDecl(OriginalParmVarDecl *D); 55 void VisitFileScopeAsmDecl(FileScopeAsmDecl *D); 56 void VisitOverloadedFunctionDecl(OverloadedFunctionDecl *D); 57 void VisitNamespaceDecl(NamespaceDecl *D); 58 void VisitUsingDirectiveDecl(UsingDirectiveDecl *D); 59 void VisitNamespaceAliasDecl(NamespaceAliasDecl *D); 60 void VisitCXXRecordDecl(CXXRecordDecl *D); 61 void VisitLinkageSpecDecl(LinkageSpecDecl *D); 62 void VisitTemplateDecl(TemplateDecl *D); 63 void VisitObjCMethodDecl(ObjCMethodDecl *D); 64 void VisitObjCClassDecl(ObjCClassDecl *D); 65 void VisitObjCImplementationDecl(ObjCImplementationDecl *D); 66 void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); 67 void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D); 68 void VisitObjCProtocolDecl(ObjCProtocolDecl *D); 69 void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); 70 void VisitObjCCategoryDecl(ObjCCategoryDecl *D); 71 void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D); 72 void VisitObjCPropertyDecl(ObjCPropertyDecl *D); 73 void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); 74 }; 75} 76 77void Decl::print(llvm::raw_ostream &Out, ASTContext &Context, 78 unsigned Indentation) { 79 print(Out, Context, Context.PrintingPolicy, Indentation); 80} 81 82void Decl::print(llvm::raw_ostream &Out, ASTContext &Context, 83 const PrintingPolicy &Policy, unsigned Indentation) { 84 DeclPrinter Printer(Out, Context, Policy, Indentation); 85 Printer.Visit(this); 86} 87 88static QualType GetBaseType(QualType T) { 89 // FIXME: This should be on the Type class! 90 QualType BaseType = T; 91 while (!BaseType->isSpecifierType()) { 92 if (isa<TypedefType>(BaseType)) 93 break; 94 else if (const PointerType* PTy = BaseType->getAsPointerType()) 95 BaseType = PTy->getPointeeType(); 96 else if (const ArrayType* ATy = dyn_cast<ArrayType>(BaseType)) 97 BaseType = ATy->getElementType(); 98 else if (const FunctionType* FTy = BaseType->getAsFunctionType()) 99 BaseType = FTy->getResultType(); 100 else 101 assert(0 && "Unknown declarator!"); 102 } 103 return BaseType; 104} 105 106static QualType getDeclType(Decl* D) { 107 if (TypedefDecl* TDD = dyn_cast<TypedefDecl>(D)) 108 return TDD->getUnderlyingType(); 109 if (ValueDecl* VD = dyn_cast<ValueDecl>(D)) 110 return VD->getType(); 111 return QualType(); 112} 113 114void Decl::printGroup(Decl** Begin, unsigned NumDecls, 115 llvm::raw_ostream &Out, ASTContext &Context, 116 const PrintingPolicy &Policy, 117 unsigned Indentation) { 118 if (NumDecls == 1) { 119 (*Begin)->print(Out, Context, Policy, Indentation); 120 return; 121 } 122 123 Decl** End = Begin + NumDecls; 124 TagDecl* TD = dyn_cast<TagDecl>(*Begin); 125 if (TD) 126 ++Begin; 127 128 PrintingPolicy SubPolicy(Policy); 129 if (TD && TD->isDefinition()) { 130 TD->print(Out, Context, Policy, Indentation); 131 Out << " "; 132 SubPolicy.SuppressTag = true; 133 } 134 135 bool isFirst = true; 136 for ( ; Begin != End; ++Begin) { 137 if (isFirst) { 138 SubPolicy.SuppressSpecifiers = false; 139 isFirst = false; 140 } else { 141 if (!isFirst) Out << ", "; 142 SubPolicy.SuppressSpecifiers = true; 143 } 144 145 (*Begin)->print(Out, Context, SubPolicy, Indentation); 146 } 147} 148 149void Decl::dump(ASTContext &Context) { 150 print(llvm::errs(), Context); 151} 152 153llvm::raw_ostream& DeclPrinter::Indent() { 154 for (unsigned i = 0; i < Indentation; ++i) 155 Out << " "; 156 return Out; 157} 158 159void DeclPrinter::ProcessDeclGroup(llvm::SmallVectorImpl<Decl*>& Decls) { 160 this->Indent(); 161 Decl::printGroup(Decls.data(), Decls.size(), Out, Context, 162 Policy, Indentation); 163 Out << ";\n"; 164 Decls.clear(); 165 166} 167 168//---------------------------------------------------------------------------- 169// Common C declarations 170//---------------------------------------------------------------------------- 171 172void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { 173 if (Indent) 174 Indentation += Policy.Indentation; 175 176 llvm::SmallVector<Decl*, 2> Decls; 177 for (DeclContext::decl_iterator D = DC->decls_begin(Context), 178 DEnd = DC->decls_end(Context); 179 D != DEnd; ++D) { 180 if (!Policy.Dump) { 181 // Skip over implicit declarations in pretty-printing mode. 182 if (D->isImplicit()) continue; 183 // FIXME: Ugly hack so we don't pretty-print the builtin declaration 184 // of __builtin_va_list. There should be some other way to check that. 185 if (isa<NamedDecl>(*D) && cast<NamedDecl>(*D)->getNameAsString() == 186 "__builtin_va_list") 187 continue; 188 } 189 190 // The next bits of code handles stuff like "struct {int x;} a,b"; we're 191 // forced to merge the declarations because there's no other way to 192 // refer to the struct in question. This limited merging is safe without 193 // a bunch of other checks because it only merges declarations directly 194 // referring to the tag, not typedefs. 195 // 196 // Check whether the current declaration should be grouped with a previous 197 // unnamed struct. 198 QualType CurDeclType = getDeclType(*D); 199 if (!Decls.empty() && !CurDeclType.isNull()) { 200 QualType BaseType = GetBaseType(CurDeclType); 201 if (!BaseType.isNull() && isa<TagType>(BaseType) && 202 cast<TagType>(BaseType)->getDecl() == Decls[0]) { 203 Decls.push_back(*D); 204 continue; 205 } 206 } 207 208 // If we have a merged group waiting to be handled, handle it now. 209 if (!Decls.empty()) 210 ProcessDeclGroup(Decls); 211 212 // If the current declaration is an unnamed tag type, save it 213 // so we can merge it with the subsequent declaration(s) using it. 214 if (isa<TagDecl>(*D) && !cast<TagDecl>(*D)->getIdentifier()) { 215 Decls.push_back(*D); 216 continue; 217 } 218 this->Indent(); 219 Visit(*D); 220 221 // FIXME: Need to be able to tell the DeclPrinter when 222 const char *Terminator = 0; 223 if (isa<FunctionDecl>(*D) && 224 cast<FunctionDecl>(*D)->isThisDeclarationADefinition()) 225 Terminator = 0; 226 else if (isa<ObjCMethodDecl>(*D) && cast<ObjCMethodDecl>(*D)->getBody()) 227 Terminator = 0; 228 else if (isa<NamespaceDecl>(*D) || isa<LinkageSpecDecl>(*D) || 229 isa<ObjCImplementationDecl>(*D) || 230 isa<ObjCInterfaceDecl>(*D) || 231 isa<ObjCProtocolDecl>(*D) || 232 isa<ObjCCategoryImplDecl>(*D) || 233 isa<ObjCCategoryDecl>(*D)) 234 Terminator = 0; 235 else if (isa<EnumConstantDecl>(*D)) { 236 DeclContext::decl_iterator Next = D; 237 ++Next; 238 if (Next != DEnd) 239 Terminator = ","; 240 } else 241 Terminator = ";"; 242 243 if (Terminator) 244 Out << Terminator; 245 Out << "\n"; 246 } 247 248 if (!Decls.empty()) 249 ProcessDeclGroup(Decls); 250 251 if (Indent) 252 Indentation -= Policy.Indentation; 253} 254 255void DeclPrinter::VisitTranslationUnitDecl(TranslationUnitDecl *D) { 256 VisitDeclContext(D, false); 257} 258 259void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) { 260 std::string S = D->getNameAsString(); 261 D->getUnderlyingType().getAsStringInternal(S, Policy); 262 if (!Policy.SuppressSpecifiers) 263 Out << "typedef "; 264 Out << S; 265} 266 267void DeclPrinter::VisitEnumDecl(EnumDecl *D) { 268 Out << "enum " << D->getNameAsString() << " {\n"; 269 VisitDeclContext(D); 270 Indent() << "}"; 271} 272 273void DeclPrinter::VisitRecordDecl(RecordDecl *D) { 274 Out << D->getKindName(); 275 if (D->getIdentifier()) { 276 Out << " "; 277 Out << D->getNameAsString(); 278 } 279 280 if (D->isDefinition()) { 281 Out << " {\n"; 282 VisitDeclContext(D); 283 Indent() << "}"; 284 } 285} 286 287void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) { 288 Out << D->getNameAsString(); 289 if (Expr *Init = D->getInitExpr()) { 290 Out << " = "; 291 Init->printPretty(Out, Context, 0, Policy, Indentation); 292 } 293} 294 295void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { 296 if (!Policy.SuppressSpecifiers) { 297 switch (D->getStorageClass()) { 298 case FunctionDecl::None: break; 299 case FunctionDecl::Extern: Out << "extern "; break; 300 case FunctionDecl::Static: Out << "static "; break; 301 case FunctionDecl::PrivateExtern: Out << "__private_extern__ "; break; 302 } 303 304 if (D->isInline()) Out << "inline "; 305 if (D->isVirtualAsWritten()) Out << "virtual "; 306 } 307 308 PrintingPolicy SubPolicy(Policy); 309 SubPolicy.SuppressSpecifiers = false; 310 std::string Proto = D->getNameAsString(); 311 if (isa<FunctionType>(D->getType().getTypePtr())) { 312 const FunctionType *AFT = D->getType()->getAsFunctionType(); 313 314 const FunctionProtoType *FT = 0; 315 if (D->hasWrittenPrototype()) 316 FT = dyn_cast<FunctionProtoType>(AFT); 317 318 Proto += "("; 319 if (FT) { 320 llvm::raw_string_ostream POut(Proto); 321 DeclPrinter ParamPrinter(POut, Context, SubPolicy, Indentation); 322 for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) { 323 if (i) POut << ", "; 324 ParamPrinter.VisitParmVarDecl(D->getParamDecl(i)); 325 } 326 327 if (FT->isVariadic()) { 328 if (D->getNumParams()) POut << ", "; 329 POut << "..."; 330 } 331 } else if (D->isThisDeclarationADefinition() && !D->hasPrototype()) { 332 for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) { 333 if (i) 334 Proto += ", "; 335 Proto += D->getParamDecl(i)->getNameAsString(); 336 } 337 } 338 339 Proto += ")"; 340 AFT->getResultType().getAsStringInternal(Proto, Policy); 341 } else { 342 D->getType().getAsStringInternal(Proto, Policy); 343 } 344 345 Out << Proto; 346 347 if (D->isPure()) 348 Out << " = 0"; 349 else if (D->isDeleted()) 350 Out << " = delete"; 351 else if (D->isThisDeclarationADefinition()) { 352 if (!D->hasPrototype() && D->getNumParams()) { 353 // This is a K&R function definition, so we need to print the 354 // parameters. 355 Out << '\n'; 356 DeclPrinter ParamPrinter(Out, Context, SubPolicy, Indentation); 357 Indentation += Policy.Indentation; 358 for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) { 359 Indent(); 360 ParamPrinter.VisitParmVarDecl(D->getParamDecl(i)); 361 Out << ";\n"; 362 } 363 Indentation -= Policy.Indentation; 364 } else 365 Out << ' '; 366 367 D->getBody(Context)->printPretty(Out, Context, 0, SubPolicy, Indentation); 368 Out << '\n'; 369 } 370} 371 372void DeclPrinter::VisitFieldDecl(FieldDecl *D) { 373 if (!Policy.SuppressSpecifiers && D->isMutable()) 374 Out << "mutable "; 375 376 std::string Name = D->getNameAsString(); 377 D->getType().getAsStringInternal(Name, Policy); 378 Out << Name; 379 380 if (D->isBitField()) { 381 Out << " : "; 382 D->getBitWidth()->printPretty(Out, Context, 0, Policy, Indentation); 383 } 384} 385 386void DeclPrinter::VisitVarDecl(VarDecl *D) { 387 if (!Policy.SuppressSpecifiers && D->getStorageClass() != VarDecl::None) 388 Out << VarDecl::getStorageClassSpecifierString(D->getStorageClass()) << " "; 389 390 if (!Policy.SuppressSpecifiers && D->isThreadSpecified()) 391 Out << "__thread "; 392 393 std::string Name = D->getNameAsString(); 394 QualType T = D->getType(); 395 if (OriginalParmVarDecl *Parm = dyn_cast<OriginalParmVarDecl>(D)) 396 T = Parm->getOriginalType(); 397 T.getAsStringInternal(Name, Policy); 398 Out << Name; 399 if (D->getInit()) { 400 if (D->hasCXXDirectInitializer()) 401 Out << "("; 402 else 403 Out << " = "; 404 D->getInit()->printPretty(Out, Context, 0, Policy, Indentation); 405 if (D->hasCXXDirectInitializer()) 406 Out << ")"; 407 } 408} 409 410void DeclPrinter::VisitParmVarDecl(ParmVarDecl *D) { 411 VisitVarDecl(D); 412} 413 414void DeclPrinter::VisitOriginalParmVarDecl(OriginalParmVarDecl *D) { 415 VisitVarDecl(D); 416} 417 418void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { 419 Out << "__asm ("; 420 D->getAsmString()->printPretty(Out, Context, 0, Policy, Indentation); 421 Out << ")"; 422} 423 424//---------------------------------------------------------------------------- 425// C++ declarations 426//---------------------------------------------------------------------------- 427void DeclPrinter::VisitOverloadedFunctionDecl(OverloadedFunctionDecl *D) { 428 assert(false && 429 "OverloadedFunctionDecls aren't really decls and are never printed"); 430} 431 432void DeclPrinter::VisitNamespaceDecl(NamespaceDecl *D) { 433 Out << "namespace " << D->getNameAsString() << " {\n"; 434 VisitDeclContext(D); 435 Indent() << "}"; 436} 437 438void DeclPrinter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { 439 Out << "using namespace "; 440 if (D->getQualifier()) 441 D->getQualifier()->print(Out, Policy); 442 Out << D->getNominatedNamespace()->getNameAsString(); 443} 444 445void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { 446 Out << "namespace " << D->getNameAsString() << " = "; 447 if (D->getQualifier()) 448 D->getQualifier()->print(Out, Policy); 449 Out << D->getAliasedNamespace()->getNameAsString(); 450} 451 452void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { 453 Out << D->getKindName(); 454 if (D->getIdentifier()) { 455 Out << " "; 456 Out << D->getNameAsString(); 457 } 458 459 if (D->isDefinition()) { 460 // Print the base classes 461 if (D->getNumBases()) { 462 Out << " : "; 463 for(CXXRecordDecl::base_class_iterator Base = D->bases_begin(), 464 BaseEnd = D->bases_end(); 465 Base != BaseEnd; ++Base) { 466 if (Base != D->bases_begin()) 467 Out << ", "; 468 469 if (Base->isVirtual()) 470 Out << "virtual "; 471 472 switch(Base->getAccessSpecifierAsWritten()) { 473 case AS_none: break; 474 case AS_public: Out << "public "; break; 475 case AS_protected: Out << "protected "; break; 476 case AS_private: Out << " private "; break; 477 } 478 479 Out << Base->getType().getAsString(Policy); 480 } 481 } 482 483 // Print the class definition 484 // FIXME: Doesn't print access specifiers, e.g., "public:" 485 Out << " {\n"; 486 VisitDeclContext(D); 487 Indent() << "}"; 488 } 489} 490 491void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { 492 const char *l; 493 if (D->getLanguage() == LinkageSpecDecl::lang_c) 494 l = "C"; 495 else { 496 assert(D->getLanguage() == LinkageSpecDecl::lang_cxx && 497 "unknown language in linkage specification"); 498 l = "C++"; 499 } 500 501 Out << "extern \"" << l << "\" "; 502 if (D->hasBraces()) { 503 Out << "{\n"; 504 VisitDeclContext(D); 505 Indent() << "}"; 506 } else 507 Visit(*D->decls_begin(Context)); 508} 509 510void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) { 511 // TODO: Write template parameters. 512 Out << "template <...> "; 513 Visit(D->getTemplatedDecl()); 514} 515 516//---------------------------------------------------------------------------- 517// Objective-C declarations 518//---------------------------------------------------------------------------- 519 520void DeclPrinter::VisitObjCClassDecl(ObjCClassDecl *D) { 521 Out << "@class "; 522 for (ObjCClassDecl::iterator I = D->begin(), E = D->end(); 523 I != E; ++I) { 524 if (I != D->begin()) Out << ", "; 525 Out << (*I)->getNameAsString(); 526 } 527} 528 529void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) { 530 if (OMD->isInstanceMethod()) 531 Out << "- "; 532 else 533 Out << "+ "; 534 if (!OMD->getResultType().isNull()) 535 Out << '(' << OMD->getResultType().getAsString(Policy) << ")"; 536 537 std::string name = OMD->getSelector().getAsString(); 538 std::string::size_type pos, lastPos = 0; 539 for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(), 540 E = OMD->param_end(); PI != E; ++PI) { 541 // FIXME: selector is missing here! 542 pos = name.find_first_of(":", lastPos); 543 Out << " " << name.substr(lastPos, pos - lastPos); 544 Out << ":(" << (*PI)->getType().getAsString(Policy) << ")" 545 << (*PI)->getNameAsString(); 546 lastPos = pos + 1; 547 } 548 549 if (OMD->param_begin() == OMD->param_end()) 550 Out << " " << name; 551 552 if (OMD->isVariadic()) 553 Out << ", ..."; 554 555 if (OMD->getBody()) { 556 Out << ' '; 557 OMD->getBody()->printPretty(Out, Context, 0, Policy); 558 Out << '\n'; 559 } 560} 561 562void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) { 563 std::string I = OID->getNameAsString(); 564 ObjCInterfaceDecl *SID = OID->getSuperClass(); 565 566 if (SID) 567 Out << "@implementation " << I << " : " << SID->getNameAsString(); 568 else 569 Out << "@implementation " << I; 570 Out << "\n"; 571 VisitDeclContext(OID, false); 572 Out << "@end"; 573} 574 575void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { 576 std::string I = OID->getNameAsString(); 577 ObjCInterfaceDecl *SID = OID->getSuperClass(); 578 579 if (SID) 580 Out << "@interface " << I << " : " << SID->getNameAsString(); 581 else 582 Out << "@interface " << I; 583 584 // Protocols? 585 const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols(); 586 if (!Protocols.empty()) { 587 for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), 588 E = Protocols.end(); I != E; ++I) 589 Out << (I == Protocols.begin() ? '<' : ',') << (*I)->getNameAsString(); 590 } 591 592 if (!Protocols.empty()) 593 Out << "> "; 594 595 if (OID->ivar_size() > 0) { 596 Out << "{\n"; 597 Indentation += Policy.Indentation; 598 for (ObjCInterfaceDecl::ivar_iterator I = OID->ivar_begin(), 599 E = OID->ivar_end(); I != E; ++I) { 600 Indent() << (*I)->getType().getAsString(Policy) 601 << ' ' << (*I)->getNameAsString() << ";\n"; 602 } 603 Indentation -= Policy.Indentation; 604 Out << "}\n"; 605 } 606 607 VisitDeclContext(OID, false); 608 Out << "@end"; 609 // FIXME: implement the rest... 610} 611 612void DeclPrinter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) { 613 Out << "@protocol "; 614 for (ObjCForwardProtocolDecl::protocol_iterator I = D->protocol_begin(), 615 E = D->protocol_end(); 616 I != E; ++I) { 617 if (I != D->protocol_begin()) Out << ", "; 618 Out << (*I)->getNameAsString(); 619 } 620} 621 622void DeclPrinter::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) { 623 Out << "@protocol " << PID->getNameAsString() << '\n'; 624 VisitDeclContext(PID, false); 625 Out << "@end"; 626} 627 628void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) { 629 Out << "@implementation " 630 << PID->getClassInterface()->getNameAsString() 631 << '(' << PID->getNameAsString() << ")\n"; 632 633 VisitDeclContext(PID, false); 634 Out << "@end"; 635 // FIXME: implement the rest... 636} 637 638void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) { 639 Out << "@interface " 640 << PID->getClassInterface()->getNameAsString() 641 << '(' << PID->getNameAsString() << ")\n"; 642 VisitDeclContext(PID, false); 643 Out << "@end"; 644 645 // FIXME: implement the rest... 646} 647 648void DeclPrinter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID) { 649 Out << "@compatibility_alias " << AID->getNameAsString() 650 << ' ' << AID->getClassInterface()->getNameAsString() << ";\n"; 651} 652 653/// PrintObjCPropertyDecl - print a property declaration. 654/// 655void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) { 656 if (PDecl->getPropertyImplementation() == ObjCPropertyDecl::Required) 657 Out << "@required\n"; 658 else if (PDecl->getPropertyImplementation() == ObjCPropertyDecl::Optional) 659 Out << "@optional\n"; 660 661 Out << "@property"; 662 if (PDecl->getPropertyAttributes() != ObjCPropertyDecl::OBJC_PR_noattr) { 663 bool first = true; 664 Out << " ("; 665 if (PDecl->getPropertyAttributes() & 666 ObjCPropertyDecl::OBJC_PR_readonly) { 667 Out << (first ? ' ' : ',') << "readonly"; 668 first = false; 669 } 670 671 if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_getter) { 672 Out << (first ? ' ' : ',') << "getter = " 673 << PDecl->getGetterName().getAsString(); 674 first = false; 675 } 676 if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter) { 677 Out << (first ? ' ' : ',') << "setter = " 678 << PDecl->getSetterName().getAsString(); 679 first = false; 680 } 681 682 if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_assign) { 683 Out << (first ? ' ' : ',') << "assign"; 684 first = false; 685 } 686 687 if (PDecl->getPropertyAttributes() & 688 ObjCPropertyDecl::OBJC_PR_readwrite) { 689 Out << (first ? ' ' : ',') << "readwrite"; 690 first = false; 691 } 692 693 if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_retain) { 694 Out << (first ? ' ' : ',') << "retain"; 695 first = false; 696 } 697 698 if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_copy) { 699 Out << (first ? ' ' : ',') << "copy"; 700 first = false; 701 } 702 703 if (PDecl->getPropertyAttributes() & 704 ObjCPropertyDecl::OBJC_PR_nonatomic) { 705 Out << (first ? ' ' : ',') << "nonatomic"; 706 first = false; 707 } 708 Out << " )"; 709 } 710 Out << ' ' << PDecl->getType().getAsString(Policy) 711 << ' ' << PDecl->getNameAsString(); 712} 713 714void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) { 715 if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) 716 Out << "@synthesize "; 717 else 718 Out << "@dynamic "; 719 Out << PID->getPropertyDecl()->getNameAsString(); 720 if (PID->getPropertyIvarDecl()) 721 Out << "=" << PID->getPropertyIvarDecl()->getNameAsString(); 722} 723