ObjCMT.cpp revision d33884f1e2e3189ee2db75cc72d90ea854f6bc68
1//===--- ObjCMT.cpp - ObjC Migrate Tool -----------------------------------===// 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#include "Transforms.h" 11#include "clang/ARCMigrate/ARCMTActions.h" 12#include "clang/AST/ASTConsumer.h" 13#include "clang/AST/ASTContext.h" 14#include "clang/AST/NSAPI.h" 15#include "clang/AST/ParentMap.h" 16#include "clang/AST/RecursiveASTVisitor.h" 17#include "clang/Basic/FileManager.h" 18#include "clang/Edit/Commit.h" 19#include "clang/Edit/EditedSource.h" 20#include "clang/Edit/EditsReceiver.h" 21#include "clang/Edit/Rewriters.h" 22#include "clang/Frontend/CompilerInstance.h" 23#include "clang/Frontend/MultiplexConsumer.h" 24#include "clang/Lex/PPConditionalDirectiveRecord.h" 25#include "clang/Lex/Preprocessor.h" 26#include "clang/Rewrite/Core/Rewriter.h" 27#include "clang/Analysis/DomainSpecific/CocoaConventions.h" 28#include "clang/StaticAnalyzer/Checkers/ObjCRetainCount.h" 29#include "clang/AST/Attr.h" 30#include "llvm/ADT/SmallString.h" 31 32using namespace clang; 33using namespace arcmt; 34using namespace ento::objc_retain; 35 36namespace { 37 38class ObjCMigrateASTConsumer : public ASTConsumer { 39 enum CF_BRIDGING_KIND { 40 CF_BRIDGING_NONE, 41 CF_BRIDGING_ENABLE, 42 CF_BRIDGING_MAY_INCLUDE 43 }; 44 45 void migrateDecl(Decl *D); 46 void migrateObjCInterfaceDecl(ASTContext &Ctx, ObjCContainerDecl *D); 47 void migrateProtocolConformance(ASTContext &Ctx, 48 const ObjCImplementationDecl *ImpDecl); 49 void CacheObjCNSIntegerTypedefed(const TypedefDecl *TypedefDcl); 50 bool migrateNSEnumDecl(ASTContext &Ctx, const EnumDecl *EnumDcl, 51 const TypedefDecl *TypedefDcl); 52 void migrateAllMethodInstaceType(ASTContext &Ctx, ObjCContainerDecl *CDecl); 53 void migrateMethodInstanceType(ASTContext &Ctx, ObjCContainerDecl *CDecl, 54 ObjCMethodDecl *OM); 55 bool migrateProperty(ASTContext &Ctx, ObjCContainerDecl *D, ObjCMethodDecl *OM); 56 void migrateNsReturnsInnerPointer(ASTContext &Ctx, ObjCMethodDecl *OM); 57 void migratePropertyNsReturnsInnerPointer(ASTContext &Ctx, ObjCPropertyDecl *P); 58 void migrateFactoryMethod(ASTContext &Ctx, ObjCContainerDecl *CDecl, 59 ObjCMethodDecl *OM, 60 ObjCInstanceTypeFamily OIT_Family = OIT_None); 61 62 void migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl); 63 void AddCFAnnotations(ASTContext &Ctx, const CallEffects &CE, 64 const FunctionDecl *FuncDecl, bool ResultAnnotated); 65 void AddCFAnnotations(ASTContext &Ctx, const CallEffects &CE, 66 const ObjCMethodDecl *MethodDecl, bool ResultAnnotated); 67 68 void AnnotateImplicitBridging(ASTContext &Ctx); 69 70 CF_BRIDGING_KIND migrateAddFunctionAnnotation(ASTContext &Ctx, 71 const FunctionDecl *FuncDecl); 72 73 void migrateARCSafeAnnotation(ASTContext &Ctx, ObjCContainerDecl *CDecl); 74 75 void migrateAddMethodAnnotation(ASTContext &Ctx, 76 const ObjCMethodDecl *MethodDecl); 77public: 78 std::string MigrateDir; 79 unsigned ASTMigrateActions; 80 unsigned FileId; 81 const TypedefDecl *NSIntegerTypedefed; 82 const TypedefDecl *NSUIntegerTypedefed; 83 OwningPtr<NSAPI> NSAPIObj; 84 OwningPtr<edit::EditedSource> Editor; 85 FileRemapper &Remapper; 86 FileManager &FileMgr; 87 const PPConditionalDirectiveRecord *PPRec; 88 Preprocessor &PP; 89 bool IsOutputFile; 90 llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ObjCProtocolDecls; 91 llvm::SmallVector<const Decl *, 8> CFFunctionIBCandidates; 92 93 ObjCMigrateASTConsumer(StringRef migrateDir, 94 unsigned astMigrateActions, 95 FileRemapper &remapper, 96 FileManager &fileMgr, 97 const PPConditionalDirectiveRecord *PPRec, 98 Preprocessor &PP, 99 bool isOutputFile = false) 100 : MigrateDir(migrateDir), 101 ASTMigrateActions(astMigrateActions), 102 FileId(0), NSIntegerTypedefed(0), NSUIntegerTypedefed(0), 103 Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec), PP(PP), 104 IsOutputFile(isOutputFile) { } 105 106protected: 107 virtual void Initialize(ASTContext &Context) { 108 NSAPIObj.reset(new NSAPI(Context)); 109 Editor.reset(new edit::EditedSource(Context.getSourceManager(), 110 Context.getLangOpts(), 111 PPRec, false)); 112 } 113 114 virtual bool HandleTopLevelDecl(DeclGroupRef DG) { 115 for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) 116 migrateDecl(*I); 117 return true; 118 } 119 virtual void HandleInterestingDecl(DeclGroupRef DG) { 120 // Ignore decls from the PCH. 121 } 122 virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) { 123 ObjCMigrateASTConsumer::HandleTopLevelDecl(DG); 124 } 125 126 virtual void HandleTranslationUnit(ASTContext &Ctx); 127}; 128 129} 130 131ObjCMigrateAction::ObjCMigrateAction(FrontendAction *WrappedAction, 132 StringRef migrateDir, 133 unsigned migrateAction) 134 : WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir), 135 ObjCMigAction(migrateAction), 136 CompInst(0) { 137 if (MigrateDir.empty()) 138 MigrateDir = "."; // user current directory if none is given. 139} 140 141ASTConsumer *ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI, 142 StringRef InFile) { 143 PPConditionalDirectiveRecord * 144 PPRec = new PPConditionalDirectiveRecord(CompInst->getSourceManager()); 145 CompInst->getPreprocessor().addPPCallbacks(PPRec); 146 ASTConsumer * 147 WrappedConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile); 148 ASTConsumer *MTConsumer = new ObjCMigrateASTConsumer(MigrateDir, 149 ObjCMigAction, 150 Remapper, 151 CompInst->getFileManager(), 152 PPRec, 153 CompInst->getPreprocessor()); 154 ASTConsumer *Consumers[] = { MTConsumer, WrappedConsumer }; 155 return new MultiplexConsumer(Consumers); 156} 157 158bool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) { 159 Remapper.initFromDisk(MigrateDir, CI.getDiagnostics(), 160 /*ignoreIfFilesChanges=*/true); 161 CompInst = &CI; 162 CI.getDiagnostics().setIgnoreAllWarnings(true); 163 return true; 164} 165 166namespace { 167class ObjCMigrator : public RecursiveASTVisitor<ObjCMigrator> { 168 ObjCMigrateASTConsumer &Consumer; 169 ParentMap &PMap; 170 171public: 172 ObjCMigrator(ObjCMigrateASTConsumer &consumer, ParentMap &PMap) 173 : Consumer(consumer), PMap(PMap) { } 174 175 bool shouldVisitTemplateInstantiations() const { return false; } 176 bool shouldWalkTypesOfTypeLocs() const { return false; } 177 178 bool VisitObjCMessageExpr(ObjCMessageExpr *E) { 179 if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_Literals) { 180 edit::Commit commit(*Consumer.Editor); 181 edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit, &PMap); 182 Consumer.Editor->commit(commit); 183 } 184 185 if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_Subscripting) { 186 edit::Commit commit(*Consumer.Editor); 187 edit::rewriteToObjCSubscriptSyntax(E, *Consumer.NSAPIObj, commit); 188 Consumer.Editor->commit(commit); 189 } 190 191 return true; 192 } 193 194 bool TraverseObjCMessageExpr(ObjCMessageExpr *E) { 195 // Do depth first; we want to rewrite the subexpressions first so that if 196 // we have to move expressions we will move them already rewritten. 197 for (Stmt::child_range range = E->children(); range; ++range) 198 if (!TraverseStmt(*range)) 199 return false; 200 201 return WalkUpFromObjCMessageExpr(E); 202 } 203}; 204 205class BodyMigrator : public RecursiveASTVisitor<BodyMigrator> { 206 ObjCMigrateASTConsumer &Consumer; 207 OwningPtr<ParentMap> PMap; 208 209public: 210 BodyMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { } 211 212 bool shouldVisitTemplateInstantiations() const { return false; } 213 bool shouldWalkTypesOfTypeLocs() const { return false; } 214 215 bool TraverseStmt(Stmt *S) { 216 PMap.reset(new ParentMap(S)); 217 ObjCMigrator(Consumer, *PMap).TraverseStmt(S); 218 return true; 219 } 220}; 221} 222 223void ObjCMigrateASTConsumer::migrateDecl(Decl *D) { 224 if (!D) 225 return; 226 if (isa<ObjCMethodDecl>(D)) 227 return; // Wait for the ObjC container declaration. 228 229 BodyMigrator(*this).TraverseDecl(D); 230} 231 232static void append_attr(std::string &PropertyString, const char *attr, 233 bool &LParenAdded) { 234 if (!LParenAdded) { 235 PropertyString += "("; 236 LParenAdded = true; 237 } 238 else 239 PropertyString += ", "; 240 PropertyString += attr; 241} 242 243static 244void MigrateBlockOrFunctionPointerTypeVariable(std::string & PropertyString, 245 const std::string& TypeString, 246 const char *name) { 247 const char *argPtr = TypeString.c_str(); 248 int paren = 0; 249 while (*argPtr) { 250 switch (*argPtr) { 251 case '(': 252 PropertyString += *argPtr; 253 paren++; 254 break; 255 case ')': 256 PropertyString += *argPtr; 257 paren--; 258 break; 259 case '^': 260 case '*': 261 PropertyString += (*argPtr); 262 if (paren == 1) { 263 PropertyString += name; 264 name = ""; 265 } 266 break; 267 default: 268 PropertyString += *argPtr; 269 break; 270 } 271 argPtr++; 272 } 273} 274 275 276static void rewriteToObjCProperty(const ObjCMethodDecl *Getter, 277 const ObjCMethodDecl *Setter, 278 const NSAPI &NS, edit::Commit &commit, 279 unsigned LengthOfPrefix, 280 bool Atomic) { 281 ASTContext &Context = NS.getASTContext(); 282 bool LParenAdded = false; 283 std::string PropertyString = "@property "; 284 if (!Atomic) { 285 PropertyString += "(nonatomic"; 286 LParenAdded = true; 287 } 288 289 std::string PropertyNameString = Getter->getNameAsString(); 290 StringRef PropertyName(PropertyNameString); 291 if (LengthOfPrefix > 0) { 292 if (!LParenAdded) { 293 PropertyString += "(getter="; 294 LParenAdded = true; 295 } 296 else 297 PropertyString += ", getter="; 298 PropertyString += PropertyNameString; 299 } 300 // Property with no setter may be suggested as a 'readonly' property. 301 if (!Setter) { 302 if (!LParenAdded) { 303 PropertyString += "(readonly"; 304 LParenAdded = true; 305 } 306 else 307 append_attr(PropertyString, "readonly", LParenAdded); 308 } 309 310 // Short circuit 'delegate' properties that contain the name "delegate" or 311 // "dataSource", or have exact name "target" to have 'assign' attribute. 312 if (PropertyName.equals("target") || 313 (PropertyName.find("delegate") != StringRef::npos) || 314 (PropertyName.find("dataSource") != StringRef::npos)) { 315 QualType QT = Getter->getResultType(); 316 if (!QT->isRealType()) 317 append_attr(PropertyString, "assign", LParenAdded); 318 } 319 else if (Setter) { 320 const ParmVarDecl *argDecl = *Setter->param_begin(); 321 QualType ArgType = Context.getCanonicalType(argDecl->getType()); 322 Qualifiers::ObjCLifetime propertyLifetime = ArgType.getObjCLifetime(); 323 bool RetainableObject = ArgType->isObjCRetainableType(); 324 if (RetainableObject && propertyLifetime == Qualifiers::OCL_Strong) { 325 if (const ObjCObjectPointerType *ObjPtrTy = 326 ArgType->getAs<ObjCObjectPointerType>()) { 327 ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface(); 328 if (IDecl && 329 IDecl->lookupNestedProtocol(&Context.Idents.get("NSCopying"))) 330 append_attr(PropertyString, "copy", LParenAdded); 331 else 332 append_attr(PropertyString, "retain", LParenAdded); 333 } 334 else if (ArgType->isBlockPointerType()) 335 append_attr(PropertyString, "copy", LParenAdded); 336 } else if (propertyLifetime == Qualifiers::OCL_Weak) 337 // TODO. More precise determination of 'weak' attribute requires 338 // looking into setter's implementation for backing weak ivar. 339 append_attr(PropertyString, "weak", LParenAdded); 340 else if (RetainableObject) 341 append_attr(PropertyString, 342 ArgType->isBlockPointerType() ? "copy" : "retain", LParenAdded); 343 } 344 if (LParenAdded) 345 PropertyString += ')'; 346 QualType RT = Getter->getResultType(); 347 if (!isa<TypedefType>(RT)) { 348 // strip off any ARC lifetime qualifier. 349 QualType CanResultTy = Context.getCanonicalType(RT); 350 if (CanResultTy.getQualifiers().hasObjCLifetime()) { 351 Qualifiers Qs = CanResultTy.getQualifiers(); 352 Qs.removeObjCLifetime(); 353 RT = Context.getQualifiedType(CanResultTy.getUnqualifiedType(), Qs); 354 } 355 } 356 PropertyString += " "; 357 PrintingPolicy SubPolicy(Context.getPrintingPolicy()); 358 SubPolicy.SuppressStrongLifetime = true; 359 SubPolicy.SuppressLifetimeQualifiers = true; 360 std::string TypeString = RT.getAsString(SubPolicy); 361 if (LengthOfPrefix > 0) { 362 // property name must strip off "is" and lower case the first character 363 // after that; e.g. isContinuous will become continuous. 364 StringRef PropertyNameStringRef(PropertyNameString); 365 PropertyNameStringRef = PropertyNameStringRef.drop_front(LengthOfPrefix); 366 PropertyNameString = PropertyNameStringRef; 367 bool NoLowering = (isUppercase(PropertyNameString[0]) && 368 PropertyNameString.size() > 1 && 369 isUppercase(PropertyNameString[1])); 370 if (!NoLowering) 371 PropertyNameString[0] = toLowercase(PropertyNameString[0]); 372 } 373 if (RT->isBlockPointerType() || RT->isFunctionPointerType()) 374 MigrateBlockOrFunctionPointerTypeVariable(PropertyString, 375 TypeString, 376 PropertyNameString.c_str()); 377 else { 378 char LastChar = TypeString[TypeString.size()-1]; 379 PropertyString += TypeString; 380 if (LastChar != '*') 381 PropertyString += ' '; 382 PropertyString += PropertyNameString; 383 } 384 SourceLocation StartGetterSelectorLoc = Getter->getSelectorStartLoc(); 385 Selector GetterSelector = Getter->getSelector(); 386 387 SourceLocation EndGetterSelectorLoc = 388 StartGetterSelectorLoc.getLocWithOffset(GetterSelector.getNameForSlot(0).size()); 389 commit.replace(CharSourceRange::getCharRange(Getter->getLocStart(), 390 EndGetterSelectorLoc), 391 PropertyString); 392 if (Setter) { 393 SourceLocation EndLoc = Setter->getDeclaratorEndLoc(); 394 // Get location past ';' 395 EndLoc = EndLoc.getLocWithOffset(1); 396 SourceLocation BeginOfSetterDclLoc = Setter->getLocStart(); 397 // FIXME. This assumes that setter decl; is immediately preceeded by eoln. 398 // It is trying to remove the setter method decl. line entirely. 399 BeginOfSetterDclLoc = BeginOfSetterDclLoc.getLocWithOffset(-1); 400 commit.remove(SourceRange(BeginOfSetterDclLoc, EndLoc)); 401 } 402} 403 404void ObjCMigrateASTConsumer::migrateObjCInterfaceDecl(ASTContext &Ctx, 405 ObjCContainerDecl *D) { 406 if (D->isDeprecated()) 407 return; 408 409 for (ObjCContainerDecl::method_iterator M = D->meth_begin(), MEnd = D->meth_end(); 410 M != MEnd; ++M) { 411 ObjCMethodDecl *Method = (*M); 412 if (Method->isDeprecated()) 413 continue; 414 migrateProperty(Ctx, D, Method); 415 if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) 416 migrateNsReturnsInnerPointer(Ctx, Method); 417 } 418 for (ObjCContainerDecl::prop_iterator P = D->prop_begin(), 419 E = D->prop_end(); P != E; ++P) { 420 ObjCPropertyDecl *Prop = *P; 421 if ((ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) && 422 !P->isDeprecated()) 423 migratePropertyNsReturnsInnerPointer(Ctx, Prop); 424 } 425} 426 427static bool 428ClassImplementsAllMethodsAndProperties(ASTContext &Ctx, 429 const ObjCImplementationDecl *ImpDecl, 430 const ObjCInterfaceDecl *IDecl, 431 ObjCProtocolDecl *Protocol) { 432 // In auto-synthesis, protocol properties are not synthesized. So, 433 // a conforming protocol must have its required properties declared 434 // in class interface. 435 bool HasAtleastOneRequiredProperty = false; 436 if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition()) 437 for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), 438 E = PDecl->prop_end(); P != E; ++P) { 439 ObjCPropertyDecl *Property = *P; 440 if (Property->getPropertyImplementation() == ObjCPropertyDecl::Optional) 441 continue; 442 HasAtleastOneRequiredProperty = true; 443 DeclContext::lookup_const_result R = IDecl->lookup(Property->getDeclName()); 444 if (R.size() == 0) { 445 // Relax the rule and look into class's implementation for a synthesize 446 // or dynamic declaration. Class is implementing a property coming from 447 // another protocol. This still makes the target protocol as conforming. 448 if (!ImpDecl->FindPropertyImplDecl( 449 Property->getDeclName().getAsIdentifierInfo())) 450 return false; 451 } 452 else if (ObjCPropertyDecl *ClassProperty = dyn_cast<ObjCPropertyDecl>(R[0])) { 453 if ((ClassProperty->getPropertyAttributes() 454 != Property->getPropertyAttributes()) || 455 !Ctx.hasSameType(ClassProperty->getType(), Property->getType())) 456 return false; 457 } 458 else 459 return false; 460 } 461 462 // At this point, all required properties in this protocol conform to those 463 // declared in the class. 464 // Check that class implements the required methods of the protocol too. 465 bool HasAtleastOneRequiredMethod = false; 466 if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition()) { 467 if (PDecl->meth_begin() == PDecl->meth_end()) 468 return HasAtleastOneRequiredProperty; 469 for (ObjCContainerDecl::method_iterator M = PDecl->meth_begin(), 470 MEnd = PDecl->meth_end(); M != MEnd; ++M) { 471 ObjCMethodDecl *MD = (*M); 472 if (MD->isImplicit()) 473 continue; 474 if (MD->getImplementationControl() == ObjCMethodDecl::Optional) 475 continue; 476 DeclContext::lookup_const_result R = ImpDecl->lookup(MD->getDeclName()); 477 if (R.size() == 0) 478 return false; 479 bool match = false; 480 HasAtleastOneRequiredMethod = true; 481 for (unsigned I = 0, N = R.size(); I != N; ++I) 482 if (ObjCMethodDecl *ImpMD = dyn_cast<ObjCMethodDecl>(R[0])) 483 if (Ctx.ObjCMethodsAreEqual(MD, ImpMD)) { 484 match = true; 485 break; 486 } 487 if (!match) 488 return false; 489 } 490 } 491 if (HasAtleastOneRequiredProperty || HasAtleastOneRequiredMethod) 492 return true; 493 return false; 494} 495 496static bool rewriteToObjCInterfaceDecl(const ObjCInterfaceDecl *IDecl, 497 llvm::SmallVectorImpl<ObjCProtocolDecl*> &ConformingProtocols, 498 const NSAPI &NS, edit::Commit &commit) { 499 const ObjCList<ObjCProtocolDecl> &Protocols = IDecl->getReferencedProtocols(); 500 std::string ClassString; 501 SourceLocation EndLoc = 502 IDecl->getSuperClass() ? IDecl->getSuperClassLoc() : IDecl->getLocation(); 503 504 if (Protocols.empty()) { 505 ClassString = '<'; 506 for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) { 507 ClassString += ConformingProtocols[i]->getNameAsString(); 508 if (i != (e-1)) 509 ClassString += ", "; 510 } 511 ClassString += "> "; 512 } 513 else { 514 ClassString = ", "; 515 for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) { 516 ClassString += ConformingProtocols[i]->getNameAsString(); 517 if (i != (e-1)) 518 ClassString += ", "; 519 } 520 ObjCInterfaceDecl::protocol_loc_iterator PL = IDecl->protocol_loc_end() - 1; 521 EndLoc = *PL; 522 } 523 524 commit.insertAfterToken(EndLoc, ClassString); 525 return true; 526} 527 528static bool rewriteToNSEnumDecl(const EnumDecl *EnumDcl, 529 const TypedefDecl *TypedefDcl, 530 const NSAPI &NS, edit::Commit &commit, 531 bool IsNSIntegerType, 532 bool NSOptions) { 533 std::string ClassString; 534 if (NSOptions) 535 ClassString = "typedef NS_OPTIONS(NSUInteger, "; 536 else 537 ClassString = 538 IsNSIntegerType ? "typedef NS_ENUM(NSInteger, " 539 : "typedef NS_ENUM(NSUInteger, "; 540 541 ClassString += TypedefDcl->getIdentifier()->getName(); 542 ClassString += ')'; 543 SourceRange R(EnumDcl->getLocStart(), EnumDcl->getLocStart()); 544 commit.replace(R, ClassString); 545 SourceLocation EndOfEnumDclLoc = EnumDcl->getLocEnd(); 546 EndOfEnumDclLoc = trans::findSemiAfterLocation(EndOfEnumDclLoc, 547 NS.getASTContext(), /*IsDecl*/true); 548 if (!EndOfEnumDclLoc.isInvalid()) { 549 SourceRange EnumDclRange(EnumDcl->getLocStart(), EndOfEnumDclLoc); 550 commit.insertFromRange(TypedefDcl->getLocStart(), EnumDclRange); 551 } 552 else 553 return false; 554 555 SourceLocation EndTypedefDclLoc = TypedefDcl->getLocEnd(); 556 EndTypedefDclLoc = trans::findSemiAfterLocation(EndTypedefDclLoc, 557 NS.getASTContext(), /*IsDecl*/true); 558 if (!EndTypedefDclLoc.isInvalid()) { 559 SourceRange TDRange(TypedefDcl->getLocStart(), EndTypedefDclLoc); 560 commit.remove(TDRange); 561 } 562 else 563 return false; 564 565 EndOfEnumDclLoc = trans::findLocationAfterSemi(EnumDcl->getLocEnd(), NS.getASTContext(), 566 /*IsDecl*/true); 567 if (!EndOfEnumDclLoc.isInvalid()) { 568 SourceLocation BeginOfEnumDclLoc = EnumDcl->getLocStart(); 569 // FIXME. This assumes that enum decl; is immediately preceeded by eoln. 570 // It is trying to remove the enum decl. lines entirely. 571 BeginOfEnumDclLoc = BeginOfEnumDclLoc.getLocWithOffset(-1); 572 commit.remove(SourceRange(BeginOfEnumDclLoc, EndOfEnumDclLoc)); 573 return true; 574 } 575 return false; 576} 577 578static void rewriteToNSMacroDecl(const EnumDecl *EnumDcl, 579 const TypedefDecl *TypedefDcl, 580 const NSAPI &NS, edit::Commit &commit, 581 bool IsNSIntegerType) { 582 std::string ClassString = 583 IsNSIntegerType ? "NS_ENUM(NSInteger, " : "NS_OPTIONS(NSUInteger, "; 584 ClassString += TypedefDcl->getIdentifier()->getName(); 585 ClassString += ')'; 586 SourceRange R(EnumDcl->getLocStart(), EnumDcl->getLocStart()); 587 commit.replace(R, ClassString); 588 SourceLocation TypedefLoc = TypedefDcl->getLocEnd(); 589 commit.remove(SourceRange(TypedefLoc, TypedefLoc)); 590} 591 592static bool UseNSOptionsMacro(Preprocessor &PP, ASTContext &Ctx, 593 const EnumDecl *EnumDcl) { 594 bool PowerOfTwo = true; 595 bool AllHexdecimalEnumerator = true; 596 uint64_t MaxPowerOfTwoVal = 0; 597 for (EnumDecl::enumerator_iterator EI = EnumDcl->enumerator_begin(), 598 EE = EnumDcl->enumerator_end(); EI != EE; ++EI) { 599 EnumConstantDecl *Enumerator = (*EI); 600 const Expr *InitExpr = Enumerator->getInitExpr(); 601 if (!InitExpr) { 602 PowerOfTwo = false; 603 AllHexdecimalEnumerator = false; 604 continue; 605 } 606 InitExpr = InitExpr->IgnoreParenCasts(); 607 if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(InitExpr)) 608 if (BO->isShiftOp() || BO->isBitwiseOp()) 609 return true; 610 611 uint64_t EnumVal = Enumerator->getInitVal().getZExtValue(); 612 if (PowerOfTwo && EnumVal) { 613 if (!llvm::isPowerOf2_64(EnumVal)) 614 PowerOfTwo = false; 615 else if (EnumVal > MaxPowerOfTwoVal) 616 MaxPowerOfTwoVal = EnumVal; 617 } 618 if (AllHexdecimalEnumerator && EnumVal) { 619 bool FoundHexdecimalEnumerator = false; 620 SourceLocation EndLoc = Enumerator->getLocEnd(); 621 Token Tok; 622 if (!PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true)) 623 if (Tok.isLiteral() && Tok.getLength() > 2) { 624 if (const char *StringLit = Tok.getLiteralData()) 625 FoundHexdecimalEnumerator = 626 (StringLit[0] == '0' && (toLowercase(StringLit[1]) == 'x')); 627 } 628 if (!FoundHexdecimalEnumerator) 629 AllHexdecimalEnumerator = false; 630 } 631 } 632 return AllHexdecimalEnumerator || (PowerOfTwo && (MaxPowerOfTwoVal > 2)); 633} 634 635void ObjCMigrateASTConsumer::migrateProtocolConformance(ASTContext &Ctx, 636 const ObjCImplementationDecl *ImpDecl) { 637 const ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface(); 638 if (!IDecl || ObjCProtocolDecls.empty() || IDecl->isDeprecated()) 639 return; 640 // Find all implicit conforming protocols for this class 641 // and make them explicit. 642 llvm::SmallPtrSet<ObjCProtocolDecl *, 8> ExplicitProtocols; 643 Ctx.CollectInheritedProtocols(IDecl, ExplicitProtocols); 644 llvm::SmallVector<ObjCProtocolDecl *, 8> PotentialImplicitProtocols; 645 646 for (llvm::SmallPtrSet<ObjCProtocolDecl*, 32>::iterator I = 647 ObjCProtocolDecls.begin(), 648 E = ObjCProtocolDecls.end(); I != E; ++I) 649 if (!ExplicitProtocols.count(*I)) 650 PotentialImplicitProtocols.push_back(*I); 651 652 if (PotentialImplicitProtocols.empty()) 653 return; 654 655 // go through list of non-optional methods and properties in each protocol 656 // in the PotentialImplicitProtocols list. If class implements every one of the 657 // methods and properties, then this class conforms to this protocol. 658 llvm::SmallVector<ObjCProtocolDecl*, 8> ConformingProtocols; 659 for (unsigned i = 0, e = PotentialImplicitProtocols.size(); i != e; i++) 660 if (ClassImplementsAllMethodsAndProperties(Ctx, ImpDecl, IDecl, 661 PotentialImplicitProtocols[i])) 662 ConformingProtocols.push_back(PotentialImplicitProtocols[i]); 663 664 if (ConformingProtocols.empty()) 665 return; 666 667 // Further reduce number of conforming protocols. If protocol P1 is in the list 668 // protocol P2 (P2<P1>), No need to include P1. 669 llvm::SmallVector<ObjCProtocolDecl*, 8> MinimalConformingProtocols; 670 for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) { 671 bool DropIt = false; 672 ObjCProtocolDecl *TargetPDecl = ConformingProtocols[i]; 673 for (unsigned i1 = 0, e1 = ConformingProtocols.size(); i1 != e1; i1++) { 674 ObjCProtocolDecl *PDecl = ConformingProtocols[i1]; 675 if (PDecl == TargetPDecl) 676 continue; 677 if (PDecl->lookupProtocolNamed( 678 TargetPDecl->getDeclName().getAsIdentifierInfo())) { 679 DropIt = true; 680 break; 681 } 682 } 683 if (!DropIt) 684 MinimalConformingProtocols.push_back(TargetPDecl); 685 } 686 edit::Commit commit(*Editor); 687 rewriteToObjCInterfaceDecl(IDecl, MinimalConformingProtocols, 688 *NSAPIObj, commit); 689 Editor->commit(commit); 690} 691 692void ObjCMigrateASTConsumer::CacheObjCNSIntegerTypedefed( 693 const TypedefDecl *TypedefDcl) { 694 695 QualType qt = TypedefDcl->getTypeSourceInfo()->getType(); 696 if (NSAPIObj->isObjCNSIntegerType(qt)) 697 NSIntegerTypedefed = TypedefDcl; 698 else if (NSAPIObj->isObjCNSUIntegerType(qt)) 699 NSUIntegerTypedefed = TypedefDcl; 700} 701 702bool ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx, 703 const EnumDecl *EnumDcl, 704 const TypedefDecl *TypedefDcl) { 705 if (!EnumDcl->isCompleteDefinition() || EnumDcl->getIdentifier() || 706 EnumDcl->isDeprecated()) 707 return false; 708 if (!TypedefDcl) { 709 if (NSIntegerTypedefed) { 710 TypedefDcl = NSIntegerTypedefed; 711 NSIntegerTypedefed = 0; 712 } 713 else if (NSUIntegerTypedefed) { 714 TypedefDcl = NSUIntegerTypedefed; 715 NSUIntegerTypedefed = 0; 716 } 717 else 718 return false; 719 unsigned FileIdOfTypedefDcl = 720 PP.getSourceManager().getFileID(TypedefDcl->getLocation()).getHashValue(); 721 unsigned FileIdOfEnumDcl = 722 PP.getSourceManager().getFileID(EnumDcl->getLocation()).getHashValue(); 723 if (FileIdOfTypedefDcl != FileIdOfEnumDcl) 724 return false; 725 } 726 if (TypedefDcl->isDeprecated()) 727 return false; 728 729 QualType qt = TypedefDcl->getTypeSourceInfo()->getType(); 730 bool IsNSIntegerType = NSAPIObj->isObjCNSIntegerType(qt); 731 bool IsNSUIntegerType = !IsNSIntegerType && NSAPIObj->isObjCNSUIntegerType(qt); 732 733 if (!IsNSIntegerType && !IsNSUIntegerType) { 734 // Also check for typedef enum {...} TD; 735 if (const EnumType *EnumTy = qt->getAs<EnumType>()) { 736 if (EnumTy->getDecl() == EnumDcl) { 737 bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl); 738 if (NSOptions) { 739 if (!Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition()) 740 return false; 741 } 742 else if (!Ctx.Idents.get("NS_ENUM").hasMacroDefinition()) 743 return false; 744 edit::Commit commit(*Editor); 745 rewriteToNSMacroDecl(EnumDcl, TypedefDcl, *NSAPIObj, commit, !NSOptions); 746 Editor->commit(commit); 747 return true; 748 } 749 } 750 return false; 751 } 752 753 // We may still use NS_OPTIONS based on what we find in the enumertor list. 754 bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl); 755 // NS_ENUM must be available. 756 if (IsNSIntegerType && !Ctx.Idents.get("NS_ENUM").hasMacroDefinition()) 757 return false; 758 // NS_OPTIONS must be available. 759 if (IsNSUIntegerType && !Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition()) 760 return false; 761 edit::Commit commit(*Editor); 762 bool Res = rewriteToNSEnumDecl(EnumDcl, TypedefDcl, *NSAPIObj, 763 commit, IsNSIntegerType, NSOptions); 764 Editor->commit(commit); 765 return Res; 766} 767 768static void ReplaceWithInstancetype(const ObjCMigrateASTConsumer &ASTC, 769 ObjCMethodDecl *OM) { 770 SourceRange R; 771 std::string ClassString; 772 if (TypeSourceInfo *TSInfo = OM->getResultTypeSourceInfo()) { 773 TypeLoc TL = TSInfo->getTypeLoc(); 774 R = SourceRange(TL.getBeginLoc(), TL.getEndLoc()); 775 ClassString = "instancetype"; 776 } 777 else { 778 R = SourceRange(OM->getLocStart(), OM->getLocStart()); 779 ClassString = OM->isInstanceMethod() ? '-' : '+'; 780 ClassString += " (instancetype)"; 781 } 782 edit::Commit commit(*ASTC.Editor); 783 commit.replace(R, ClassString); 784 ASTC.Editor->commit(commit); 785} 786 787static void ReplaceWithClasstype(const ObjCMigrateASTConsumer &ASTC, 788 ObjCMethodDecl *OM) { 789 ObjCInterfaceDecl *IDecl = OM->getClassInterface(); 790 SourceRange R; 791 std::string ClassString; 792 if (TypeSourceInfo *TSInfo = OM->getResultTypeSourceInfo()) { 793 TypeLoc TL = TSInfo->getTypeLoc(); 794 R = SourceRange(TL.getBeginLoc(), TL.getEndLoc()); { 795 ClassString = IDecl->getName(); 796 ClassString += "*"; 797 } 798 } 799 else { 800 R = SourceRange(OM->getLocStart(), OM->getLocStart()); 801 ClassString = "+ ("; 802 ClassString += IDecl->getName(); ClassString += "*)"; 803 } 804 edit::Commit commit(*ASTC.Editor); 805 commit.replace(R, ClassString); 806 ASTC.Editor->commit(commit); 807} 808 809void ObjCMigrateASTConsumer::migrateMethodInstanceType(ASTContext &Ctx, 810 ObjCContainerDecl *CDecl, 811 ObjCMethodDecl *OM) { 812 ObjCInstanceTypeFamily OIT_Family = 813 Selector::getInstTypeMethodFamily(OM->getSelector()); 814 815 std::string ClassName; 816 switch (OIT_Family) { 817 case OIT_None: 818 migrateFactoryMethod(Ctx, CDecl, OM); 819 return; 820 case OIT_Array: 821 ClassName = "NSArray"; 822 break; 823 case OIT_Dictionary: 824 ClassName = "NSDictionary"; 825 break; 826 case OIT_Singleton: 827 migrateFactoryMethod(Ctx, CDecl, OM, OIT_Singleton); 828 return; 829 case OIT_Init: 830 if (OM->getResultType()->isObjCIdType()) 831 ReplaceWithInstancetype(*this, OM); 832 return; 833 case OIT_ReturnsSelf: 834 migrateFactoryMethod(Ctx, CDecl, OM, OIT_ReturnsSelf); 835 return; 836 } 837 if (!OM->getResultType()->isObjCIdType()) 838 return; 839 840 ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl); 841 if (!IDecl) { 842 if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) 843 IDecl = CatDecl->getClassInterface(); 844 else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl)) 845 IDecl = ImpDecl->getClassInterface(); 846 } 847 if (!IDecl || 848 !IDecl->lookupInheritedClass(&Ctx.Idents.get(ClassName))) { 849 migrateFactoryMethod(Ctx, CDecl, OM); 850 return; 851 } 852 ReplaceWithInstancetype(*this, OM); 853} 854 855static bool TypeIsInnerPointer(QualType T) { 856 if (!T->isAnyPointerType()) 857 return false; 858 if (T->isObjCObjectPointerType() || T->isObjCBuiltinType() || 859 T->isBlockPointerType() || T->isFunctionPointerType() || 860 ento::coreFoundation::isCFObjectRef(T)) 861 return false; 862 // Also, typedef-of-pointer-to-incomplete-struct is something that we assume 863 // is not an innter pointer type. 864 QualType OrigT = T; 865 while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) 866 T = TD->getDecl()->getUnderlyingType(); 867 if (OrigT == T || !T->isPointerType()) 868 return true; 869 const PointerType* PT = T->getAs<PointerType>(); 870 QualType UPointeeT = PT->getPointeeType().getUnqualifiedType(); 871 if (UPointeeT->isRecordType()) { 872 const RecordType *RecordTy = UPointeeT->getAs<RecordType>(); 873 if (!RecordTy->getDecl()->isCompleteDefinition()) 874 return false; 875 } 876 return true; 877} 878 879static bool AttributesMatch(const Decl *Decl1, const Decl *Decl2) { 880 if (Decl1->hasAttrs() != Decl2->hasAttrs()) 881 return false; 882 883 if (!Decl1->hasAttrs()) 884 return true; 885 886 const AttrVec &Attrs1 = Decl1->getAttrs(); 887 const AttrVec &Attrs2 = Decl2->getAttrs(); 888 // This list is very small, so this need not be optimized. 889 for (unsigned i = 0, e = Attrs1.size(); i != e; i++) { 890 bool match = false; 891 for (unsigned j = 0, f = Attrs2.size(); j != f; j++) { 892 // Matching attribute kind only. We are not getting into 893 // details of the attributes. For all practical purposes 894 // this is sufficient. 895 if (Attrs1[i]->getKind() == Attrs2[j]->getKind()) { 896 match = true; 897 break; 898 } 899 } 900 if (!match) 901 return false; 902 } 903 return true; 904} 905 906static bool IsValidIdentifier(ASTContext &Ctx, 907 const char *Name) { 908 if (!isIdentifierHead(Name[0])) 909 return false; 910 std::string NameString = Name; 911 NameString[0] = toLowercase(NameString[0]); 912 IdentifierInfo *II = &Ctx.Idents.get(NameString); 913 return II->getTokenID() == tok::identifier; 914} 915 916bool ObjCMigrateASTConsumer::migrateProperty(ASTContext &Ctx, 917 ObjCContainerDecl *D, 918 ObjCMethodDecl *Method) { 919 if (Method->isPropertyAccessor() || !Method->isInstanceMethod() || 920 Method->param_size() != 0) 921 return false; 922 // Is this method candidate to be a getter? 923 QualType GRT = Method->getResultType(); 924 if (GRT->isVoidType()) 925 return false; 926 927 Selector GetterSelector = Method->getSelector(); 928 ObjCInstanceTypeFamily OIT_Family = 929 Selector::getInstTypeMethodFamily(GetterSelector); 930 931 if (OIT_Family != OIT_None) 932 return false; 933 934 IdentifierInfo *getterName = GetterSelector.getIdentifierInfoForSlot(0); 935 Selector SetterSelector = 936 SelectorTable::constructSetterSelector(PP.getIdentifierTable(), 937 PP.getSelectorTable(), 938 getterName); 939 ObjCMethodDecl *SetterMethod = D->getInstanceMethod(SetterSelector); 940 unsigned LengthOfPrefix = 0; 941 if (!SetterMethod) { 942 // try a different naming convention for getter: isXxxxx 943 StringRef getterNameString = getterName->getName(); 944 bool IsPrefix = getterNameString.startswith("is"); 945 // Note that we don't want to change an isXXX method of retainable object 946 // type to property (readonly or otherwise). 947 if (IsPrefix && GRT->isObjCRetainableType()) 948 return false; 949 if (IsPrefix || getterNameString.startswith("get")) { 950 LengthOfPrefix = (IsPrefix ? 2 : 3); 951 const char *CGetterName = getterNameString.data() + LengthOfPrefix; 952 // Make sure that first character after "is" or "get" prefix can 953 // start an identifier. 954 if (!IsValidIdentifier(Ctx, CGetterName)) 955 return false; 956 if (CGetterName[0] && isUppercase(CGetterName[0])) { 957 getterName = &Ctx.Idents.get(CGetterName); 958 SetterSelector = 959 SelectorTable::constructSetterSelector(PP.getIdentifierTable(), 960 PP.getSelectorTable(), 961 getterName); 962 SetterMethod = D->getInstanceMethod(SetterSelector); 963 } 964 } 965 } 966 967 if (SetterMethod) { 968 if ((ASTMigrateActions & FrontendOptions::ObjCMT_ReadwriteProperty) == 0) 969 return false; 970 if (SetterMethod->isDeprecated() || 971 !AttributesMatch(Method, SetterMethod)) 972 return false; 973 974 // Is this a valid setter, matching the target getter? 975 QualType SRT = SetterMethod->getResultType(); 976 if (!SRT->isVoidType()) 977 return false; 978 const ParmVarDecl *argDecl = *SetterMethod->param_begin(); 979 QualType ArgType = argDecl->getType(); 980 if (!Ctx.hasSameUnqualifiedType(ArgType, GRT)) 981 return false; 982 edit::Commit commit(*Editor); 983 rewriteToObjCProperty(Method, SetterMethod, *NSAPIObj, commit, 984 LengthOfPrefix, 985 (ASTMigrateActions & 986 FrontendOptions::ObjCMT_AtomicProperty) != 0); 987 Editor->commit(commit); 988 return true; 989 } 990 else if (ASTMigrateActions & FrontendOptions::ObjCMT_ReadonlyProperty) { 991 // Try a non-void method with no argument (and no setter or property of same name 992 // as a 'readonly' property. 993 edit::Commit commit(*Editor); 994 rewriteToObjCProperty(Method, 0 /*SetterMethod*/, *NSAPIObj, commit, 995 LengthOfPrefix, 996 (ASTMigrateActions & 997 FrontendOptions::ObjCMT_AtomicProperty) != 0); 998 Editor->commit(commit); 999 return true; 1000 } 1001 return false; 1002} 1003 1004void ObjCMigrateASTConsumer::migrateNsReturnsInnerPointer(ASTContext &Ctx, 1005 ObjCMethodDecl *OM) { 1006 if (OM->isImplicit() || 1007 !OM->isInstanceMethod() || 1008 OM->hasAttr<ObjCReturnsInnerPointerAttr>()) 1009 return; 1010 1011 QualType RT = OM->getResultType(); 1012 if (!TypeIsInnerPointer(RT) || 1013 !Ctx.Idents.get("NS_RETURNS_INNER_POINTER").hasMacroDefinition()) 1014 return; 1015 1016 edit::Commit commit(*Editor); 1017 commit.insertBefore(OM->getLocEnd(), " NS_RETURNS_INNER_POINTER"); 1018 Editor->commit(commit); 1019} 1020 1021void ObjCMigrateASTConsumer::migratePropertyNsReturnsInnerPointer(ASTContext &Ctx, 1022 ObjCPropertyDecl *P) { 1023 QualType T = P->getType(); 1024 1025 if (!TypeIsInnerPointer(T) || 1026 !Ctx.Idents.get("NS_RETURNS_INNER_POINTER").hasMacroDefinition()) 1027 return; 1028 edit::Commit commit(*Editor); 1029 commit.insertBefore(P->getLocEnd(), " NS_RETURNS_INNER_POINTER "); 1030 Editor->commit(commit); 1031} 1032 1033void ObjCMigrateASTConsumer::migrateAllMethodInstaceType(ASTContext &Ctx, 1034 ObjCContainerDecl *CDecl) { 1035 if (CDecl->isDeprecated()) 1036 return; 1037 1038 // migrate methods which can have instancetype as their result type. 1039 for (ObjCContainerDecl::method_iterator M = CDecl->meth_begin(), 1040 MEnd = CDecl->meth_end(); 1041 M != MEnd; ++M) { 1042 ObjCMethodDecl *Method = (*M); 1043 if (Method->isDeprecated()) 1044 continue; 1045 migrateMethodInstanceType(Ctx, CDecl, Method); 1046 } 1047} 1048 1049void ObjCMigrateASTConsumer::migrateFactoryMethod(ASTContext &Ctx, 1050 ObjCContainerDecl *CDecl, 1051 ObjCMethodDecl *OM, 1052 ObjCInstanceTypeFamily OIT_Family) { 1053 if (OM->isInstanceMethod() || 1054 OM->getResultType() == Ctx.getObjCInstanceType() || 1055 !OM->getResultType()->isObjCIdType()) 1056 return; 1057 1058 // Candidate factory methods are + (id) NaMeXXX : ... which belong to a class 1059 // NSYYYNamE with matching names be at least 3 characters long. 1060 ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl); 1061 if (!IDecl) { 1062 if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) 1063 IDecl = CatDecl->getClassInterface(); 1064 else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl)) 1065 IDecl = ImpDecl->getClassInterface(); 1066 } 1067 if (!IDecl) 1068 return; 1069 1070 std::string StringClassName = IDecl->getName(); 1071 StringRef LoweredClassName(StringClassName); 1072 std::string StringLoweredClassName = LoweredClassName.lower(); 1073 LoweredClassName = StringLoweredClassName; 1074 1075 IdentifierInfo *MethodIdName = OM->getSelector().getIdentifierInfoForSlot(0); 1076 // Handle method with no name at its first selector slot; e.g. + (id):(int)x. 1077 if (!MethodIdName) 1078 return; 1079 1080 std::string MethodName = MethodIdName->getName(); 1081 if (OIT_Family == OIT_Singleton || OIT_Family == OIT_ReturnsSelf) { 1082 StringRef STRefMethodName(MethodName); 1083 size_t len = 0; 1084 if (STRefMethodName.startswith("standard")) 1085 len = strlen("standard"); 1086 else if (STRefMethodName.startswith("shared")) 1087 len = strlen("shared"); 1088 else if (STRefMethodName.startswith("default")) 1089 len = strlen("default"); 1090 else 1091 return; 1092 MethodName = STRefMethodName.substr(len); 1093 } 1094 std::string MethodNameSubStr = MethodName.substr(0, 3); 1095 StringRef MethodNamePrefix(MethodNameSubStr); 1096 std::string StringLoweredMethodNamePrefix = MethodNamePrefix.lower(); 1097 MethodNamePrefix = StringLoweredMethodNamePrefix; 1098 size_t Ix = LoweredClassName.rfind(MethodNamePrefix); 1099 if (Ix == StringRef::npos) 1100 return; 1101 std::string ClassNamePostfix = LoweredClassName.substr(Ix); 1102 StringRef LoweredMethodName(MethodName); 1103 std::string StringLoweredMethodName = LoweredMethodName.lower(); 1104 LoweredMethodName = StringLoweredMethodName; 1105 if (!LoweredMethodName.startswith(ClassNamePostfix)) 1106 return; 1107 if (OIT_Family == OIT_ReturnsSelf) 1108 ReplaceWithClasstype(*this, OM); 1109 else 1110 ReplaceWithInstancetype(*this, OM); 1111} 1112 1113static bool IsVoidStarType(QualType Ty) { 1114 if (!Ty->isPointerType()) 1115 return false; 1116 1117 while (const TypedefType *TD = dyn_cast<TypedefType>(Ty.getTypePtr())) 1118 Ty = TD->getDecl()->getUnderlyingType(); 1119 1120 // Is the type void*? 1121 const PointerType* PT = Ty->getAs<PointerType>(); 1122 if (PT->getPointeeType().getUnqualifiedType()->isVoidType()) 1123 return true; 1124 return IsVoidStarType(PT->getPointeeType()); 1125} 1126 1127/// AuditedType - This routine audits the type AT and returns false if it is one of known 1128/// CF object types or of the "void *" variety. It returns true if we don't care about the type 1129/// such as a non-pointer or pointers which have no ownership issues (such as "int *"). 1130static bool AuditedType (QualType AT) { 1131 if (!AT->isAnyPointerType() && !AT->isBlockPointerType()) 1132 return true; 1133 // FIXME. There isn't much we can say about CF pointer type; or is there? 1134 if (ento::coreFoundation::isCFObjectRef(AT) || 1135 IsVoidStarType(AT) || 1136 // If an ObjC object is type, assuming that it is not a CF function and 1137 // that it is an un-audited function. 1138 AT->isObjCObjectPointerType() || AT->isObjCBuiltinType()) 1139 return false; 1140 // All other pointers are assumed audited as harmless. 1141 return true; 1142} 1143 1144void ObjCMigrateASTConsumer::AnnotateImplicitBridging(ASTContext &Ctx) { 1145 if (CFFunctionIBCandidates.empty()) 1146 return; 1147 if (!Ctx.Idents.get("CF_IMPLICIT_BRIDGING_ENABLED").hasMacroDefinition()) { 1148 CFFunctionIBCandidates.clear(); 1149 FileId = 0; 1150 return; 1151 } 1152 // Insert CF_IMPLICIT_BRIDGING_ENABLE/CF_IMPLICIT_BRIDGING_DISABLED 1153 const Decl *FirstFD = CFFunctionIBCandidates[0]; 1154 const Decl *LastFD = 1155 CFFunctionIBCandidates[CFFunctionIBCandidates.size()-1]; 1156 const char *PragmaString = "\nCF_IMPLICIT_BRIDGING_ENABLED\n\n"; 1157 edit::Commit commit(*Editor); 1158 commit.insertBefore(FirstFD->getLocStart(), PragmaString); 1159 PragmaString = "\n\nCF_IMPLICIT_BRIDGING_DISABLED\n"; 1160 SourceLocation EndLoc = LastFD->getLocEnd(); 1161 // get location just past end of function location. 1162 EndLoc = PP.getLocForEndOfToken(EndLoc); 1163 if (isa<FunctionDecl>(LastFD)) { 1164 // For Methods, EndLoc points to the ending semcolon. So, 1165 // not of these extra work is needed. 1166 Token Tok; 1167 // get locaiton of token that comes after end of function. 1168 bool Failed = PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true); 1169 if (!Failed) 1170 EndLoc = Tok.getLocation(); 1171 } 1172 commit.insertAfterToken(EndLoc, PragmaString); 1173 Editor->commit(commit); 1174 FileId = 0; 1175 CFFunctionIBCandidates.clear(); 1176} 1177 1178void ObjCMigrateASTConsumer::migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl) { 1179 if (Decl->isDeprecated()) 1180 return; 1181 1182 if (Decl->hasAttr<CFAuditedTransferAttr>()) { 1183 assert(CFFunctionIBCandidates.empty() && 1184 "Cannot have audited functions/methods inside user " 1185 "provided CF_IMPLICIT_BRIDGING_ENABLE"); 1186 return; 1187 } 1188 1189 // Finction must be annotated first. 1190 if (const FunctionDecl *FuncDecl = dyn_cast<FunctionDecl>(Decl)) { 1191 CF_BRIDGING_KIND AuditKind = migrateAddFunctionAnnotation(Ctx, FuncDecl); 1192 if (AuditKind == CF_BRIDGING_ENABLE) { 1193 CFFunctionIBCandidates.push_back(Decl); 1194 if (!FileId) 1195 FileId = PP.getSourceManager().getFileID(Decl->getLocation()).getHashValue(); 1196 } 1197 else if (AuditKind == CF_BRIDGING_MAY_INCLUDE) { 1198 if (!CFFunctionIBCandidates.empty()) { 1199 CFFunctionIBCandidates.push_back(Decl); 1200 if (!FileId) 1201 FileId = PP.getSourceManager().getFileID(Decl->getLocation()).getHashValue(); 1202 } 1203 } 1204 else 1205 AnnotateImplicitBridging(Ctx); 1206 } 1207 else { 1208 migrateAddMethodAnnotation(Ctx, cast<ObjCMethodDecl>(Decl)); 1209 AnnotateImplicitBridging(Ctx); 1210 } 1211} 1212 1213void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx, 1214 const CallEffects &CE, 1215 const FunctionDecl *FuncDecl, 1216 bool ResultAnnotated) { 1217 // Annotate function. 1218 if (!ResultAnnotated) { 1219 RetEffect Ret = CE.getReturnValue(); 1220 const char *AnnotationString = 0; 1221 if (Ret.getObjKind() == RetEffect::CF) { 1222 if (Ret.isOwned() && 1223 Ctx.Idents.get("CF_RETURNS_RETAINED").hasMacroDefinition()) 1224 AnnotationString = " CF_RETURNS_RETAINED"; 1225 else if (Ret.notOwned() && 1226 Ctx.Idents.get("CF_RETURNS_NOT_RETAINED").hasMacroDefinition()) 1227 AnnotationString = " CF_RETURNS_NOT_RETAINED"; 1228 } 1229 else if (Ret.getObjKind() == RetEffect::ObjC) { 1230 if (Ret.isOwned() && 1231 Ctx.Idents.get("NS_RETURNS_RETAINED").hasMacroDefinition()) 1232 AnnotationString = " NS_RETURNS_RETAINED"; 1233 } 1234 1235 if (AnnotationString) { 1236 edit::Commit commit(*Editor); 1237 commit.insertAfterToken(FuncDecl->getLocEnd(), AnnotationString); 1238 Editor->commit(commit); 1239 } 1240 } 1241 llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs(); 1242 unsigned i = 0; 1243 for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(), 1244 pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) { 1245 const ParmVarDecl *pd = *pi; 1246 ArgEffect AE = AEArgs[i]; 1247 if (AE == DecRef && !pd->getAttr<CFConsumedAttr>() && 1248 Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) { 1249 edit::Commit commit(*Editor); 1250 commit.insertBefore(pd->getLocation(), "CF_CONSUMED "); 1251 Editor->commit(commit); 1252 } 1253 else if (AE == DecRefMsg && !pd->getAttr<NSConsumedAttr>() && 1254 Ctx.Idents.get("NS_CONSUMED").hasMacroDefinition()) { 1255 edit::Commit commit(*Editor); 1256 commit.insertBefore(pd->getLocation(), "NS_CONSUMED "); 1257 Editor->commit(commit); 1258 } 1259 } 1260} 1261 1262 1263ObjCMigrateASTConsumer::CF_BRIDGING_KIND 1264 ObjCMigrateASTConsumer::migrateAddFunctionAnnotation( 1265 ASTContext &Ctx, 1266 const FunctionDecl *FuncDecl) { 1267 if (FuncDecl->hasBody()) 1268 return CF_BRIDGING_NONE; 1269 1270 CallEffects CE = CallEffects::getEffect(FuncDecl); 1271 bool FuncIsReturnAnnotated = (FuncDecl->getAttr<CFReturnsRetainedAttr>() || 1272 FuncDecl->getAttr<CFReturnsNotRetainedAttr>() || 1273 FuncDecl->getAttr<NSReturnsRetainedAttr>() || 1274 FuncDecl->getAttr<NSReturnsNotRetainedAttr>() || 1275 FuncDecl->getAttr<NSReturnsAutoreleasedAttr>()); 1276 1277 // Trivial case of when funciton is annotated and has no argument. 1278 if (FuncIsReturnAnnotated && FuncDecl->getNumParams() == 0) 1279 return CF_BRIDGING_NONE; 1280 1281 bool ReturnCFAudited = false; 1282 if (!FuncIsReturnAnnotated) { 1283 RetEffect Ret = CE.getReturnValue(); 1284 if (Ret.getObjKind() == RetEffect::CF && 1285 (Ret.isOwned() || Ret.notOwned())) 1286 ReturnCFAudited = true; 1287 else if (!AuditedType(FuncDecl->getResultType())) 1288 return CF_BRIDGING_NONE; 1289 } 1290 1291 // At this point result type is audited for potential inclusion. 1292 // Now, how about argument types. 1293 llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs(); 1294 unsigned i = 0; 1295 bool ArgCFAudited = false; 1296 for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(), 1297 pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) { 1298 const ParmVarDecl *pd = *pi; 1299 ArgEffect AE = AEArgs[i]; 1300 if (AE == DecRef /*CFConsumed annotated*/ || AE == IncRef) { 1301 if (AE == DecRef && !pd->getAttr<CFConsumedAttr>()) 1302 ArgCFAudited = true; 1303 else if (AE == IncRef) 1304 ArgCFAudited = true; 1305 } 1306 else { 1307 QualType AT = pd->getType(); 1308 if (!AuditedType(AT)) { 1309 AddCFAnnotations(Ctx, CE, FuncDecl, FuncIsReturnAnnotated); 1310 return CF_BRIDGING_NONE; 1311 } 1312 } 1313 } 1314 if (ReturnCFAudited || ArgCFAudited) 1315 return CF_BRIDGING_ENABLE; 1316 1317 return CF_BRIDGING_MAY_INCLUDE; 1318} 1319 1320void ObjCMigrateASTConsumer::migrateARCSafeAnnotation(ASTContext &Ctx, 1321 ObjCContainerDecl *CDecl) { 1322 if (!isa<ObjCInterfaceDecl>(CDecl) || CDecl->isDeprecated()) 1323 return; 1324 1325 // migrate methods which can have instancetype as their result type. 1326 for (ObjCContainerDecl::method_iterator M = CDecl->meth_begin(), 1327 MEnd = CDecl->meth_end(); 1328 M != MEnd; ++M) { 1329 ObjCMethodDecl *Method = (*M); 1330 migrateCFAnnotation(Ctx, Method); 1331 } 1332} 1333 1334void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx, 1335 const CallEffects &CE, 1336 const ObjCMethodDecl *MethodDecl, 1337 bool ResultAnnotated) { 1338 // Annotate function. 1339 if (!ResultAnnotated) { 1340 RetEffect Ret = CE.getReturnValue(); 1341 const char *AnnotationString = 0; 1342 if (Ret.getObjKind() == RetEffect::CF) { 1343 if (Ret.isOwned() && 1344 Ctx.Idents.get("CF_RETURNS_RETAINED").hasMacroDefinition()) 1345 AnnotationString = " CF_RETURNS_RETAINED"; 1346 else if (Ret.notOwned() && 1347 Ctx.Idents.get("CF_RETURNS_NOT_RETAINED").hasMacroDefinition()) 1348 AnnotationString = " CF_RETURNS_NOT_RETAINED"; 1349 } 1350 else if (Ret.getObjKind() == RetEffect::ObjC) { 1351 ObjCMethodFamily OMF = MethodDecl->getMethodFamily(); 1352 switch (OMF) { 1353 case clang::OMF_alloc: 1354 case clang::OMF_new: 1355 case clang::OMF_copy: 1356 case clang::OMF_init: 1357 case clang::OMF_mutableCopy: 1358 break; 1359 1360 default: 1361 if (Ret.isOwned() && 1362 Ctx.Idents.get("NS_RETURNS_RETAINED").hasMacroDefinition()) 1363 AnnotationString = " NS_RETURNS_RETAINED"; 1364 break; 1365 } 1366 } 1367 1368 if (AnnotationString) { 1369 edit::Commit commit(*Editor); 1370 commit.insertBefore(MethodDecl->getLocEnd(), AnnotationString); 1371 Editor->commit(commit); 1372 } 1373 } 1374 llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs(); 1375 unsigned i = 0; 1376 for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(), 1377 pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) { 1378 const ParmVarDecl *pd = *pi; 1379 ArgEffect AE = AEArgs[i]; 1380 if (AE == DecRef && !pd->getAttr<CFConsumedAttr>() && 1381 Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) { 1382 edit::Commit commit(*Editor); 1383 commit.insertBefore(pd->getLocation(), "CF_CONSUMED "); 1384 Editor->commit(commit); 1385 } 1386 } 1387} 1388 1389void ObjCMigrateASTConsumer::migrateAddMethodAnnotation( 1390 ASTContext &Ctx, 1391 const ObjCMethodDecl *MethodDecl) { 1392 if (MethodDecl->hasBody() || MethodDecl->isImplicit()) 1393 return; 1394 1395 CallEffects CE = CallEffects::getEffect(MethodDecl); 1396 bool MethodIsReturnAnnotated = (MethodDecl->getAttr<CFReturnsRetainedAttr>() || 1397 MethodDecl->getAttr<CFReturnsNotRetainedAttr>() || 1398 MethodDecl->getAttr<NSReturnsRetainedAttr>() || 1399 MethodDecl->getAttr<NSReturnsNotRetainedAttr>() || 1400 MethodDecl->getAttr<NSReturnsAutoreleasedAttr>()); 1401 1402 if (CE.getReceiver() == DecRefMsg && 1403 !MethodDecl->getAttr<NSConsumesSelfAttr>() && 1404 MethodDecl->getMethodFamily() != OMF_init && 1405 MethodDecl->getMethodFamily() != OMF_release && 1406 Ctx.Idents.get("NS_CONSUMES_SELF").hasMacroDefinition()) { 1407 edit::Commit commit(*Editor); 1408 commit.insertBefore(MethodDecl->getLocEnd(), " NS_CONSUMES_SELF"); 1409 Editor->commit(commit); 1410 } 1411 1412 // Trivial case of when funciton is annotated and has no argument. 1413 if (MethodIsReturnAnnotated && 1414 (MethodDecl->param_begin() == MethodDecl->param_end())) 1415 return; 1416 1417 if (!MethodIsReturnAnnotated) { 1418 RetEffect Ret = CE.getReturnValue(); 1419 if ((Ret.getObjKind() == RetEffect::CF || 1420 Ret.getObjKind() == RetEffect::ObjC) && 1421 (Ret.isOwned() || Ret.notOwned())) { 1422 AddCFAnnotations(Ctx, CE, MethodDecl, false); 1423 return; 1424 } 1425 else if (!AuditedType(MethodDecl->getResultType())) 1426 return; 1427 } 1428 1429 // At this point result type is either annotated or audited. 1430 // Now, how about argument types. 1431 llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs(); 1432 unsigned i = 0; 1433 for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(), 1434 pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) { 1435 const ParmVarDecl *pd = *pi; 1436 ArgEffect AE = AEArgs[i]; 1437 if ((AE == DecRef && !pd->getAttr<CFConsumedAttr>()) || AE == IncRef || 1438 !AuditedType(pd->getType())) { 1439 AddCFAnnotations(Ctx, CE, MethodDecl, MethodIsReturnAnnotated); 1440 return; 1441 } 1442 } 1443 return; 1444} 1445 1446namespace { 1447 1448class RewritesReceiver : public edit::EditsReceiver { 1449 Rewriter &Rewrite; 1450 1451public: 1452 RewritesReceiver(Rewriter &Rewrite) : Rewrite(Rewrite) { } 1453 1454 virtual void insert(SourceLocation loc, StringRef text) { 1455 Rewrite.InsertText(loc, text); 1456 } 1457 virtual void replace(CharSourceRange range, StringRef text) { 1458 Rewrite.ReplaceText(range.getBegin(), Rewrite.getRangeSize(range), text); 1459 } 1460}; 1461 1462} 1463 1464static bool 1465IsReallyASystemHeader(ASTContext &Ctx, const FileEntry *file, FileID FID) { 1466 bool Invalid = false; 1467 const SrcMgr::SLocEntry &SEntry = 1468 Ctx.getSourceManager().getSLocEntry(FID, &Invalid); 1469 if (!Invalid && SEntry.isFile()) { 1470 const SrcMgr::FileInfo &FI = SEntry.getFile(); 1471 if (!FI.hasLineDirectives()) { 1472 if (FI.getFileCharacteristic() == SrcMgr::C_ExternCSystem) 1473 return true; 1474 if (FI.getFileCharacteristic() == SrcMgr::C_System) { 1475 // This file is in a system header directory. Continue with commiting change 1476 // only if it is a user specified system directory because user put a 1477 // .system_framework file in the framework directory. 1478 StringRef Directory(file->getDir()->getName()); 1479 size_t Ix = Directory.rfind(".framework"); 1480 if (Ix == StringRef::npos) 1481 return true; 1482 std::string PatchToSystemFramework = Directory.slice(0, Ix+sizeof(".framework")); 1483 PatchToSystemFramework += ".system_framework"; 1484 if (!llvm::sys::fs::exists(PatchToSystemFramework.data())) 1485 return true; 1486 } 1487 } 1488 } 1489 return false; 1490} 1491 1492void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) { 1493 1494 TranslationUnitDecl *TU = Ctx.getTranslationUnitDecl(); 1495 if (ASTMigrateActions & FrontendOptions::ObjCMT_MigrateDecls) { 1496 for (DeclContext::decl_iterator D = TU->decls_begin(), DEnd = TU->decls_end(); 1497 D != DEnd; ++D) { 1498 if (unsigned FID = 1499 PP.getSourceManager().getFileID((*D)->getLocation()).getHashValue()) 1500 if (FileId && FileId != FID) { 1501 if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) 1502 AnnotateImplicitBridging(Ctx); 1503 } 1504 1505 if (ObjCInterfaceDecl *CDecl = dyn_cast<ObjCInterfaceDecl>(*D)) 1506 migrateObjCInterfaceDecl(Ctx, CDecl); 1507 if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(*D)) 1508 migrateObjCInterfaceDecl(Ctx, CatDecl); 1509 else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(*D)) 1510 ObjCProtocolDecls.insert(PDecl); 1511 else if (const ObjCImplementationDecl *ImpDecl = 1512 dyn_cast<ObjCImplementationDecl>(*D)) { 1513 if (ASTMigrateActions & FrontendOptions::ObjCMT_ProtocolConformance) 1514 migrateProtocolConformance(Ctx, ImpDecl); 1515 } 1516 else if (const EnumDecl *ED = dyn_cast<EnumDecl>(*D)) { 1517 if (!(ASTMigrateActions & FrontendOptions::ObjCMT_NsMacros)) 1518 continue; 1519 DeclContext::decl_iterator N = D; 1520 if (++N != DEnd) { 1521 const TypedefDecl *TD = dyn_cast<TypedefDecl>(*N); 1522 if (migrateNSEnumDecl(Ctx, ED, TD) && TD) 1523 D++; 1524 } 1525 else 1526 migrateNSEnumDecl(Ctx, ED, /*TypedefDecl */0); 1527 } 1528 else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(*D)) { 1529 if (!(ASTMigrateActions & FrontendOptions::ObjCMT_NsMacros)) 1530 continue; 1531 DeclContext::decl_iterator N = D; 1532 if (++N == DEnd) 1533 continue; 1534 if (const EnumDecl *ED = dyn_cast<EnumDecl>(*N)) { 1535 if (++N != DEnd) 1536 if (const TypedefDecl *TDF = dyn_cast<TypedefDecl>(*N)) { 1537 // prefer typedef-follows-enum to enum-follows-typedef pattern. 1538 if (migrateNSEnumDecl(Ctx, ED, TDF)) { 1539 ++D; ++D; 1540 CacheObjCNSIntegerTypedefed(TD); 1541 continue; 1542 } 1543 } 1544 if (migrateNSEnumDecl(Ctx, ED, TD)) { 1545 ++D; 1546 continue; 1547 } 1548 } 1549 CacheObjCNSIntegerTypedefed(TD); 1550 } 1551 else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*D)) { 1552 if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) 1553 migrateCFAnnotation(Ctx, FD); 1554 } 1555 1556 if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(*D)) { 1557 // migrate methods which can have instancetype as their result type. 1558 if (ASTMigrateActions & FrontendOptions::ObjCMT_Instancetype) 1559 migrateAllMethodInstaceType(Ctx, CDecl); 1560 // annotate methods with CF annotations. 1561 if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) 1562 migrateARCSafeAnnotation(Ctx, CDecl); 1563 } 1564 } 1565 if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) 1566 AnnotateImplicitBridging(Ctx); 1567 } 1568 1569 Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts()); 1570 RewritesReceiver Rec(rewriter); 1571 Editor->applyRewrites(Rec); 1572 1573 for (Rewriter::buffer_iterator 1574 I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) { 1575 FileID FID = I->first; 1576 RewriteBuffer &buf = I->second; 1577 const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID); 1578 assert(file); 1579 if (IsReallyASystemHeader(Ctx, file, FID)) 1580 continue; 1581 SmallString<512> newText; 1582 llvm::raw_svector_ostream vecOS(newText); 1583 buf.write(vecOS); 1584 vecOS.flush(); 1585 llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy( 1586 StringRef(newText.data(), newText.size()), file->getName()); 1587 SmallString<64> filePath(file->getName()); 1588 FileMgr.FixupRelativePath(filePath); 1589 Remapper.remap(filePath.str(), memBuf); 1590 } 1591 1592 if (IsOutputFile) { 1593 Remapper.flushToFile(MigrateDir, Ctx.getDiagnostics()); 1594 } else { 1595 Remapper.flushToDisk(MigrateDir, Ctx.getDiagnostics()); 1596 } 1597} 1598 1599bool MigrateSourceAction::BeginInvocation(CompilerInstance &CI) { 1600 CI.getDiagnostics().setIgnoreAllWarnings(true); 1601 return true; 1602} 1603 1604ASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI, 1605 StringRef InFile) { 1606 PPConditionalDirectiveRecord * 1607 PPRec = new PPConditionalDirectiveRecord(CI.getSourceManager()); 1608 CI.getPreprocessor().addPPCallbacks(PPRec); 1609 return new ObjCMigrateASTConsumer(CI.getFrontendOpts().OutputFile, 1610 FrontendOptions::ObjCMT_MigrateAll, 1611 Remapper, 1612 CI.getFileManager(), 1613 PPRec, 1614 CI.getPreprocessor(), 1615 /*isOutputFile=*/true); 1616} 1617