DeclPrinter.cpp revision 4fe0c8e9c76b96e7aff21696a40dacc09d0237bc
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 36 public: 37 DeclPrinter(llvm::raw_ostream &Out, ASTContext &Context, 38 const PrintingPolicy &Policy, 39 unsigned Indentation = 0) 40 : Out(Out), Context(Context), Policy(Policy), Indentation(Indentation) { } 41 42 void VisitDeclContext(DeclContext *DC, bool Indent = true); 43 44 void VisitTranslationUnitDecl(TranslationUnitDecl *D); 45 void VisitTypedefDecl(TypedefDecl *D); 46 void VisitEnumDecl(EnumDecl *D); 47 void VisitRecordDecl(RecordDecl *D); 48 void VisitEnumConstantDecl(EnumConstantDecl *D); 49 void VisitFunctionDecl(FunctionDecl *D); 50 void VisitFieldDecl(FieldDecl *D); 51 void VisitVarDecl(VarDecl *D); 52 void VisitParmVarDecl(ParmVarDecl *D); 53 void VisitFileScopeAsmDecl(FileScopeAsmDecl *D); 54 void VisitNamespaceDecl(NamespaceDecl *D); 55 void VisitLinkageSpecDecl(LinkageSpecDecl *D); 56 void VisitTemplateDecl(TemplateDecl *D); 57 void VisitObjCClassDecl(ObjCClassDecl *D); 58 void VisitObjCMethodDecl(ObjCMethodDecl *D); 59 void VisitObjCImplementationDecl(ObjCImplementationDecl *D); 60 void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); 61 void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D); 62 void VisitObjCProtocolDecl(ObjCProtocolDecl *D); 63 void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); 64 void VisitObjCCategoryDecl(ObjCCategoryDecl *D); 65 void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D); 66 void VisitObjCPropertyDecl(ObjCPropertyDecl *D); 67 void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); 68 }; 69} 70 71void Decl::print(llvm::raw_ostream &Out, ASTContext &Context, 72 unsigned Indentation) { 73 print(Out, Context, Context.PrintingPolicy, Indentation); 74} 75 76void Decl::print(llvm::raw_ostream &Out, ASTContext &Context, 77 const PrintingPolicy &Policy, unsigned Indentation) { 78 DeclPrinter Printer(Out, Context, Policy, Indentation); 79 Printer.Visit(this); 80} 81 82void Decl::dump(ASTContext &Context) { 83 print(llvm::errs(), Context); 84} 85 86llvm::raw_ostream& DeclPrinter::Indent() { 87 for (unsigned i = 0; i < Indentation; ++i) 88 Out << " "; 89 return Out; 90} 91 92//---------------------------------------------------------------------------- 93// Common C declarations 94//---------------------------------------------------------------------------- 95 96void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { 97 if (Indent) 98 Indentation += Policy.Indentation; 99 100 for (DeclContext::decl_iterator D = DC->decls_begin(Context), 101 DEnd = DC->decls_end(Context); 102 D != DEnd; ++D) { 103 this->Indent(); 104 Visit(*D); 105 106 // FIXME: Need to be able to tell the DeclPrinter when 107 const char *Terminator = 0; 108 if (isa<FunctionDecl>(*D) && 109 cast<FunctionDecl>(*D)->isThisDeclarationADefinition()) 110 Terminator = 0; 111 else if (isa<NamespaceDecl>(*D) || isa<LinkageSpecDecl>(*D)) 112 Terminator = 0; 113 else if (isa<EnumConstantDecl>(*D)) { 114 DeclContext::decl_iterator Next = D; 115 ++Next; 116 if (Next != DEnd) 117 Terminator = ","; 118 } else 119 Terminator = ";"; 120 121 if (Terminator) 122 Out << Terminator; 123 Out << "\n"; 124 } 125 126 if (Indent) 127 Indentation -= Policy.Indentation; 128} 129 130void DeclPrinter::VisitTranslationUnitDecl(TranslationUnitDecl *D) { 131 VisitDeclContext(D, false); 132} 133 134void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) { 135 std::string S = D->getNameAsString(); 136 D->getUnderlyingType().getAsStringInternal(S, Policy); 137 Out << "typedef " << S; 138} 139 140void DeclPrinter::VisitEnumDecl(EnumDecl *D) { 141 Out << "enum " << D->getNameAsString() << " {\n"; 142 VisitDeclContext(D); 143 Indent() << "}"; 144} 145 146void DeclPrinter::VisitRecordDecl(RecordDecl *D) { 147 // print a free standing tag decl (e.g. "struct x;"). 148 Out << D->getKindName(); 149 Out << " "; 150 Out << D->getNameAsString(); 151 152 if (D->isDefinition()) { 153 Out << " {\n"; 154 VisitDeclContext(D); 155 Indent() << "}"; 156 } 157} 158 159void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) { 160 Out << D->getNameAsString(); 161 if (Expr *Init = D->getInitExpr()) { 162 Out << " = "; 163 Init->printPretty(Out, 0, Policy, Indentation); 164 } 165} 166 167void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { 168 switch (D->getStorageClass()) { 169 case FunctionDecl::None: break; 170 case FunctionDecl::Extern: Out << "extern "; break; 171 case FunctionDecl::Static: Out << "static "; break; 172 case FunctionDecl::PrivateExtern: Out << "__private_extern__ "; break; 173 } 174 175 if (D->isInline()) Out << "inline "; 176 if (D->isVirtualAsWritten()) Out << "virtual "; 177 178 std::string Proto = D->getNameAsString(); 179 if (isa<FunctionType>(D->getType().getTypePtr())) { 180 const FunctionType *AFT = D->getType()->getAsFunctionType(); 181 182 const FunctionProtoType *FT = 0; 183 if (D->hasWrittenPrototype()) 184 FT = dyn_cast<FunctionProtoType>(AFT); 185 186 Proto += "("; 187 if (FT) { 188 llvm::raw_string_ostream POut(Proto); 189 DeclPrinter ParamPrinter(POut, Context, Policy, Indentation); 190 for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) { 191 if (i) POut << ", "; 192 ParamPrinter.VisitParmVarDecl(D->getParamDecl(i)); 193 } 194 195 if (FT->isVariadic()) { 196 if (D->getNumParams()) POut << ", "; 197 POut << "..."; 198 } 199 } 200 201 Proto += ")"; 202 AFT->getResultType().getAsStringInternal(Proto, Policy); 203 } else { 204 D->getType().getAsStringInternal(Proto, Policy); 205 } 206 207 Out << Proto; 208 209 if (D->isPure()) 210 Out << " = 0"; 211 else if (D->isDeleted()) 212 Out << " = delete"; 213 else if (D->isThisDeclarationADefinition()) { 214 if (!D->hasPrototype() && D->getNumParams()) { 215 // This is a K&R function definition, so we need to print the 216 // parameters. 217 Out << '\n'; 218 Indentation += Policy.Indentation; 219 for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) { 220 Indent(); 221 VisitParmVarDecl(D->getParamDecl(i)); 222 Out << ";\n"; 223 } 224 Indentation -= Policy.Indentation; 225 } else 226 Out << ' '; 227 228 D->getBody(Context)->printPretty(Out, 0, Policy, Indentation); 229 Out << '\n'; 230 } 231} 232 233void DeclPrinter::VisitFieldDecl(FieldDecl *D) { 234 if (D->isMutable()) 235 Out << "mutable "; 236 237 std::string Name = D->getNameAsString(); 238 D->getType().getAsStringInternal(Name, Policy); 239 Out << Name; 240 241 if (D->isBitField()) { 242 Out << " : "; 243 D->getBitWidth()->printPretty(Out, 0, Policy, Indentation); 244 } 245} 246 247void DeclPrinter::VisitVarDecl(VarDecl *D) { 248 if (D->getStorageClass() != VarDecl::None) 249 Out << VarDecl::getStorageClassSpecifierString(D->getStorageClass()) << " "; 250 251 if (D->isThreadSpecified()) 252 Out << "__thread "; 253 254 std::string Name = D->getNameAsString(); 255 QualType T = D->getType(); 256 if (OriginalParmVarDecl *Parm = dyn_cast<OriginalParmVarDecl>(D)) 257 T = Parm->getOriginalType(); 258 T.getAsStringInternal(Name, Policy); 259 Out << Name; 260 if (D->getInit()) { 261 if (D->hasCXXDirectInitializer()) 262 Out << "("; 263 else 264 Out << " = "; 265 D->getInit()->printPretty(Out, 0, Policy, Indentation); 266 if (D->hasCXXDirectInitializer()) 267 Out << ")"; 268 } 269} 270 271void DeclPrinter::VisitParmVarDecl(ParmVarDecl *D) { 272 VisitVarDecl(D); 273} 274 275void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { 276 Out << "__asm ("; 277 D->getAsmString()->printPretty(Out, 0, Policy, Indentation); 278 Out << ")"; 279} 280 281//---------------------------------------------------------------------------- 282// C++ declarations 283//---------------------------------------------------------------------------- 284void DeclPrinter::VisitNamespaceDecl(NamespaceDecl *D) { 285 Out << "namespace " << D->getNameAsString() << " {\n"; 286 VisitDeclContext(D); 287 Indent() << "}"; 288} 289 290void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { 291 const char *l; 292 if (D->getLanguage() == LinkageSpecDecl::lang_c) 293 l = "C"; 294 else { 295 assert(D->getLanguage() == LinkageSpecDecl::lang_cxx && 296 "unknown language in linkage specification"); 297 l = "C++"; 298 } 299 300 Out << "extern \"" << l << "\" "; 301 if (D->hasBraces()) { 302 Out << "{\n"; 303 VisitDeclContext(D); 304 Indent() << "}"; 305 } else 306 Visit(*D->decls_begin(Context)); 307} 308 309void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) { 310 // TODO: Write template parameters. 311 Out << "template <...> "; 312 Visit(D->getTemplatedDecl()); 313} 314 315//---------------------------------------------------------------------------- 316// Objective-C declarations 317//---------------------------------------------------------------------------- 318 319void DeclPrinter::VisitObjCClassDecl(ObjCClassDecl *D) { 320 Out << "@class "; 321 for (ObjCClassDecl::iterator I = D->begin(), E = D->end(); 322 I != E; ++I) { 323 if (I != D->begin()) Out << ", "; 324 Out << (*I)->getNameAsString(); 325 } 326 Out << ";\n"; 327} 328 329void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) { 330 if (OMD->isInstanceMethod()) 331 Out << "\n- "; 332 else 333 Out << "\n+ "; 334 if (!OMD->getResultType().isNull()) 335 Out << '(' << OMD->getResultType().getAsString() << ")"; 336 337 std::string name = OMD->getSelector().getAsString(); 338 std::string::size_type pos, lastPos = 0; 339 for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(), 340 E = OMD->param_end(); PI != E; ++PI) { 341 // FIXME: selector is missing here! 342 pos = name.find_first_of(":", lastPos); 343 Out << " " << name.substr(lastPos, pos - lastPos); 344 Out << ":(" << (*PI)->getType().getAsString() << ")" 345 << (*PI)->getNameAsString(); 346 lastPos = pos + 1; 347 } 348 349 if (OMD->param_begin() == OMD->param_end()) 350 Out << " " << name; 351 352 if (OMD->isVariadic()) 353 Out << ", ..."; 354 355 if (OMD->getBody()) { 356 Out << ' '; 357 OMD->getBody()->printPretty(Out, 0, Policy); 358 Out << '\n'; 359 } else 360 Out << ";"; 361} 362 363void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) { 364 std::string I = OID->getNameAsString(); 365 ObjCInterfaceDecl *SID = OID->getSuperClass(); 366 367 if (SID) 368 Out << "@implementation " << I << " : " << SID->getNameAsString(); 369 else 370 Out << "@implementation " << I; 371 372 VisitDeclContext(OID); 373 Out << "@end\n"; 374} 375 376void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { 377 std::string I = OID->getNameAsString(); 378 ObjCInterfaceDecl *SID = OID->getSuperClass(); 379 380 if (SID) 381 Out << "@interface " << I << " : " << SID->getNameAsString(); 382 else 383 Out << "@interface " << I; 384 385 // Protocols? 386 const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols(); 387 if (!Protocols.empty()) { 388 for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), 389 E = Protocols.end(); I != E; ++I) 390 Out << (I == Protocols.begin() ? '<' : ',') << (*I)->getNameAsString(); 391 } 392 393 if (!Protocols.empty()) 394 Out << ">"; 395 Out << '\n'; 396 397 if (OID->ivar_size() > 0) { 398 Out << '{'; 399 for (ObjCInterfaceDecl::ivar_iterator I = OID->ivar_begin(), 400 E = OID->ivar_end(); I != E; ++I) { 401 Out << '\t' << (*I)->getType().getAsString(Policy) 402 << ' ' << (*I)->getNameAsString() << ";\n"; 403 } 404 Out << "}\n"; 405 } 406 407 VisitDeclContext(OID, false); 408 Out << "@end\n"; 409 // FIXME: implement the rest... 410} 411 412void DeclPrinter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) { 413 Out << "@protocol "; 414 for (ObjCForwardProtocolDecl::protocol_iterator I = D->protocol_begin(), 415 E = D->protocol_end(); 416 I != E; ++I) { 417 if (I != D->protocol_begin()) Out << ", "; 418 Out << (*I)->getNameAsString(); 419 } 420 Out << ";\n"; 421} 422 423void DeclPrinter::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) { 424 Out << "@protocol " << PID->getNameAsString() << '\n'; 425 426 for (ObjCProtocolDecl::prop_iterator I = PID->prop_begin(Context), 427 E = PID->prop_end(Context); I != E; ++I) 428 VisitObjCPropertyDecl(*I); 429 Out << "@end\n"; 430 // FIXME: implement the rest... 431} 432 433void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) { 434 Out << "@implementation " 435 << PID->getClassInterface()->getNameAsString() 436 << '(' << PID->getNameAsString() << ");\n"; 437 438 VisitDeclContext(PID, false); 439 Out << "@end\n"; 440 // FIXME: implement the rest... 441} 442 443void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) { 444 Out << "@interface " 445 << PID->getClassInterface()->getNameAsString() 446 << '(' << PID->getNameAsString() << ");\n"; 447 VisitDeclContext(PID, false); 448 Out << "@end\n"; 449 450 // FIXME: implement the rest... 451} 452 453void DeclPrinter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID) { 454 Out << "@compatibility_alias " << AID->getNameAsString() 455 << ' ' << AID->getClassInterface()->getNameAsString() << ";\n"; 456} 457 458/// PrintObjCPropertyDecl - print a property declaration. 459/// 460void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) { 461 if (PDecl->getPropertyImplementation() == ObjCPropertyDecl::Required) 462 Out << "@required\n"; 463 else if (PDecl->getPropertyImplementation() == ObjCPropertyDecl::Optional) 464 Out << "@optional\n"; 465 466 Out << "@property"; 467 if (PDecl->getPropertyAttributes() != ObjCPropertyDecl::OBJC_PR_noattr) { 468 bool first = true; 469 Out << " ("; 470 if (PDecl->getPropertyAttributes() & 471 ObjCPropertyDecl::OBJC_PR_readonly) { 472 Out << (first ? ' ' : ',') << "readonly"; 473 first = false; 474 } 475 476 if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_getter) { 477 Out << (first ? ' ' : ',') << "getter = " 478 << PDecl->getGetterName().getAsString(); 479 first = false; 480 } 481 if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter) { 482 Out << (first ? ' ' : ',') << "setter = " 483 << PDecl->getSetterName().getAsString(); 484 first = false; 485 } 486 487 if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_assign) { 488 Out << (first ? ' ' : ',') << "assign"; 489 first = false; 490 } 491 492 if (PDecl->getPropertyAttributes() & 493 ObjCPropertyDecl::OBJC_PR_readwrite) { 494 Out << (first ? ' ' : ',') << "readwrite"; 495 first = false; 496 } 497 498 if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_retain) { 499 Out << (first ? ' ' : ',') << "retain"; 500 first = false; 501 } 502 503 if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_copy) { 504 Out << (first ? ' ' : ',') << "copy"; 505 first = false; 506 } 507 508 if (PDecl->getPropertyAttributes() & 509 ObjCPropertyDecl::OBJC_PR_nonatomic) { 510 Out << (first ? ' ' : ',') << "nonatomic"; 511 first = false; 512 } 513 Out << " )"; 514 } 515 Out << ' ' << PDecl->getType().getAsString(Policy) 516 << ' ' << PDecl->getNameAsString(); 517 518 Out << ";\n"; 519} 520 521void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) { 522 if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) 523 Out << "\n@synthesize "; 524 else 525 Out << "\n@dynamic "; 526 Out << PID->getPropertyDecl()->getNameAsString(); 527 if (PID->getPropertyIvarDecl()) 528 Out << "=" << PID->getPropertyIvarDecl()->getNameAsString(); 529 Out << ";\n"; 530} 531