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/ARCMT.h" 12 #include "clang/ARCMigrate/ARCMTActions.h" 13 #include "clang/AST/ASTConsumer.h" 14 #include "clang/AST/ASTContext.h" 15 #include "clang/AST/Attr.h" 16 #include "clang/AST/NSAPI.h" 17 #include "clang/AST/ParentMap.h" 18 #include "clang/AST/RecursiveASTVisitor.h" 19 #include "clang/Analysis/DomainSpecific/CocoaConventions.h" 20 #include "clang/Basic/FileManager.h" 21 #include "clang/Edit/Commit.h" 22 #include "clang/Edit/EditedSource.h" 23 #include "clang/Edit/EditsReceiver.h" 24 #include "clang/Edit/Rewriters.h" 25 #include "clang/Frontend/CompilerInstance.h" 26 #include "clang/Frontend/MultiplexConsumer.h" 27 #include "clang/Lex/PPConditionalDirectiveRecord.h" 28 #include "clang/Lex/Preprocessor.h" 29 #include "clang/Rewrite/Core/Rewriter.h" 30 #include "clang/StaticAnalyzer/Checkers/ObjCRetainCount.h" 31 #include "llvm/ADT/SmallString.h" 32 #include "llvm/Support/Path.h" 33 #include "llvm/Support/SourceMgr.h" 34 #include "llvm/Support/YAMLParser.h" 35 36 using namespace clang; 37 using namespace arcmt; 38 using namespace ento::objc_retain; 39 40 namespace { 41 42 class ObjCMigrateASTConsumer : public ASTConsumer { 43 enum CF_BRIDGING_KIND { 44 CF_BRIDGING_NONE, 45 CF_BRIDGING_ENABLE, 46 CF_BRIDGING_MAY_INCLUDE 47 }; 48 49 void migrateDecl(Decl *D); 50 void migrateObjCInterfaceDecl(ASTContext &Ctx, ObjCContainerDecl *D); 51 void migrateProtocolConformance(ASTContext &Ctx, 52 const ObjCImplementationDecl *ImpDecl); 53 void CacheObjCNSIntegerTypedefed(const TypedefDecl *TypedefDcl); 54 bool migrateNSEnumDecl(ASTContext &Ctx, const EnumDecl *EnumDcl, 55 const TypedefDecl *TypedefDcl); 56 void migrateAllMethodInstaceType(ASTContext &Ctx, ObjCContainerDecl *CDecl); 57 void migrateMethodInstanceType(ASTContext &Ctx, ObjCContainerDecl *CDecl, 58 ObjCMethodDecl *OM); 59 bool migrateProperty(ASTContext &Ctx, ObjCContainerDecl *D, ObjCMethodDecl *OM); 60 void migrateNsReturnsInnerPointer(ASTContext &Ctx, ObjCMethodDecl *OM); 61 void migratePropertyNsReturnsInnerPointer(ASTContext &Ctx, ObjCPropertyDecl *P); 62 void migrateFactoryMethod(ASTContext &Ctx, ObjCContainerDecl *CDecl, 63 ObjCMethodDecl *OM, 64 ObjCInstanceTypeFamily OIT_Family = OIT_None); 65 66 void migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl); 67 void AddCFAnnotations(ASTContext &Ctx, const CallEffects &CE, 68 const FunctionDecl *FuncDecl, bool ResultAnnotated); 69 void AddCFAnnotations(ASTContext &Ctx, const CallEffects &CE, 70 const ObjCMethodDecl *MethodDecl, bool ResultAnnotated); 71 72 void AnnotateImplicitBridging(ASTContext &Ctx); 73 74 CF_BRIDGING_KIND migrateAddFunctionAnnotation(ASTContext &Ctx, 75 const FunctionDecl *FuncDecl); 76 77 void migrateARCSafeAnnotation(ASTContext &Ctx, ObjCContainerDecl *CDecl); 78 79 void migrateAddMethodAnnotation(ASTContext &Ctx, 80 const ObjCMethodDecl *MethodDecl); 81 82 void inferDesignatedInitializers(ASTContext &Ctx, 83 const ObjCImplementationDecl *ImplD); 84 85 public: 86 std::string MigrateDir; 87 unsigned ASTMigrateActions; 88 FileID FileId; 89 const TypedefDecl *NSIntegerTypedefed; 90 const TypedefDecl *NSUIntegerTypedefed; 91 std::unique_ptr<NSAPI> NSAPIObj; 92 std::unique_ptr<edit::EditedSource> Editor; 93 FileRemapper &Remapper; 94 FileManager &FileMgr; 95 const PPConditionalDirectiveRecord *PPRec; 96 Preprocessor &PP; 97 bool IsOutputFile; 98 llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ObjCProtocolDecls; 99 llvm::SmallVector<const Decl *, 8> CFFunctionIBCandidates; 100 llvm::StringMap<char> WhiteListFilenames; 101 102 ObjCMigrateASTConsumer(StringRef migrateDir, 103 unsigned astMigrateActions, 104 FileRemapper &remapper, 105 FileManager &fileMgr, 106 const PPConditionalDirectiveRecord *PPRec, 107 Preprocessor &PP, 108 bool isOutputFile, 109 ArrayRef<std::string> WhiteList) 110 : MigrateDir(migrateDir), 111 ASTMigrateActions(astMigrateActions), 112 NSIntegerTypedefed(0), NSUIntegerTypedefed(0), 113 Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec), PP(PP), 114 IsOutputFile(isOutputFile) { 115 116 for (ArrayRef<std::string>::iterator 117 I = WhiteList.begin(), E = WhiteList.end(); I != E; ++I) { 118 WhiteListFilenames.GetOrCreateValue(*I); 119 } 120 } 121 122 protected: 123 virtual void Initialize(ASTContext &Context) { 124 NSAPIObj.reset(new NSAPI(Context)); 125 Editor.reset(new edit::EditedSource(Context.getSourceManager(), 126 Context.getLangOpts(), 127 PPRec, false)); 128 } 129 130 virtual bool HandleTopLevelDecl(DeclGroupRef DG) { 131 for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) 132 migrateDecl(*I); 133 return true; 134 } 135 virtual void HandleInterestingDecl(DeclGroupRef DG) { 136 // Ignore decls from the PCH. 137 } 138 virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) { 139 ObjCMigrateASTConsumer::HandleTopLevelDecl(DG); 140 } 141 142 virtual void HandleTranslationUnit(ASTContext &Ctx); 143 144 bool canModifyFile(StringRef Path) { 145 if (WhiteListFilenames.empty()) 146 return true; 147 return WhiteListFilenames.find(llvm::sys::path::filename(Path)) 148 != WhiteListFilenames.end(); 149 } 150 bool canModifyFile(const FileEntry *FE) { 151 if (!FE) 152 return false; 153 return canModifyFile(FE->getName()); 154 } 155 bool canModifyFile(FileID FID) { 156 if (FID.isInvalid()) 157 return false; 158 return canModifyFile(PP.getSourceManager().getFileEntryForID(FID)); 159 } 160 161 bool canModify(const Decl *D) { 162 if (!D) 163 return false; 164 if (const ObjCCategoryImplDecl *CatImpl = dyn_cast<ObjCCategoryImplDecl>(D)) 165 return canModify(CatImpl->getCategoryDecl()); 166 if (const ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(D)) 167 return canModify(Impl->getClassInterface()); 168 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) 169 return canModify(cast<Decl>(MD->getDeclContext())); 170 171 FileID FID = PP.getSourceManager().getFileID(D->getLocation()); 172 return canModifyFile(FID); 173 } 174 }; 175 176 } 177 178 ObjCMigrateAction::ObjCMigrateAction(FrontendAction *WrappedAction, 179 StringRef migrateDir, 180 unsigned migrateAction) 181 : WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir), 182 ObjCMigAction(migrateAction), 183 CompInst(0) { 184 if (MigrateDir.empty()) 185 MigrateDir = "."; // user current directory if none is given. 186 } 187 188 ASTConsumer *ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI, 189 StringRef InFile) { 190 PPConditionalDirectiveRecord * 191 PPRec = new PPConditionalDirectiveRecord(CompInst->getSourceManager()); 192 CompInst->getPreprocessor().addPPCallbacks(PPRec); 193 ASTConsumer * 194 WrappedConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile); 195 ASTConsumer *MTConsumer = new ObjCMigrateASTConsumer(MigrateDir, 196 ObjCMigAction, 197 Remapper, 198 CompInst->getFileManager(), 199 PPRec, 200 CompInst->getPreprocessor(), 201 false, 202 ArrayRef<std::string>()); 203 ASTConsumer *Consumers[] = { MTConsumer, WrappedConsumer }; 204 return new MultiplexConsumer(Consumers); 205 } 206 207 bool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) { 208 Remapper.initFromDisk(MigrateDir, CI.getDiagnostics(), 209 /*ignoreIfFilesChanges=*/true); 210 CompInst = &CI; 211 CI.getDiagnostics().setIgnoreAllWarnings(true); 212 return true; 213 } 214 215 namespace { 216 class ObjCMigrator : public RecursiveASTVisitor<ObjCMigrator> { 217 ObjCMigrateASTConsumer &Consumer; 218 ParentMap &PMap; 219 220 public: 221 ObjCMigrator(ObjCMigrateASTConsumer &consumer, ParentMap &PMap) 222 : Consumer(consumer), PMap(PMap) { } 223 224 bool shouldVisitTemplateInstantiations() const { return false; } 225 bool shouldWalkTypesOfTypeLocs() const { return false; } 226 227 bool VisitObjCMessageExpr(ObjCMessageExpr *E) { 228 if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_Literals) { 229 edit::Commit commit(*Consumer.Editor); 230 edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit, &PMap); 231 Consumer.Editor->commit(commit); 232 } 233 234 if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_Subscripting) { 235 edit::Commit commit(*Consumer.Editor); 236 edit::rewriteToObjCSubscriptSyntax(E, *Consumer.NSAPIObj, commit); 237 Consumer.Editor->commit(commit); 238 } 239 240 return true; 241 } 242 243 bool TraverseObjCMessageExpr(ObjCMessageExpr *E) { 244 // Do depth first; we want to rewrite the subexpressions first so that if 245 // we have to move expressions we will move them already rewritten. 246 for (Stmt::child_range range = E->children(); range; ++range) 247 if (!TraverseStmt(*range)) 248 return false; 249 250 return WalkUpFromObjCMessageExpr(E); 251 } 252 }; 253 254 class BodyMigrator : public RecursiveASTVisitor<BodyMigrator> { 255 ObjCMigrateASTConsumer &Consumer; 256 std::unique_ptr<ParentMap> PMap; 257 258 public: 259 BodyMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { } 260 261 bool shouldVisitTemplateInstantiations() const { return false; } 262 bool shouldWalkTypesOfTypeLocs() const { return false; } 263 264 bool TraverseStmt(Stmt *S) { 265 PMap.reset(new ParentMap(S)); 266 ObjCMigrator(Consumer, *PMap).TraverseStmt(S); 267 return true; 268 } 269 }; 270 } 271 272 void ObjCMigrateASTConsumer::migrateDecl(Decl *D) { 273 if (!D) 274 return; 275 if (isa<ObjCMethodDecl>(D)) 276 return; // Wait for the ObjC container declaration. 277 278 BodyMigrator(*this).TraverseDecl(D); 279 } 280 281 static void append_attr(std::string &PropertyString, const char *attr, 282 bool &LParenAdded) { 283 if (!LParenAdded) { 284 PropertyString += "("; 285 LParenAdded = true; 286 } 287 else 288 PropertyString += ", "; 289 PropertyString += attr; 290 } 291 292 static 293 void MigrateBlockOrFunctionPointerTypeVariable(std::string & PropertyString, 294 const std::string& TypeString, 295 const char *name) { 296 const char *argPtr = TypeString.c_str(); 297 int paren = 0; 298 while (*argPtr) { 299 switch (*argPtr) { 300 case '(': 301 PropertyString += *argPtr; 302 paren++; 303 break; 304 case ')': 305 PropertyString += *argPtr; 306 paren--; 307 break; 308 case '^': 309 case '*': 310 PropertyString += (*argPtr); 311 if (paren == 1) { 312 PropertyString += name; 313 name = ""; 314 } 315 break; 316 default: 317 PropertyString += *argPtr; 318 break; 319 } 320 argPtr++; 321 } 322 } 323 324 static const char *PropertyMemoryAttribute(ASTContext &Context, QualType ArgType) { 325 Qualifiers::ObjCLifetime propertyLifetime = ArgType.getObjCLifetime(); 326 bool RetainableObject = ArgType->isObjCRetainableType(); 327 if (RetainableObject && 328 (propertyLifetime == Qualifiers::OCL_Strong 329 || propertyLifetime == Qualifiers::OCL_None)) { 330 if (const ObjCObjectPointerType *ObjPtrTy = 331 ArgType->getAs<ObjCObjectPointerType>()) { 332 ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface(); 333 if (IDecl && 334 IDecl->lookupNestedProtocol(&Context.Idents.get("NSCopying"))) 335 return "copy"; 336 else 337 return "strong"; 338 } 339 else if (ArgType->isBlockPointerType()) 340 return "copy"; 341 } else if (propertyLifetime == Qualifiers::OCL_Weak) 342 // TODO. More precise determination of 'weak' attribute requires 343 // looking into setter's implementation for backing weak ivar. 344 return "weak"; 345 else if (RetainableObject) 346 return ArgType->isBlockPointerType() ? "copy" : "strong"; 347 return 0; 348 } 349 350 static void rewriteToObjCProperty(const ObjCMethodDecl *Getter, 351 const ObjCMethodDecl *Setter, 352 const NSAPI &NS, edit::Commit &commit, 353 unsigned LengthOfPrefix, 354 bool Atomic, bool UseNsIosOnlyMacro, 355 bool AvailabilityArgsMatch) { 356 ASTContext &Context = NS.getASTContext(); 357 bool LParenAdded = false; 358 std::string PropertyString = "@property "; 359 if (UseNsIosOnlyMacro && Context.Idents.get("NS_NONATOMIC_IOSONLY").hasMacroDefinition()) { 360 PropertyString += "(NS_NONATOMIC_IOSONLY"; 361 LParenAdded = true; 362 } else if (!Atomic) { 363 PropertyString += "(nonatomic"; 364 LParenAdded = true; 365 } 366 367 std::string PropertyNameString = Getter->getNameAsString(); 368 StringRef PropertyName(PropertyNameString); 369 if (LengthOfPrefix > 0) { 370 if (!LParenAdded) { 371 PropertyString += "(getter="; 372 LParenAdded = true; 373 } 374 else 375 PropertyString += ", getter="; 376 PropertyString += PropertyNameString; 377 } 378 // Property with no setter may be suggested as a 'readonly' property. 379 if (!Setter) 380 append_attr(PropertyString, "readonly", LParenAdded); 381 382 383 // Short circuit 'delegate' properties that contain the name "delegate" or 384 // "dataSource", or have exact name "target" to have 'assign' attribute. 385 if (PropertyName.equals("target") || 386 (PropertyName.find("delegate") != StringRef::npos) || 387 (PropertyName.find("dataSource") != StringRef::npos)) { 388 QualType QT = Getter->getReturnType(); 389 if (!QT->isRealType()) 390 append_attr(PropertyString, "assign", LParenAdded); 391 } else if (!Setter) { 392 QualType ResType = Context.getCanonicalType(Getter->getReturnType()); 393 if (const char *MemoryManagementAttr = PropertyMemoryAttribute(Context, ResType)) 394 append_attr(PropertyString, MemoryManagementAttr, LParenAdded); 395 } else { 396 const ParmVarDecl *argDecl = *Setter->param_begin(); 397 QualType ArgType = Context.getCanonicalType(argDecl->getType()); 398 if (const char *MemoryManagementAttr = PropertyMemoryAttribute(Context, ArgType)) 399 append_attr(PropertyString, MemoryManagementAttr, LParenAdded); 400 } 401 if (LParenAdded) 402 PropertyString += ')'; 403 QualType RT = Getter->getReturnType(); 404 if (!isa<TypedefType>(RT)) { 405 // strip off any ARC lifetime qualifier. 406 QualType CanResultTy = Context.getCanonicalType(RT); 407 if (CanResultTy.getQualifiers().hasObjCLifetime()) { 408 Qualifiers Qs = CanResultTy.getQualifiers(); 409 Qs.removeObjCLifetime(); 410 RT = Context.getQualifiedType(CanResultTy.getUnqualifiedType(), Qs); 411 } 412 } 413 PropertyString += " "; 414 PrintingPolicy SubPolicy(Context.getPrintingPolicy()); 415 SubPolicy.SuppressStrongLifetime = true; 416 SubPolicy.SuppressLifetimeQualifiers = true; 417 std::string TypeString = RT.getAsString(SubPolicy); 418 if (LengthOfPrefix > 0) { 419 // property name must strip off "is" and lower case the first character 420 // after that; e.g. isContinuous will become continuous. 421 StringRef PropertyNameStringRef(PropertyNameString); 422 PropertyNameStringRef = PropertyNameStringRef.drop_front(LengthOfPrefix); 423 PropertyNameString = PropertyNameStringRef; 424 bool NoLowering = (isUppercase(PropertyNameString[0]) && 425 PropertyNameString.size() > 1 && 426 isUppercase(PropertyNameString[1])); 427 if (!NoLowering) 428 PropertyNameString[0] = toLowercase(PropertyNameString[0]); 429 } 430 if (RT->isBlockPointerType() || RT->isFunctionPointerType()) 431 MigrateBlockOrFunctionPointerTypeVariable(PropertyString, 432 TypeString, 433 PropertyNameString.c_str()); 434 else { 435 char LastChar = TypeString[TypeString.size()-1]; 436 PropertyString += TypeString; 437 if (LastChar != '*') 438 PropertyString += ' '; 439 PropertyString += PropertyNameString; 440 } 441 SourceLocation StartGetterSelectorLoc = Getter->getSelectorStartLoc(); 442 Selector GetterSelector = Getter->getSelector(); 443 444 SourceLocation EndGetterSelectorLoc = 445 StartGetterSelectorLoc.getLocWithOffset(GetterSelector.getNameForSlot(0).size()); 446 commit.replace(CharSourceRange::getCharRange(Getter->getLocStart(), 447 EndGetterSelectorLoc), 448 PropertyString); 449 if (Setter && AvailabilityArgsMatch) { 450 SourceLocation EndLoc = Setter->getDeclaratorEndLoc(); 451 // Get location past ';' 452 EndLoc = EndLoc.getLocWithOffset(1); 453 SourceLocation BeginOfSetterDclLoc = Setter->getLocStart(); 454 // FIXME. This assumes that setter decl; is immediately preceded by eoln. 455 // It is trying to remove the setter method decl. line entirely. 456 BeginOfSetterDclLoc = BeginOfSetterDclLoc.getLocWithOffset(-1); 457 commit.remove(SourceRange(BeginOfSetterDclLoc, EndLoc)); 458 } 459 } 460 461 static bool IsCategoryNameWithDeprecatedSuffix(ObjCContainerDecl *D) { 462 if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(D)) { 463 StringRef Name = CatDecl->getName(); 464 return Name.endswith("Deprecated"); 465 } 466 return false; 467 } 468 469 void ObjCMigrateASTConsumer::migrateObjCInterfaceDecl(ASTContext &Ctx, 470 ObjCContainerDecl *D) { 471 if (D->isDeprecated() || IsCategoryNameWithDeprecatedSuffix(D)) 472 return; 473 474 for (ObjCContainerDecl::method_iterator M = D->meth_begin(), MEnd = D->meth_end(); 475 M != MEnd; ++M) { 476 ObjCMethodDecl *Method = (*M); 477 if (Method->isDeprecated()) 478 continue; 479 bool PropertyInferred = migrateProperty(Ctx, D, Method); 480 // If a property is inferred, do not attempt to attach NS_RETURNS_INNER_POINTER to 481 // the getter method as it ends up on the property itself which we don't want 482 // to do unless -objcmt-returns-innerpointer-property option is on. 483 if (!PropertyInferred || 484 (ASTMigrateActions & FrontendOptions::ObjCMT_ReturnsInnerPointerProperty)) 485 if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) 486 migrateNsReturnsInnerPointer(Ctx, Method); 487 } 488 if (!(ASTMigrateActions & FrontendOptions::ObjCMT_ReturnsInnerPointerProperty)) 489 return; 490 491 for (ObjCContainerDecl::prop_iterator P = D->prop_begin(), 492 E = D->prop_end(); P != E; ++P) { 493 ObjCPropertyDecl *Prop = *P; 494 if ((ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) && 495 !Prop->isDeprecated()) 496 migratePropertyNsReturnsInnerPointer(Ctx, Prop); 497 } 498 } 499 500 static bool 501 ClassImplementsAllMethodsAndProperties(ASTContext &Ctx, 502 const ObjCImplementationDecl *ImpDecl, 503 const ObjCInterfaceDecl *IDecl, 504 ObjCProtocolDecl *Protocol) { 505 // In auto-synthesis, protocol properties are not synthesized. So, 506 // a conforming protocol must have its required properties declared 507 // in class interface. 508 bool HasAtleastOneRequiredProperty = false; 509 if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition()) 510 for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), 511 E = PDecl->prop_end(); P != E; ++P) { 512 ObjCPropertyDecl *Property = *P; 513 if (Property->getPropertyImplementation() == ObjCPropertyDecl::Optional) 514 continue; 515 HasAtleastOneRequiredProperty = true; 516 DeclContext::lookup_const_result R = IDecl->lookup(Property->getDeclName()); 517 if (R.size() == 0) { 518 // Relax the rule and look into class's implementation for a synthesize 519 // or dynamic declaration. Class is implementing a property coming from 520 // another protocol. This still makes the target protocol as conforming. 521 if (!ImpDecl->FindPropertyImplDecl( 522 Property->getDeclName().getAsIdentifierInfo())) 523 return false; 524 } 525 else if (ObjCPropertyDecl *ClassProperty = dyn_cast<ObjCPropertyDecl>(R[0])) { 526 if ((ClassProperty->getPropertyAttributes() 527 != Property->getPropertyAttributes()) || 528 !Ctx.hasSameType(ClassProperty->getType(), Property->getType())) 529 return false; 530 } 531 else 532 return false; 533 } 534 535 // At this point, all required properties in this protocol conform to those 536 // declared in the class. 537 // Check that class implements the required methods of the protocol too. 538 bool HasAtleastOneRequiredMethod = false; 539 if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition()) { 540 if (PDecl->meth_begin() == PDecl->meth_end()) 541 return HasAtleastOneRequiredProperty; 542 for (ObjCContainerDecl::method_iterator M = PDecl->meth_begin(), 543 MEnd = PDecl->meth_end(); M != MEnd; ++M) { 544 ObjCMethodDecl *MD = (*M); 545 if (MD->isImplicit()) 546 continue; 547 if (MD->getImplementationControl() == ObjCMethodDecl::Optional) 548 continue; 549 DeclContext::lookup_const_result R = ImpDecl->lookup(MD->getDeclName()); 550 if (R.size() == 0) 551 return false; 552 bool match = false; 553 HasAtleastOneRequiredMethod = true; 554 for (unsigned I = 0, N = R.size(); I != N; ++I) 555 if (ObjCMethodDecl *ImpMD = dyn_cast<ObjCMethodDecl>(R[0])) 556 if (Ctx.ObjCMethodsAreEqual(MD, ImpMD)) { 557 match = true; 558 break; 559 } 560 if (!match) 561 return false; 562 } 563 } 564 if (HasAtleastOneRequiredProperty || HasAtleastOneRequiredMethod) 565 return true; 566 return false; 567 } 568 569 static bool rewriteToObjCInterfaceDecl(const ObjCInterfaceDecl *IDecl, 570 llvm::SmallVectorImpl<ObjCProtocolDecl*> &ConformingProtocols, 571 const NSAPI &NS, edit::Commit &commit) { 572 const ObjCList<ObjCProtocolDecl> &Protocols = IDecl->getReferencedProtocols(); 573 std::string ClassString; 574 SourceLocation EndLoc = 575 IDecl->getSuperClass() ? IDecl->getSuperClassLoc() : IDecl->getLocation(); 576 577 if (Protocols.empty()) { 578 ClassString = '<'; 579 for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) { 580 ClassString += ConformingProtocols[i]->getNameAsString(); 581 if (i != (e-1)) 582 ClassString += ", "; 583 } 584 ClassString += "> "; 585 } 586 else { 587 ClassString = ", "; 588 for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) { 589 ClassString += ConformingProtocols[i]->getNameAsString(); 590 if (i != (e-1)) 591 ClassString += ", "; 592 } 593 ObjCInterfaceDecl::protocol_loc_iterator PL = IDecl->protocol_loc_end() - 1; 594 EndLoc = *PL; 595 } 596 597 commit.insertAfterToken(EndLoc, ClassString); 598 return true; 599 } 600 601 static bool rewriteToNSEnumDecl(const EnumDecl *EnumDcl, 602 const TypedefDecl *TypedefDcl, 603 const NSAPI &NS, edit::Commit &commit, 604 bool IsNSIntegerType, 605 bool NSOptions) { 606 std::string ClassString; 607 if (NSOptions) 608 ClassString = "typedef NS_OPTIONS(NSUInteger, "; 609 else 610 ClassString = 611 IsNSIntegerType ? "typedef NS_ENUM(NSInteger, " 612 : "typedef NS_ENUM(NSUInteger, "; 613 614 ClassString += TypedefDcl->getIdentifier()->getName(); 615 ClassString += ')'; 616 SourceRange R(EnumDcl->getLocStart(), EnumDcl->getLocStart()); 617 commit.replace(R, ClassString); 618 SourceLocation EndOfEnumDclLoc = EnumDcl->getLocEnd(); 619 EndOfEnumDclLoc = trans::findSemiAfterLocation(EndOfEnumDclLoc, 620 NS.getASTContext(), /*IsDecl*/true); 621 if (!EndOfEnumDclLoc.isInvalid()) { 622 SourceRange EnumDclRange(EnumDcl->getLocStart(), EndOfEnumDclLoc); 623 commit.insertFromRange(TypedefDcl->getLocStart(), EnumDclRange); 624 } 625 else 626 return false; 627 628 SourceLocation EndTypedefDclLoc = TypedefDcl->getLocEnd(); 629 EndTypedefDclLoc = trans::findSemiAfterLocation(EndTypedefDclLoc, 630 NS.getASTContext(), /*IsDecl*/true); 631 if (!EndTypedefDclLoc.isInvalid()) { 632 SourceRange TDRange(TypedefDcl->getLocStart(), EndTypedefDclLoc); 633 commit.remove(TDRange); 634 } 635 else 636 return false; 637 638 EndOfEnumDclLoc = trans::findLocationAfterSemi(EnumDcl->getLocEnd(), NS.getASTContext(), 639 /*IsDecl*/true); 640 if (!EndOfEnumDclLoc.isInvalid()) { 641 SourceLocation BeginOfEnumDclLoc = EnumDcl->getLocStart(); 642 // FIXME. This assumes that enum decl; is immediately preceded by eoln. 643 // It is trying to remove the enum decl. lines entirely. 644 BeginOfEnumDclLoc = BeginOfEnumDclLoc.getLocWithOffset(-1); 645 commit.remove(SourceRange(BeginOfEnumDclLoc, EndOfEnumDclLoc)); 646 return true; 647 } 648 return false; 649 } 650 651 static void rewriteToNSMacroDecl(const EnumDecl *EnumDcl, 652 const TypedefDecl *TypedefDcl, 653 const NSAPI &NS, edit::Commit &commit, 654 bool IsNSIntegerType) { 655 std::string ClassString = 656 IsNSIntegerType ? "NS_ENUM(NSInteger, " : "NS_OPTIONS(NSUInteger, "; 657 ClassString += TypedefDcl->getIdentifier()->getName(); 658 ClassString += ')'; 659 SourceRange R(EnumDcl->getLocStart(), EnumDcl->getLocStart()); 660 commit.replace(R, ClassString); 661 SourceLocation TypedefLoc = TypedefDcl->getLocEnd(); 662 commit.remove(SourceRange(TypedefLoc, TypedefLoc)); 663 } 664 665 static bool UseNSOptionsMacro(Preprocessor &PP, ASTContext &Ctx, 666 const EnumDecl *EnumDcl) { 667 bool PowerOfTwo = true; 668 bool AllHexdecimalEnumerator = true; 669 uint64_t MaxPowerOfTwoVal = 0; 670 for (auto Enumerator : EnumDcl->enumerators()) { 671 const Expr *InitExpr = Enumerator->getInitExpr(); 672 if (!InitExpr) { 673 PowerOfTwo = false; 674 AllHexdecimalEnumerator = false; 675 continue; 676 } 677 InitExpr = InitExpr->IgnoreParenCasts(); 678 if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(InitExpr)) 679 if (BO->isShiftOp() || BO->isBitwiseOp()) 680 return true; 681 682 uint64_t EnumVal = Enumerator->getInitVal().getZExtValue(); 683 if (PowerOfTwo && EnumVal) { 684 if (!llvm::isPowerOf2_64(EnumVal)) 685 PowerOfTwo = false; 686 else if (EnumVal > MaxPowerOfTwoVal) 687 MaxPowerOfTwoVal = EnumVal; 688 } 689 if (AllHexdecimalEnumerator && EnumVal) { 690 bool FoundHexdecimalEnumerator = false; 691 SourceLocation EndLoc = Enumerator->getLocEnd(); 692 Token Tok; 693 if (!PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true)) 694 if (Tok.isLiteral() && Tok.getLength() > 2) { 695 if (const char *StringLit = Tok.getLiteralData()) 696 FoundHexdecimalEnumerator = 697 (StringLit[0] == '0' && (toLowercase(StringLit[1]) == 'x')); 698 } 699 if (!FoundHexdecimalEnumerator) 700 AllHexdecimalEnumerator = false; 701 } 702 } 703 return AllHexdecimalEnumerator || (PowerOfTwo && (MaxPowerOfTwoVal > 2)); 704 } 705 706 void ObjCMigrateASTConsumer::migrateProtocolConformance(ASTContext &Ctx, 707 const ObjCImplementationDecl *ImpDecl) { 708 const ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface(); 709 if (!IDecl || ObjCProtocolDecls.empty() || IDecl->isDeprecated()) 710 return; 711 // Find all implicit conforming protocols for this class 712 // and make them explicit. 713 llvm::SmallPtrSet<ObjCProtocolDecl *, 8> ExplicitProtocols; 714 Ctx.CollectInheritedProtocols(IDecl, ExplicitProtocols); 715 llvm::SmallVector<ObjCProtocolDecl *, 8> PotentialImplicitProtocols; 716 717 for (llvm::SmallPtrSet<ObjCProtocolDecl*, 32>::iterator I = 718 ObjCProtocolDecls.begin(), 719 E = ObjCProtocolDecls.end(); I != E; ++I) 720 if (!ExplicitProtocols.count(*I)) 721 PotentialImplicitProtocols.push_back(*I); 722 723 if (PotentialImplicitProtocols.empty()) 724 return; 725 726 // go through list of non-optional methods and properties in each protocol 727 // in the PotentialImplicitProtocols list. If class implements every one of the 728 // methods and properties, then this class conforms to this protocol. 729 llvm::SmallVector<ObjCProtocolDecl*, 8> ConformingProtocols; 730 for (unsigned i = 0, e = PotentialImplicitProtocols.size(); i != e; i++) 731 if (ClassImplementsAllMethodsAndProperties(Ctx, ImpDecl, IDecl, 732 PotentialImplicitProtocols[i])) 733 ConformingProtocols.push_back(PotentialImplicitProtocols[i]); 734 735 if (ConformingProtocols.empty()) 736 return; 737 738 // Further reduce number of conforming protocols. If protocol P1 is in the list 739 // protocol P2 (P2<P1>), No need to include P1. 740 llvm::SmallVector<ObjCProtocolDecl*, 8> MinimalConformingProtocols; 741 for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) { 742 bool DropIt = false; 743 ObjCProtocolDecl *TargetPDecl = ConformingProtocols[i]; 744 for (unsigned i1 = 0, e1 = ConformingProtocols.size(); i1 != e1; i1++) { 745 ObjCProtocolDecl *PDecl = ConformingProtocols[i1]; 746 if (PDecl == TargetPDecl) 747 continue; 748 if (PDecl->lookupProtocolNamed( 749 TargetPDecl->getDeclName().getAsIdentifierInfo())) { 750 DropIt = true; 751 break; 752 } 753 } 754 if (!DropIt) 755 MinimalConformingProtocols.push_back(TargetPDecl); 756 } 757 if (MinimalConformingProtocols.empty()) 758 return; 759 edit::Commit commit(*Editor); 760 rewriteToObjCInterfaceDecl(IDecl, MinimalConformingProtocols, 761 *NSAPIObj, commit); 762 Editor->commit(commit); 763 } 764 765 void ObjCMigrateASTConsumer::CacheObjCNSIntegerTypedefed( 766 const TypedefDecl *TypedefDcl) { 767 768 QualType qt = TypedefDcl->getTypeSourceInfo()->getType(); 769 if (NSAPIObj->isObjCNSIntegerType(qt)) 770 NSIntegerTypedefed = TypedefDcl; 771 else if (NSAPIObj->isObjCNSUIntegerType(qt)) 772 NSUIntegerTypedefed = TypedefDcl; 773 } 774 775 bool ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx, 776 const EnumDecl *EnumDcl, 777 const TypedefDecl *TypedefDcl) { 778 if (!EnumDcl->isCompleteDefinition() || EnumDcl->getIdentifier() || 779 EnumDcl->isDeprecated()) 780 return false; 781 if (!TypedefDcl) { 782 if (NSIntegerTypedefed) { 783 TypedefDcl = NSIntegerTypedefed; 784 NSIntegerTypedefed = 0; 785 } 786 else if (NSUIntegerTypedefed) { 787 TypedefDcl = NSUIntegerTypedefed; 788 NSUIntegerTypedefed = 0; 789 } 790 else 791 return false; 792 FileID FileIdOfTypedefDcl = 793 PP.getSourceManager().getFileID(TypedefDcl->getLocation()); 794 FileID FileIdOfEnumDcl = 795 PP.getSourceManager().getFileID(EnumDcl->getLocation()); 796 if (FileIdOfTypedefDcl != FileIdOfEnumDcl) 797 return false; 798 } 799 if (TypedefDcl->isDeprecated()) 800 return false; 801 802 QualType qt = TypedefDcl->getTypeSourceInfo()->getType(); 803 bool IsNSIntegerType = NSAPIObj->isObjCNSIntegerType(qt); 804 bool IsNSUIntegerType = !IsNSIntegerType && NSAPIObj->isObjCNSUIntegerType(qt); 805 806 if (!IsNSIntegerType && !IsNSUIntegerType) { 807 // Also check for typedef enum {...} TD; 808 if (const EnumType *EnumTy = qt->getAs<EnumType>()) { 809 if (EnumTy->getDecl() == EnumDcl) { 810 bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl); 811 if (NSOptions) { 812 if (!Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition()) 813 return false; 814 } 815 else if (!Ctx.Idents.get("NS_ENUM").hasMacroDefinition()) 816 return false; 817 edit::Commit commit(*Editor); 818 rewriteToNSMacroDecl(EnumDcl, TypedefDcl, *NSAPIObj, commit, !NSOptions); 819 Editor->commit(commit); 820 return true; 821 } 822 } 823 return false; 824 } 825 826 // We may still use NS_OPTIONS based on what we find in the enumertor list. 827 bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl); 828 // NS_ENUM must be available. 829 if (IsNSIntegerType && !Ctx.Idents.get("NS_ENUM").hasMacroDefinition()) 830 return false; 831 // NS_OPTIONS must be available. 832 if (IsNSUIntegerType && !Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition()) 833 return false; 834 edit::Commit commit(*Editor); 835 bool Res = rewriteToNSEnumDecl(EnumDcl, TypedefDcl, *NSAPIObj, 836 commit, IsNSIntegerType, NSOptions); 837 Editor->commit(commit); 838 return Res; 839 } 840 841 static void ReplaceWithInstancetype(const ObjCMigrateASTConsumer &ASTC, 842 ObjCMethodDecl *OM) { 843 SourceRange R; 844 std::string ClassString; 845 if (TypeSourceInfo *TSInfo = OM->getReturnTypeSourceInfo()) { 846 TypeLoc TL = TSInfo->getTypeLoc(); 847 R = SourceRange(TL.getBeginLoc(), TL.getEndLoc()); 848 ClassString = "instancetype"; 849 } 850 else { 851 R = SourceRange(OM->getLocStart(), OM->getLocStart()); 852 ClassString = OM->isInstanceMethod() ? '-' : '+'; 853 ClassString += " (instancetype)"; 854 } 855 edit::Commit commit(*ASTC.Editor); 856 commit.replace(R, ClassString); 857 ASTC.Editor->commit(commit); 858 } 859 860 static void ReplaceWithClasstype(const ObjCMigrateASTConsumer &ASTC, 861 ObjCMethodDecl *OM) { 862 ObjCInterfaceDecl *IDecl = OM->getClassInterface(); 863 SourceRange R; 864 std::string ClassString; 865 if (TypeSourceInfo *TSInfo = OM->getReturnTypeSourceInfo()) { 866 TypeLoc TL = TSInfo->getTypeLoc(); 867 R = SourceRange(TL.getBeginLoc(), TL.getEndLoc()); { 868 ClassString = IDecl->getName(); 869 ClassString += "*"; 870 } 871 } 872 else { 873 R = SourceRange(OM->getLocStart(), OM->getLocStart()); 874 ClassString = "+ ("; 875 ClassString += IDecl->getName(); ClassString += "*)"; 876 } 877 edit::Commit commit(*ASTC.Editor); 878 commit.replace(R, ClassString); 879 ASTC.Editor->commit(commit); 880 } 881 882 void ObjCMigrateASTConsumer::migrateMethodInstanceType(ASTContext &Ctx, 883 ObjCContainerDecl *CDecl, 884 ObjCMethodDecl *OM) { 885 ObjCInstanceTypeFamily OIT_Family = 886 Selector::getInstTypeMethodFamily(OM->getSelector()); 887 888 std::string ClassName; 889 switch (OIT_Family) { 890 case OIT_None: 891 migrateFactoryMethod(Ctx, CDecl, OM); 892 return; 893 case OIT_Array: 894 ClassName = "NSArray"; 895 break; 896 case OIT_Dictionary: 897 ClassName = "NSDictionary"; 898 break; 899 case OIT_Singleton: 900 migrateFactoryMethod(Ctx, CDecl, OM, OIT_Singleton); 901 return; 902 case OIT_Init: 903 if (OM->getReturnType()->isObjCIdType()) 904 ReplaceWithInstancetype(*this, OM); 905 return; 906 case OIT_ReturnsSelf: 907 migrateFactoryMethod(Ctx, CDecl, OM, OIT_ReturnsSelf); 908 return; 909 } 910 if (!OM->getReturnType()->isObjCIdType()) 911 return; 912 913 ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl); 914 if (!IDecl) { 915 if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) 916 IDecl = CatDecl->getClassInterface(); 917 else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl)) 918 IDecl = ImpDecl->getClassInterface(); 919 } 920 if (!IDecl || 921 !IDecl->lookupInheritedClass(&Ctx.Idents.get(ClassName))) { 922 migrateFactoryMethod(Ctx, CDecl, OM); 923 return; 924 } 925 ReplaceWithInstancetype(*this, OM); 926 } 927 928 static bool TypeIsInnerPointer(QualType T) { 929 if (!T->isAnyPointerType()) 930 return false; 931 if (T->isObjCObjectPointerType() || T->isObjCBuiltinType() || 932 T->isBlockPointerType() || T->isFunctionPointerType() || 933 ento::coreFoundation::isCFObjectRef(T)) 934 return false; 935 // Also, typedef-of-pointer-to-incomplete-struct is something that we assume 936 // is not an innter pointer type. 937 QualType OrigT = T; 938 while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) 939 T = TD->getDecl()->getUnderlyingType(); 940 if (OrigT == T || !T->isPointerType()) 941 return true; 942 const PointerType* PT = T->getAs<PointerType>(); 943 QualType UPointeeT = PT->getPointeeType().getUnqualifiedType(); 944 if (UPointeeT->isRecordType()) { 945 const RecordType *RecordTy = UPointeeT->getAs<RecordType>(); 946 if (!RecordTy->getDecl()->isCompleteDefinition()) 947 return false; 948 } 949 return true; 950 } 951 952 /// \brief Check whether the two versions match. 953 static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y) { 954 return (X == Y); 955 } 956 957 /// AvailabilityAttrsMatch - This routine checks that if comparing two 958 /// availability attributes, all their components match. It returns 959 /// true, if not dealing with availability or when all components of 960 /// availability attributes match. This routine is only called when 961 /// the attributes are of the same kind. 962 static bool AvailabilityAttrsMatch(Attr *At1, Attr *At2) { 963 const AvailabilityAttr *AA1 = dyn_cast<AvailabilityAttr>(At1); 964 if (!AA1) 965 return true; 966 const AvailabilityAttr *AA2 = dyn_cast<AvailabilityAttr>(At2); 967 968 VersionTuple Introduced1 = AA1->getIntroduced(); 969 VersionTuple Deprecated1 = AA1->getDeprecated(); 970 VersionTuple Obsoleted1 = AA1->getObsoleted(); 971 bool IsUnavailable1 = AA1->getUnavailable(); 972 VersionTuple Introduced2 = AA2->getIntroduced(); 973 VersionTuple Deprecated2 = AA2->getDeprecated(); 974 VersionTuple Obsoleted2 = AA2->getObsoleted(); 975 bool IsUnavailable2 = AA2->getUnavailable(); 976 return (versionsMatch(Introduced1, Introduced2) && 977 versionsMatch(Deprecated1, Deprecated2) && 978 versionsMatch(Obsoleted1, Obsoleted2) && 979 IsUnavailable1 == IsUnavailable2); 980 981 } 982 983 static bool MatchTwoAttributeLists(const AttrVec &Attrs1, const AttrVec &Attrs2, 984 bool &AvailabilityArgsMatch) { 985 // This list is very small, so this need not be optimized. 986 for (unsigned i = 0, e = Attrs1.size(); i != e; i++) { 987 bool match = false; 988 for (unsigned j = 0, f = Attrs2.size(); j != f; j++) { 989 // Matching attribute kind only. Except for Availabilty attributes, 990 // we are not getting into details of the attributes. For all practical purposes 991 // this is sufficient. 992 if (Attrs1[i]->getKind() == Attrs2[j]->getKind()) { 993 if (AvailabilityArgsMatch) 994 AvailabilityArgsMatch = AvailabilityAttrsMatch(Attrs1[i], Attrs2[j]); 995 match = true; 996 break; 997 } 998 } 999 if (!match) 1000 return false; 1001 } 1002 return true; 1003 } 1004 1005 /// AttributesMatch - This routine checks list of attributes for two 1006 /// decls. It returns false, if there is a mismatch in kind of 1007 /// attributes seen in the decls. It returns true if the two decls 1008 /// have list of same kind of attributes. Furthermore, when there 1009 /// are availability attributes in the two decls, it sets the 1010 /// AvailabilityArgsMatch to false if availability attributes have 1011 /// different versions, etc. 1012 static bool AttributesMatch(const Decl *Decl1, const Decl *Decl2, 1013 bool &AvailabilityArgsMatch) { 1014 if (!Decl1->hasAttrs() || !Decl2->hasAttrs()) { 1015 AvailabilityArgsMatch = (Decl1->hasAttrs() == Decl2->hasAttrs()); 1016 return true; 1017 } 1018 AvailabilityArgsMatch = true; 1019 const AttrVec &Attrs1 = Decl1->getAttrs(); 1020 const AttrVec &Attrs2 = Decl2->getAttrs(); 1021 bool match = MatchTwoAttributeLists(Attrs1, Attrs2, AvailabilityArgsMatch); 1022 if (match && (Attrs2.size() > Attrs1.size())) 1023 return MatchTwoAttributeLists(Attrs2, Attrs1, AvailabilityArgsMatch); 1024 return match; 1025 } 1026 1027 static bool IsValidIdentifier(ASTContext &Ctx, 1028 const char *Name) { 1029 if (!isIdentifierHead(Name[0])) 1030 return false; 1031 std::string NameString = Name; 1032 NameString[0] = toLowercase(NameString[0]); 1033 IdentifierInfo *II = &Ctx.Idents.get(NameString); 1034 return II->getTokenID() == tok::identifier; 1035 } 1036 1037 bool ObjCMigrateASTConsumer::migrateProperty(ASTContext &Ctx, 1038 ObjCContainerDecl *D, 1039 ObjCMethodDecl *Method) { 1040 if (Method->isPropertyAccessor() || !Method->isInstanceMethod() || 1041 Method->param_size() != 0) 1042 return false; 1043 // Is this method candidate to be a getter? 1044 QualType GRT = Method->getReturnType(); 1045 if (GRT->isVoidType()) 1046 return false; 1047 1048 Selector GetterSelector = Method->getSelector(); 1049 ObjCInstanceTypeFamily OIT_Family = 1050 Selector::getInstTypeMethodFamily(GetterSelector); 1051 1052 if (OIT_Family != OIT_None) 1053 return false; 1054 1055 IdentifierInfo *getterName = GetterSelector.getIdentifierInfoForSlot(0); 1056 Selector SetterSelector = 1057 SelectorTable::constructSetterSelector(PP.getIdentifierTable(), 1058 PP.getSelectorTable(), 1059 getterName); 1060 ObjCMethodDecl *SetterMethod = D->getInstanceMethod(SetterSelector); 1061 unsigned LengthOfPrefix = 0; 1062 if (!SetterMethod) { 1063 // try a different naming convention for getter: isXxxxx 1064 StringRef getterNameString = getterName->getName(); 1065 bool IsPrefix = getterNameString.startswith("is"); 1066 // Note that we don't want to change an isXXX method of retainable object 1067 // type to property (readonly or otherwise). 1068 if (IsPrefix && GRT->isObjCRetainableType()) 1069 return false; 1070 if (IsPrefix || getterNameString.startswith("get")) { 1071 LengthOfPrefix = (IsPrefix ? 2 : 3); 1072 const char *CGetterName = getterNameString.data() + LengthOfPrefix; 1073 // Make sure that first character after "is" or "get" prefix can 1074 // start an identifier. 1075 if (!IsValidIdentifier(Ctx, CGetterName)) 1076 return false; 1077 if (CGetterName[0] && isUppercase(CGetterName[0])) { 1078 getterName = &Ctx.Idents.get(CGetterName); 1079 SetterSelector = 1080 SelectorTable::constructSetterSelector(PP.getIdentifierTable(), 1081 PP.getSelectorTable(), 1082 getterName); 1083 SetterMethod = D->getInstanceMethod(SetterSelector); 1084 } 1085 } 1086 } 1087 1088 if (SetterMethod) { 1089 if ((ASTMigrateActions & FrontendOptions::ObjCMT_ReadwriteProperty) == 0) 1090 return false; 1091 bool AvailabilityArgsMatch; 1092 if (SetterMethod->isDeprecated() || 1093 !AttributesMatch(Method, SetterMethod, AvailabilityArgsMatch)) 1094 return false; 1095 1096 // Is this a valid setter, matching the target getter? 1097 QualType SRT = SetterMethod->getReturnType(); 1098 if (!SRT->isVoidType()) 1099 return false; 1100 const ParmVarDecl *argDecl = *SetterMethod->param_begin(); 1101 QualType ArgType = argDecl->getType(); 1102 if (!Ctx.hasSameUnqualifiedType(ArgType, GRT)) 1103 return false; 1104 edit::Commit commit(*Editor); 1105 rewriteToObjCProperty(Method, SetterMethod, *NSAPIObj, commit, 1106 LengthOfPrefix, 1107 (ASTMigrateActions & 1108 FrontendOptions::ObjCMT_AtomicProperty) != 0, 1109 (ASTMigrateActions & 1110 FrontendOptions::ObjCMT_NsAtomicIOSOnlyProperty) != 0, 1111 AvailabilityArgsMatch); 1112 Editor->commit(commit); 1113 return true; 1114 } 1115 else if (ASTMigrateActions & FrontendOptions::ObjCMT_ReadonlyProperty) { 1116 // Try a non-void method with no argument (and no setter or property of same name 1117 // as a 'readonly' property. 1118 edit::Commit commit(*Editor); 1119 rewriteToObjCProperty(Method, 0 /*SetterMethod*/, *NSAPIObj, commit, 1120 LengthOfPrefix, 1121 (ASTMigrateActions & 1122 FrontendOptions::ObjCMT_AtomicProperty) != 0, 1123 (ASTMigrateActions & 1124 FrontendOptions::ObjCMT_NsAtomicIOSOnlyProperty) != 0, 1125 /*AvailabilityArgsMatch*/false); 1126 Editor->commit(commit); 1127 return true; 1128 } 1129 return false; 1130 } 1131 1132 void ObjCMigrateASTConsumer::migrateNsReturnsInnerPointer(ASTContext &Ctx, 1133 ObjCMethodDecl *OM) { 1134 if (OM->isImplicit() || 1135 !OM->isInstanceMethod() || 1136 OM->hasAttr<ObjCReturnsInnerPointerAttr>()) 1137 return; 1138 1139 QualType RT = OM->getReturnType(); 1140 if (!TypeIsInnerPointer(RT) || 1141 !Ctx.Idents.get("NS_RETURNS_INNER_POINTER").hasMacroDefinition()) 1142 return; 1143 1144 edit::Commit commit(*Editor); 1145 commit.insertBefore(OM->getLocEnd(), " NS_RETURNS_INNER_POINTER"); 1146 Editor->commit(commit); 1147 } 1148 1149 void ObjCMigrateASTConsumer::migratePropertyNsReturnsInnerPointer(ASTContext &Ctx, 1150 ObjCPropertyDecl *P) { 1151 QualType T = P->getType(); 1152 1153 if (!TypeIsInnerPointer(T) || 1154 !Ctx.Idents.get("NS_RETURNS_INNER_POINTER").hasMacroDefinition()) 1155 return; 1156 edit::Commit commit(*Editor); 1157 commit.insertBefore(P->getLocEnd(), " NS_RETURNS_INNER_POINTER "); 1158 Editor->commit(commit); 1159 } 1160 1161 void ObjCMigrateASTConsumer::migrateAllMethodInstaceType(ASTContext &Ctx, 1162 ObjCContainerDecl *CDecl) { 1163 if (CDecl->isDeprecated() || IsCategoryNameWithDeprecatedSuffix(CDecl)) 1164 return; 1165 1166 // migrate methods which can have instancetype as their result type. 1167 for (ObjCContainerDecl::method_iterator M = CDecl->meth_begin(), 1168 MEnd = CDecl->meth_end(); 1169 M != MEnd; ++M) { 1170 ObjCMethodDecl *Method = (*M); 1171 if (Method->isDeprecated()) 1172 continue; 1173 migrateMethodInstanceType(Ctx, CDecl, Method); 1174 } 1175 } 1176 1177 void ObjCMigrateASTConsumer::migrateFactoryMethod(ASTContext &Ctx, 1178 ObjCContainerDecl *CDecl, 1179 ObjCMethodDecl *OM, 1180 ObjCInstanceTypeFamily OIT_Family) { 1181 if (OM->isInstanceMethod() || 1182 OM->getReturnType() == Ctx.getObjCInstanceType() || 1183 !OM->getReturnType()->isObjCIdType()) 1184 return; 1185 1186 // Candidate factory methods are + (id) NaMeXXX : ... which belong to a class 1187 // NSYYYNamE with matching names be at least 3 characters long. 1188 ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl); 1189 if (!IDecl) { 1190 if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) 1191 IDecl = CatDecl->getClassInterface(); 1192 else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl)) 1193 IDecl = ImpDecl->getClassInterface(); 1194 } 1195 if (!IDecl) 1196 return; 1197 1198 std::string StringClassName = IDecl->getName(); 1199 StringRef LoweredClassName(StringClassName); 1200 std::string StringLoweredClassName = LoweredClassName.lower(); 1201 LoweredClassName = StringLoweredClassName; 1202 1203 IdentifierInfo *MethodIdName = OM->getSelector().getIdentifierInfoForSlot(0); 1204 // Handle method with no name at its first selector slot; e.g. + (id):(int)x. 1205 if (!MethodIdName) 1206 return; 1207 1208 std::string MethodName = MethodIdName->getName(); 1209 if (OIT_Family == OIT_Singleton || OIT_Family == OIT_ReturnsSelf) { 1210 StringRef STRefMethodName(MethodName); 1211 size_t len = 0; 1212 if (STRefMethodName.startswith("standard")) 1213 len = strlen("standard"); 1214 else if (STRefMethodName.startswith("shared")) 1215 len = strlen("shared"); 1216 else if (STRefMethodName.startswith("default")) 1217 len = strlen("default"); 1218 else 1219 return; 1220 MethodName = STRefMethodName.substr(len); 1221 } 1222 std::string MethodNameSubStr = MethodName.substr(0, 3); 1223 StringRef MethodNamePrefix(MethodNameSubStr); 1224 std::string StringLoweredMethodNamePrefix = MethodNamePrefix.lower(); 1225 MethodNamePrefix = StringLoweredMethodNamePrefix; 1226 size_t Ix = LoweredClassName.rfind(MethodNamePrefix); 1227 if (Ix == StringRef::npos) 1228 return; 1229 std::string ClassNamePostfix = LoweredClassName.substr(Ix); 1230 StringRef LoweredMethodName(MethodName); 1231 std::string StringLoweredMethodName = LoweredMethodName.lower(); 1232 LoweredMethodName = StringLoweredMethodName; 1233 if (!LoweredMethodName.startswith(ClassNamePostfix)) 1234 return; 1235 if (OIT_Family == OIT_ReturnsSelf) 1236 ReplaceWithClasstype(*this, OM); 1237 else 1238 ReplaceWithInstancetype(*this, OM); 1239 } 1240 1241 static bool IsVoidStarType(QualType Ty) { 1242 if (!Ty->isPointerType()) 1243 return false; 1244 1245 while (const TypedefType *TD = dyn_cast<TypedefType>(Ty.getTypePtr())) 1246 Ty = TD->getDecl()->getUnderlyingType(); 1247 1248 // Is the type void*? 1249 const PointerType* PT = Ty->getAs<PointerType>(); 1250 if (PT->getPointeeType().getUnqualifiedType()->isVoidType()) 1251 return true; 1252 return IsVoidStarType(PT->getPointeeType()); 1253 } 1254 1255 /// AuditedType - This routine audits the type AT and returns false if it is one of known 1256 /// CF object types or of the "void *" variety. It returns true if we don't care about the type 1257 /// such as a non-pointer or pointers which have no ownership issues (such as "int *"). 1258 static bool AuditedType (QualType AT) { 1259 if (!AT->isAnyPointerType() && !AT->isBlockPointerType()) 1260 return true; 1261 // FIXME. There isn't much we can say about CF pointer type; or is there? 1262 if (ento::coreFoundation::isCFObjectRef(AT) || 1263 IsVoidStarType(AT) || 1264 // If an ObjC object is type, assuming that it is not a CF function and 1265 // that it is an un-audited function. 1266 AT->isObjCObjectPointerType() || AT->isObjCBuiltinType()) 1267 return false; 1268 // All other pointers are assumed audited as harmless. 1269 return true; 1270 } 1271 1272 void ObjCMigrateASTConsumer::AnnotateImplicitBridging(ASTContext &Ctx) { 1273 if (CFFunctionIBCandidates.empty()) 1274 return; 1275 if (!Ctx.Idents.get("CF_IMPLICIT_BRIDGING_ENABLED").hasMacroDefinition()) { 1276 CFFunctionIBCandidates.clear(); 1277 FileId = FileID(); 1278 return; 1279 } 1280 // Insert CF_IMPLICIT_BRIDGING_ENABLE/CF_IMPLICIT_BRIDGING_DISABLED 1281 const Decl *FirstFD = CFFunctionIBCandidates[0]; 1282 const Decl *LastFD = 1283 CFFunctionIBCandidates[CFFunctionIBCandidates.size()-1]; 1284 const char *PragmaString = "\nCF_IMPLICIT_BRIDGING_ENABLED\n\n"; 1285 edit::Commit commit(*Editor); 1286 commit.insertBefore(FirstFD->getLocStart(), PragmaString); 1287 PragmaString = "\n\nCF_IMPLICIT_BRIDGING_DISABLED\n"; 1288 SourceLocation EndLoc = LastFD->getLocEnd(); 1289 // get location just past end of function location. 1290 EndLoc = PP.getLocForEndOfToken(EndLoc); 1291 if (isa<FunctionDecl>(LastFD)) { 1292 // For Methods, EndLoc points to the ending semcolon. So, 1293 // not of these extra work is needed. 1294 Token Tok; 1295 // get locaiton of token that comes after end of function. 1296 bool Failed = PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true); 1297 if (!Failed) 1298 EndLoc = Tok.getLocation(); 1299 } 1300 commit.insertAfterToken(EndLoc, PragmaString); 1301 Editor->commit(commit); 1302 FileId = FileID(); 1303 CFFunctionIBCandidates.clear(); 1304 } 1305 1306 void ObjCMigrateASTConsumer::migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl) { 1307 if (Decl->isDeprecated()) 1308 return; 1309 1310 if (Decl->hasAttr<CFAuditedTransferAttr>()) { 1311 assert(CFFunctionIBCandidates.empty() && 1312 "Cannot have audited functions/methods inside user " 1313 "provided CF_IMPLICIT_BRIDGING_ENABLE"); 1314 return; 1315 } 1316 1317 // Finction must be annotated first. 1318 if (const FunctionDecl *FuncDecl = dyn_cast<FunctionDecl>(Decl)) { 1319 CF_BRIDGING_KIND AuditKind = migrateAddFunctionAnnotation(Ctx, FuncDecl); 1320 if (AuditKind == CF_BRIDGING_ENABLE) { 1321 CFFunctionIBCandidates.push_back(Decl); 1322 if (FileId.isInvalid()) 1323 FileId = PP.getSourceManager().getFileID(Decl->getLocation()); 1324 } 1325 else if (AuditKind == CF_BRIDGING_MAY_INCLUDE) { 1326 if (!CFFunctionIBCandidates.empty()) { 1327 CFFunctionIBCandidates.push_back(Decl); 1328 if (FileId.isInvalid()) 1329 FileId = PP.getSourceManager().getFileID(Decl->getLocation()); 1330 } 1331 } 1332 else 1333 AnnotateImplicitBridging(Ctx); 1334 } 1335 else { 1336 migrateAddMethodAnnotation(Ctx, cast<ObjCMethodDecl>(Decl)); 1337 AnnotateImplicitBridging(Ctx); 1338 } 1339 } 1340 1341 void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx, 1342 const CallEffects &CE, 1343 const FunctionDecl *FuncDecl, 1344 bool ResultAnnotated) { 1345 // Annotate function. 1346 if (!ResultAnnotated) { 1347 RetEffect Ret = CE.getReturnValue(); 1348 const char *AnnotationString = 0; 1349 if (Ret.getObjKind() == RetEffect::CF) { 1350 if (Ret.isOwned() && 1351 Ctx.Idents.get("CF_RETURNS_RETAINED").hasMacroDefinition()) 1352 AnnotationString = " CF_RETURNS_RETAINED"; 1353 else if (Ret.notOwned() && 1354 Ctx.Idents.get("CF_RETURNS_NOT_RETAINED").hasMacroDefinition()) 1355 AnnotationString = " CF_RETURNS_NOT_RETAINED"; 1356 } 1357 else if (Ret.getObjKind() == RetEffect::ObjC) { 1358 if (Ret.isOwned() && 1359 Ctx.Idents.get("NS_RETURNS_RETAINED").hasMacroDefinition()) 1360 AnnotationString = " NS_RETURNS_RETAINED"; 1361 } 1362 1363 if (AnnotationString) { 1364 edit::Commit commit(*Editor); 1365 commit.insertAfterToken(FuncDecl->getLocEnd(), AnnotationString); 1366 Editor->commit(commit); 1367 } 1368 } 1369 llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs(); 1370 unsigned i = 0; 1371 for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(), 1372 pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) { 1373 const ParmVarDecl *pd = *pi; 1374 ArgEffect AE = AEArgs[i]; 1375 if (AE == DecRef && !pd->hasAttr<CFConsumedAttr>() && 1376 Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) { 1377 edit::Commit commit(*Editor); 1378 commit.insertBefore(pd->getLocation(), "CF_CONSUMED "); 1379 Editor->commit(commit); 1380 } 1381 else if (AE == DecRefMsg && !pd->hasAttr<NSConsumedAttr>() && 1382 Ctx.Idents.get("NS_CONSUMED").hasMacroDefinition()) { 1383 edit::Commit commit(*Editor); 1384 commit.insertBefore(pd->getLocation(), "NS_CONSUMED "); 1385 Editor->commit(commit); 1386 } 1387 } 1388 } 1389 1390 1391 ObjCMigrateASTConsumer::CF_BRIDGING_KIND 1392 ObjCMigrateASTConsumer::migrateAddFunctionAnnotation( 1393 ASTContext &Ctx, 1394 const FunctionDecl *FuncDecl) { 1395 if (FuncDecl->hasBody()) 1396 return CF_BRIDGING_NONE; 1397 1398 CallEffects CE = CallEffects::getEffect(FuncDecl); 1399 bool FuncIsReturnAnnotated = (FuncDecl->hasAttr<CFReturnsRetainedAttr>() || 1400 FuncDecl->hasAttr<CFReturnsNotRetainedAttr>() || 1401 FuncDecl->hasAttr<NSReturnsRetainedAttr>() || 1402 FuncDecl->hasAttr<NSReturnsNotRetainedAttr>() || 1403 FuncDecl->hasAttr<NSReturnsAutoreleasedAttr>()); 1404 1405 // Trivial case of when funciton is annotated and has no argument. 1406 if (FuncIsReturnAnnotated && FuncDecl->getNumParams() == 0) 1407 return CF_BRIDGING_NONE; 1408 1409 bool ReturnCFAudited = false; 1410 if (!FuncIsReturnAnnotated) { 1411 RetEffect Ret = CE.getReturnValue(); 1412 if (Ret.getObjKind() == RetEffect::CF && 1413 (Ret.isOwned() || Ret.notOwned())) 1414 ReturnCFAudited = true; 1415 else if (!AuditedType(FuncDecl->getReturnType())) 1416 return CF_BRIDGING_NONE; 1417 } 1418 1419 // At this point result type is audited for potential inclusion. 1420 // Now, how about argument types. 1421 llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs(); 1422 unsigned i = 0; 1423 bool ArgCFAudited = false; 1424 for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(), 1425 pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) { 1426 const ParmVarDecl *pd = *pi; 1427 ArgEffect AE = AEArgs[i]; 1428 if (AE == DecRef /*CFConsumed annotated*/ || AE == IncRef) { 1429 if (AE == DecRef && !pd->hasAttr<CFConsumedAttr>()) 1430 ArgCFAudited = true; 1431 else if (AE == IncRef) 1432 ArgCFAudited = true; 1433 } 1434 else { 1435 QualType AT = pd->getType(); 1436 if (!AuditedType(AT)) { 1437 AddCFAnnotations(Ctx, CE, FuncDecl, FuncIsReturnAnnotated); 1438 return CF_BRIDGING_NONE; 1439 } 1440 } 1441 } 1442 if (ReturnCFAudited || ArgCFAudited) 1443 return CF_BRIDGING_ENABLE; 1444 1445 return CF_BRIDGING_MAY_INCLUDE; 1446 } 1447 1448 void ObjCMigrateASTConsumer::migrateARCSafeAnnotation(ASTContext &Ctx, 1449 ObjCContainerDecl *CDecl) { 1450 if (!isa<ObjCInterfaceDecl>(CDecl) || CDecl->isDeprecated()) 1451 return; 1452 1453 // migrate methods which can have instancetype as their result type. 1454 for (ObjCContainerDecl::method_iterator M = CDecl->meth_begin(), 1455 MEnd = CDecl->meth_end(); 1456 M != MEnd; ++M) { 1457 ObjCMethodDecl *Method = (*M); 1458 migrateCFAnnotation(Ctx, Method); 1459 } 1460 } 1461 1462 void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx, 1463 const CallEffects &CE, 1464 const ObjCMethodDecl *MethodDecl, 1465 bool ResultAnnotated) { 1466 // Annotate function. 1467 if (!ResultAnnotated) { 1468 RetEffect Ret = CE.getReturnValue(); 1469 const char *AnnotationString = 0; 1470 if (Ret.getObjKind() == RetEffect::CF) { 1471 if (Ret.isOwned() && 1472 Ctx.Idents.get("CF_RETURNS_RETAINED").hasMacroDefinition()) 1473 AnnotationString = " CF_RETURNS_RETAINED"; 1474 else if (Ret.notOwned() && 1475 Ctx.Idents.get("CF_RETURNS_NOT_RETAINED").hasMacroDefinition()) 1476 AnnotationString = " CF_RETURNS_NOT_RETAINED"; 1477 } 1478 else if (Ret.getObjKind() == RetEffect::ObjC) { 1479 ObjCMethodFamily OMF = MethodDecl->getMethodFamily(); 1480 switch (OMF) { 1481 case clang::OMF_alloc: 1482 case clang::OMF_new: 1483 case clang::OMF_copy: 1484 case clang::OMF_init: 1485 case clang::OMF_mutableCopy: 1486 break; 1487 1488 default: 1489 if (Ret.isOwned() && 1490 Ctx.Idents.get("NS_RETURNS_RETAINED").hasMacroDefinition()) 1491 AnnotationString = " NS_RETURNS_RETAINED"; 1492 break; 1493 } 1494 } 1495 1496 if (AnnotationString) { 1497 edit::Commit commit(*Editor); 1498 commit.insertBefore(MethodDecl->getLocEnd(), AnnotationString); 1499 Editor->commit(commit); 1500 } 1501 } 1502 llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs(); 1503 unsigned i = 0; 1504 for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(), 1505 pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) { 1506 const ParmVarDecl *pd = *pi; 1507 ArgEffect AE = AEArgs[i]; 1508 if (AE == DecRef && !pd->hasAttr<CFConsumedAttr>() && 1509 Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) { 1510 edit::Commit commit(*Editor); 1511 commit.insertBefore(pd->getLocation(), "CF_CONSUMED "); 1512 Editor->commit(commit); 1513 } 1514 } 1515 } 1516 1517 void ObjCMigrateASTConsumer::migrateAddMethodAnnotation( 1518 ASTContext &Ctx, 1519 const ObjCMethodDecl *MethodDecl) { 1520 if (MethodDecl->hasBody() || MethodDecl->isImplicit()) 1521 return; 1522 1523 CallEffects CE = CallEffects::getEffect(MethodDecl); 1524 bool MethodIsReturnAnnotated = (MethodDecl->hasAttr<CFReturnsRetainedAttr>() || 1525 MethodDecl->hasAttr<CFReturnsNotRetainedAttr>() || 1526 MethodDecl->hasAttr<NSReturnsRetainedAttr>() || 1527 MethodDecl->hasAttr<NSReturnsNotRetainedAttr>() || 1528 MethodDecl->hasAttr<NSReturnsAutoreleasedAttr>()); 1529 1530 if (CE.getReceiver() == DecRefMsg && 1531 !MethodDecl->hasAttr<NSConsumesSelfAttr>() && 1532 MethodDecl->getMethodFamily() != OMF_init && 1533 MethodDecl->getMethodFamily() != OMF_release && 1534 Ctx.Idents.get("NS_CONSUMES_SELF").hasMacroDefinition()) { 1535 edit::Commit commit(*Editor); 1536 commit.insertBefore(MethodDecl->getLocEnd(), " NS_CONSUMES_SELF"); 1537 Editor->commit(commit); 1538 } 1539 1540 // Trivial case of when funciton is annotated and has no argument. 1541 if (MethodIsReturnAnnotated && 1542 (MethodDecl->param_begin() == MethodDecl->param_end())) 1543 return; 1544 1545 if (!MethodIsReturnAnnotated) { 1546 RetEffect Ret = CE.getReturnValue(); 1547 if ((Ret.getObjKind() == RetEffect::CF || 1548 Ret.getObjKind() == RetEffect::ObjC) && 1549 (Ret.isOwned() || Ret.notOwned())) { 1550 AddCFAnnotations(Ctx, CE, MethodDecl, false); 1551 return; 1552 } else if (!AuditedType(MethodDecl->getReturnType())) 1553 return; 1554 } 1555 1556 // At this point result type is either annotated or audited. 1557 // Now, how about argument types. 1558 llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs(); 1559 unsigned i = 0; 1560 for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(), 1561 pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) { 1562 const ParmVarDecl *pd = *pi; 1563 ArgEffect AE = AEArgs[i]; 1564 if ((AE == DecRef && !pd->hasAttr<CFConsumedAttr>()) || AE == IncRef || 1565 !AuditedType(pd->getType())) { 1566 AddCFAnnotations(Ctx, CE, MethodDecl, MethodIsReturnAnnotated); 1567 return; 1568 } 1569 } 1570 return; 1571 } 1572 1573 namespace { 1574 class SuperInitChecker : public RecursiveASTVisitor<SuperInitChecker> { 1575 public: 1576 bool shouldVisitTemplateInstantiations() const { return false; } 1577 bool shouldWalkTypesOfTypeLocs() const { return false; } 1578 1579 bool VisitObjCMessageExpr(ObjCMessageExpr *E) { 1580 if (E->getReceiverKind() == ObjCMessageExpr::SuperInstance) { 1581 if (E->getMethodFamily() == OMF_init) 1582 return false; 1583 } 1584 return true; 1585 } 1586 }; 1587 } // anonymous namespace 1588 1589 static bool hasSuperInitCall(const ObjCMethodDecl *MD) { 1590 return !SuperInitChecker().TraverseStmt(MD->getBody()); 1591 } 1592 1593 void ObjCMigrateASTConsumer::inferDesignatedInitializers( 1594 ASTContext &Ctx, 1595 const ObjCImplementationDecl *ImplD) { 1596 1597 const ObjCInterfaceDecl *IFace = ImplD->getClassInterface(); 1598 if (!IFace || IFace->hasDesignatedInitializers()) 1599 return; 1600 if (!Ctx.Idents.get("NS_DESIGNATED_INITIALIZER").hasMacroDefinition()) 1601 return; 1602 1603 for (ObjCImplementationDecl::instmeth_iterator 1604 I = ImplD->instmeth_begin(), E = ImplD->instmeth_end(); I != E; ++I) { 1605 const ObjCMethodDecl *MD = *I; 1606 if (MD->isDeprecated() || 1607 MD->getMethodFamily() != OMF_init || 1608 MD->isDesignatedInitializerForTheInterface()) 1609 continue; 1610 const ObjCMethodDecl *IFaceM = IFace->getMethod(MD->getSelector(), 1611 /*isInstance=*/true); 1612 if (!IFaceM) 1613 continue; 1614 if (hasSuperInitCall(MD)) { 1615 edit::Commit commit(*Editor); 1616 commit.insert(IFaceM->getLocEnd(), " NS_DESIGNATED_INITIALIZER"); 1617 Editor->commit(commit); 1618 } 1619 } 1620 } 1621 1622 namespace { 1623 1624 class RewritesReceiver : public edit::EditsReceiver { 1625 Rewriter &Rewrite; 1626 1627 public: 1628 RewritesReceiver(Rewriter &Rewrite) : Rewrite(Rewrite) { } 1629 1630 virtual void insert(SourceLocation loc, StringRef text) { 1631 Rewrite.InsertText(loc, text); 1632 } 1633 virtual void replace(CharSourceRange range, StringRef text) { 1634 Rewrite.ReplaceText(range.getBegin(), Rewrite.getRangeSize(range), text); 1635 } 1636 }; 1637 1638 class JSONEditWriter : public edit::EditsReceiver { 1639 SourceManager &SourceMgr; 1640 llvm::raw_ostream &OS; 1641 1642 public: 1643 JSONEditWriter(SourceManager &SM, llvm::raw_ostream &OS) 1644 : SourceMgr(SM), OS(OS) { 1645 OS << "[\n"; 1646 } 1647 ~JSONEditWriter() { 1648 OS << "]\n"; 1649 } 1650 1651 private: 1652 struct EntryWriter { 1653 SourceManager &SourceMgr; 1654 llvm::raw_ostream &OS; 1655 1656 EntryWriter(SourceManager &SM, llvm::raw_ostream &OS) 1657 : SourceMgr(SM), OS(OS) { 1658 OS << " {\n"; 1659 } 1660 ~EntryWriter() { 1661 OS << " },\n"; 1662 } 1663 1664 void writeLoc(SourceLocation Loc) { 1665 FileID FID; 1666 unsigned Offset; 1667 std::tie(FID, Offset) = SourceMgr.getDecomposedLoc(Loc); 1668 assert(!FID.isInvalid()); 1669 SmallString<200> Path = 1670 StringRef(SourceMgr.getFileEntryForID(FID)->getName()); 1671 llvm::sys::fs::make_absolute(Path); 1672 OS << " \"file\": \""; 1673 OS.write_escaped(Path.str()) << "\",\n"; 1674 OS << " \"offset\": " << Offset << ",\n"; 1675 } 1676 1677 void writeRemove(CharSourceRange Range) { 1678 assert(Range.isCharRange()); 1679 std::pair<FileID, unsigned> Begin = 1680 SourceMgr.getDecomposedLoc(Range.getBegin()); 1681 std::pair<FileID, unsigned> End = 1682 SourceMgr.getDecomposedLoc(Range.getEnd()); 1683 assert(Begin.first == End.first); 1684 assert(Begin.second <= End.second); 1685 unsigned Length = End.second - Begin.second; 1686 1687 OS << " \"remove\": " << Length << ",\n"; 1688 } 1689 1690 void writeText(StringRef Text) { 1691 OS << " \"text\": \""; 1692 OS.write_escaped(Text) << "\",\n"; 1693 } 1694 }; 1695 1696 virtual void insert(SourceLocation Loc, StringRef Text) { 1697 EntryWriter Writer(SourceMgr, OS); 1698 Writer.writeLoc(Loc); 1699 Writer.writeText(Text); 1700 } 1701 1702 virtual void replace(CharSourceRange Range, StringRef Text) { 1703 EntryWriter Writer(SourceMgr, OS); 1704 Writer.writeLoc(Range.getBegin()); 1705 Writer.writeRemove(Range); 1706 Writer.writeText(Text); 1707 } 1708 1709 virtual void remove(CharSourceRange Range) { 1710 EntryWriter Writer(SourceMgr, OS); 1711 Writer.writeLoc(Range.getBegin()); 1712 Writer.writeRemove(Range); 1713 } 1714 }; 1715 1716 } 1717 1718 static bool 1719 IsReallyASystemHeader(ASTContext &Ctx, const FileEntry *file, FileID FID) { 1720 bool Invalid = false; 1721 const SrcMgr::SLocEntry &SEntry = 1722 Ctx.getSourceManager().getSLocEntry(FID, &Invalid); 1723 if (!Invalid && SEntry.isFile()) { 1724 const SrcMgr::FileInfo &FI = SEntry.getFile(); 1725 if (!FI.hasLineDirectives()) { 1726 if (FI.getFileCharacteristic() == SrcMgr::C_ExternCSystem) 1727 return true; 1728 if (FI.getFileCharacteristic() == SrcMgr::C_System) { 1729 // This file is in a system header directory. Continue committing 1730 // change only if it's a user-specified system directory because user 1731 // put a .system_framework file in the framework directory. 1732 StringRef Directory(file->getDir()->getName()); 1733 size_t Ix = Directory.rfind(".framework"); 1734 if (Ix == StringRef::npos) 1735 return true; 1736 std::string PatchToSystemFramework = Directory.slice(0, Ix+sizeof(".framework")); 1737 PatchToSystemFramework += ".system_framework"; 1738 if (!llvm::sys::fs::exists(PatchToSystemFramework.data())) 1739 return true; 1740 } 1741 } 1742 } 1743 return false; 1744 } 1745 1746 void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) { 1747 1748 TranslationUnitDecl *TU = Ctx.getTranslationUnitDecl(); 1749 if (ASTMigrateActions & FrontendOptions::ObjCMT_MigrateDecls) { 1750 for (DeclContext::decl_iterator D = TU->decls_begin(), DEnd = TU->decls_end(); 1751 D != DEnd; ++D) { 1752 FileID FID = PP.getSourceManager().getFileID((*D)->getLocation()); 1753 if (!FID.isInvalid()) 1754 if (!FileId.isInvalid() && FileId != FID) { 1755 if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) 1756 AnnotateImplicitBridging(Ctx); 1757 } 1758 1759 if (ObjCInterfaceDecl *CDecl = dyn_cast<ObjCInterfaceDecl>(*D)) 1760 if (canModify(CDecl)) 1761 migrateObjCInterfaceDecl(Ctx, CDecl); 1762 if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(*D)) { 1763 if (canModify(CatDecl)) 1764 migrateObjCInterfaceDecl(Ctx, CatDecl); 1765 } 1766 else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(*D)) 1767 ObjCProtocolDecls.insert(PDecl->getCanonicalDecl()); 1768 else if (const ObjCImplementationDecl *ImpDecl = 1769 dyn_cast<ObjCImplementationDecl>(*D)) { 1770 if ((ASTMigrateActions & FrontendOptions::ObjCMT_ProtocolConformance) && 1771 canModify(ImpDecl)) 1772 migrateProtocolConformance(Ctx, ImpDecl); 1773 } 1774 else if (const EnumDecl *ED = dyn_cast<EnumDecl>(*D)) { 1775 if (!(ASTMigrateActions & FrontendOptions::ObjCMT_NsMacros)) 1776 continue; 1777 if (!canModify(ED)) 1778 continue; 1779 DeclContext::decl_iterator N = D; 1780 if (++N != DEnd) { 1781 const TypedefDecl *TD = dyn_cast<TypedefDecl>(*N); 1782 if (migrateNSEnumDecl(Ctx, ED, TD) && TD) 1783 D++; 1784 } 1785 else 1786 migrateNSEnumDecl(Ctx, ED, /*TypedefDecl */0); 1787 } 1788 else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(*D)) { 1789 if (!(ASTMigrateActions & FrontendOptions::ObjCMT_NsMacros)) 1790 continue; 1791 if (!canModify(TD)) 1792 continue; 1793 DeclContext::decl_iterator N = D; 1794 if (++N == DEnd) 1795 continue; 1796 if (const EnumDecl *ED = dyn_cast<EnumDecl>(*N)) { 1797 if (++N != DEnd) 1798 if (const TypedefDecl *TDF = dyn_cast<TypedefDecl>(*N)) { 1799 // prefer typedef-follows-enum to enum-follows-typedef pattern. 1800 if (migrateNSEnumDecl(Ctx, ED, TDF)) { 1801 ++D; ++D; 1802 CacheObjCNSIntegerTypedefed(TD); 1803 continue; 1804 } 1805 } 1806 if (migrateNSEnumDecl(Ctx, ED, TD)) { 1807 ++D; 1808 continue; 1809 } 1810 } 1811 CacheObjCNSIntegerTypedefed(TD); 1812 } 1813 else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*D)) { 1814 if ((ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) && 1815 canModify(FD)) 1816 migrateCFAnnotation(Ctx, FD); 1817 } 1818 1819 if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(*D)) { 1820 bool CanModify = canModify(CDecl); 1821 // migrate methods which can have instancetype as their result type. 1822 if ((ASTMigrateActions & FrontendOptions::ObjCMT_Instancetype) && 1823 CanModify) 1824 migrateAllMethodInstaceType(Ctx, CDecl); 1825 // annotate methods with CF annotations. 1826 if ((ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) && 1827 CanModify) 1828 migrateARCSafeAnnotation(Ctx, CDecl); 1829 } 1830 1831 if (const ObjCImplementationDecl * 1832 ImplD = dyn_cast<ObjCImplementationDecl>(*D)) { 1833 if ((ASTMigrateActions & FrontendOptions::ObjCMT_DesignatedInitializer) && 1834 canModify(ImplD)) 1835 inferDesignatedInitializers(Ctx, ImplD); 1836 } 1837 } 1838 if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) 1839 AnnotateImplicitBridging(Ctx); 1840 } 1841 1842 if (IsOutputFile) { 1843 std::string Error; 1844 llvm::raw_fd_ostream OS(MigrateDir.c_str(), Error, llvm::sys::fs::F_None); 1845 if (!Error.empty()) { 1846 DiagnosticsEngine &Diags = Ctx.getDiagnostics(); 1847 Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Error, "%0")) 1848 << Error; 1849 return; 1850 } 1851 1852 JSONEditWriter Writer(Ctx.getSourceManager(), OS); 1853 Editor->applyRewrites(Writer); 1854 return; 1855 } 1856 1857 Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts()); 1858 RewritesReceiver Rec(rewriter); 1859 Editor->applyRewrites(Rec); 1860 1861 for (Rewriter::buffer_iterator 1862 I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) { 1863 FileID FID = I->first; 1864 RewriteBuffer &buf = I->second; 1865 const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID); 1866 assert(file); 1867 if (IsReallyASystemHeader(Ctx, file, FID)) 1868 continue; 1869 SmallString<512> newText; 1870 llvm::raw_svector_ostream vecOS(newText); 1871 buf.write(vecOS); 1872 vecOS.flush(); 1873 llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy( 1874 StringRef(newText.data(), newText.size()), file->getName()); 1875 SmallString<64> filePath(file->getName()); 1876 FileMgr.FixupRelativePath(filePath); 1877 Remapper.remap(filePath.str(), memBuf); 1878 } 1879 1880 if (IsOutputFile) { 1881 Remapper.flushToFile(MigrateDir, Ctx.getDiagnostics()); 1882 } else { 1883 Remapper.flushToDisk(MigrateDir, Ctx.getDiagnostics()); 1884 } 1885 } 1886 1887 bool MigrateSourceAction::BeginInvocation(CompilerInstance &CI) { 1888 CI.getDiagnostics().setIgnoreAllWarnings(true); 1889 return true; 1890 } 1891 1892 static std::vector<std::string> getWhiteListFilenames(StringRef DirPath) { 1893 using namespace llvm::sys::fs; 1894 using namespace llvm::sys::path; 1895 1896 std::vector<std::string> Filenames; 1897 if (DirPath.empty() || !is_directory(DirPath)) 1898 return Filenames; 1899 1900 llvm::error_code EC; 1901 directory_iterator DI = directory_iterator(DirPath, EC); 1902 directory_iterator DE; 1903 for (; !EC && DI != DE; DI = DI.increment(EC)) { 1904 if (is_regular_file(DI->path())) 1905 Filenames.push_back(filename(DI->path())); 1906 } 1907 1908 return Filenames; 1909 } 1910 1911 ASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI, 1912 StringRef InFile) { 1913 PPConditionalDirectiveRecord * 1914 PPRec = new PPConditionalDirectiveRecord(CI.getSourceManager()); 1915 unsigned ObjCMTAction = CI.getFrontendOpts().ObjCMTAction; 1916 unsigned ObjCMTOpts = ObjCMTAction; 1917 // These are companion flags, they do not enable transformations. 1918 ObjCMTOpts &= ~(FrontendOptions::ObjCMT_AtomicProperty | 1919 FrontendOptions::ObjCMT_NsAtomicIOSOnlyProperty); 1920 if (ObjCMTOpts == FrontendOptions::ObjCMT_None) { 1921 // If no specific option was given, enable literals+subscripting transforms 1922 // by default. 1923 ObjCMTAction |= FrontendOptions::ObjCMT_Literals | 1924 FrontendOptions::ObjCMT_Subscripting; 1925 } 1926 CI.getPreprocessor().addPPCallbacks(PPRec); 1927 std::vector<std::string> WhiteList = 1928 getWhiteListFilenames(CI.getFrontendOpts().ObjCMTWhiteListPath); 1929 return new ObjCMigrateASTConsumer(CI.getFrontendOpts().OutputFile, 1930 ObjCMTAction, 1931 Remapper, 1932 CI.getFileManager(), 1933 PPRec, 1934 CI.getPreprocessor(), 1935 /*isOutputFile=*/true, 1936 WhiteList); 1937 } 1938 1939 namespace { 1940 struct EditEntry { 1941 const FileEntry *File; 1942 unsigned Offset; 1943 unsigned RemoveLen; 1944 std::string Text; 1945 1946 EditEntry() : File(), Offset(), RemoveLen() {} 1947 }; 1948 } 1949 1950 namespace llvm { 1951 template<> struct DenseMapInfo<EditEntry> { 1952 static inline EditEntry getEmptyKey() { 1953 EditEntry Entry; 1954 Entry.Offset = unsigned(-1); 1955 return Entry; 1956 } 1957 static inline EditEntry getTombstoneKey() { 1958 EditEntry Entry; 1959 Entry.Offset = unsigned(-2); 1960 return Entry; 1961 } 1962 static unsigned getHashValue(const EditEntry& Val) { 1963 llvm::FoldingSetNodeID ID; 1964 ID.AddPointer(Val.File); 1965 ID.AddInteger(Val.Offset); 1966 ID.AddInteger(Val.RemoveLen); 1967 ID.AddString(Val.Text); 1968 return ID.ComputeHash(); 1969 } 1970 static bool isEqual(const EditEntry &LHS, const EditEntry &RHS) { 1971 return LHS.File == RHS.File && 1972 LHS.Offset == RHS.Offset && 1973 LHS.RemoveLen == RHS.RemoveLen && 1974 LHS.Text == RHS.Text; 1975 } 1976 }; 1977 } 1978 1979 namespace { 1980 class RemapFileParser { 1981 FileManager &FileMgr; 1982 1983 public: 1984 RemapFileParser(FileManager &FileMgr) : FileMgr(FileMgr) { } 1985 1986 bool parse(StringRef File, SmallVectorImpl<EditEntry> &Entries) { 1987 using namespace llvm::yaml; 1988 1989 std::unique_ptr<llvm::MemoryBuffer> FileBuf; 1990 if (llvm::MemoryBuffer::getFile(File, FileBuf)) 1991 return true; 1992 1993 llvm::SourceMgr SM; 1994 Stream YAMLStream(FileBuf.release(), SM); 1995 document_iterator I = YAMLStream.begin(); 1996 if (I == YAMLStream.end()) 1997 return true; 1998 Node *Root = I->getRoot(); 1999 if (!Root) 2000 return true; 2001 2002 SequenceNode *SeqNode = dyn_cast<SequenceNode>(Root); 2003 if (!SeqNode) 2004 return true; 2005 2006 for (SequenceNode::iterator 2007 AI = SeqNode->begin(), AE = SeqNode->end(); AI != AE; ++AI) { 2008 MappingNode *MapNode = dyn_cast<MappingNode>(&*AI); 2009 if (!MapNode) 2010 continue; 2011 parseEdit(MapNode, Entries); 2012 } 2013 2014 return false; 2015 } 2016 2017 private: 2018 void parseEdit(llvm::yaml::MappingNode *Node, 2019 SmallVectorImpl<EditEntry> &Entries) { 2020 using namespace llvm::yaml; 2021 EditEntry Entry; 2022 bool Ignore = false; 2023 2024 for (MappingNode::iterator 2025 KVI = Node->begin(), KVE = Node->end(); KVI != KVE; ++KVI) { 2026 ScalarNode *KeyString = dyn_cast<ScalarNode>((*KVI).getKey()); 2027 if (!KeyString) 2028 continue; 2029 SmallString<10> KeyStorage; 2030 StringRef Key = KeyString->getValue(KeyStorage); 2031 2032 ScalarNode *ValueString = dyn_cast<ScalarNode>((*KVI).getValue()); 2033 if (!ValueString) 2034 continue; 2035 SmallString<64> ValueStorage; 2036 StringRef Val = ValueString->getValue(ValueStorage); 2037 2038 if (Key == "file") { 2039 const FileEntry *FE = FileMgr.getFile(Val); 2040 if (!FE) 2041 Ignore = true; 2042 Entry.File = FE; 2043 } else if (Key == "offset") { 2044 if (Val.getAsInteger(10, Entry.Offset)) 2045 Ignore = true; 2046 } else if (Key == "remove") { 2047 if (Val.getAsInteger(10, Entry.RemoveLen)) 2048 Ignore = true; 2049 } else if (Key == "text") { 2050 Entry.Text = Val; 2051 } 2052 } 2053 2054 if (!Ignore) 2055 Entries.push_back(Entry); 2056 } 2057 }; 2058 } 2059 2060 static bool reportDiag(const Twine &Err, DiagnosticsEngine &Diag) { 2061 Diag.Report(Diag.getCustomDiagID(DiagnosticsEngine::Error, "%0")) 2062 << Err.str(); 2063 return true; 2064 } 2065 2066 static std::string applyEditsToTemp(const FileEntry *FE, 2067 ArrayRef<EditEntry> Edits, 2068 FileManager &FileMgr, 2069 DiagnosticsEngine &Diag) { 2070 using namespace llvm::sys; 2071 2072 SourceManager SM(Diag, FileMgr); 2073 FileID FID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User); 2074 LangOptions LangOpts; 2075 edit::EditedSource Editor(SM, LangOpts); 2076 for (ArrayRef<EditEntry>::iterator 2077 I = Edits.begin(), E = Edits.end(); I != E; ++I) { 2078 const EditEntry &Entry = *I; 2079 assert(Entry.File == FE); 2080 SourceLocation Loc = 2081 SM.getLocForStartOfFile(FID).getLocWithOffset(Entry.Offset); 2082 CharSourceRange Range; 2083 if (Entry.RemoveLen != 0) { 2084 Range = CharSourceRange::getCharRange(Loc, 2085 Loc.getLocWithOffset(Entry.RemoveLen)); 2086 } 2087 2088 edit::Commit commit(Editor); 2089 if (Range.isInvalid()) { 2090 commit.insert(Loc, Entry.Text); 2091 } else if (Entry.Text.empty()) { 2092 commit.remove(Range); 2093 } else { 2094 commit.replace(Range, Entry.Text); 2095 } 2096 Editor.commit(commit); 2097 } 2098 2099 Rewriter rewriter(SM, LangOpts); 2100 RewritesReceiver Rec(rewriter); 2101 Editor.applyRewrites(Rec); 2102 2103 const RewriteBuffer *Buf = rewriter.getRewriteBufferFor(FID); 2104 SmallString<512> NewText; 2105 llvm::raw_svector_ostream OS(NewText); 2106 Buf->write(OS); 2107 OS.flush(); 2108 2109 SmallString<64> TempPath; 2110 int FD; 2111 if (fs::createTemporaryFile(path::filename(FE->getName()), 2112 path::extension(FE->getName()), FD, 2113 TempPath)) { 2114 reportDiag("Could not create file: " + TempPath.str(), Diag); 2115 return std::string(); 2116 } 2117 2118 llvm::raw_fd_ostream TmpOut(FD, /*shouldClose=*/true); 2119 TmpOut.write(NewText.data(), NewText.size()); 2120 TmpOut.close(); 2121 2122 return TempPath.str(); 2123 } 2124 2125 bool arcmt::getFileRemappingsFromFileList( 2126 std::vector<std::pair<std::string,std::string> > &remap, 2127 ArrayRef<StringRef> remapFiles, 2128 DiagnosticConsumer *DiagClient) { 2129 bool hasErrorOccurred = false; 2130 2131 FileSystemOptions FSOpts; 2132 FileManager FileMgr(FSOpts); 2133 RemapFileParser Parser(FileMgr); 2134 2135 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 2136 IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 2137 new DiagnosticsEngine(DiagID, new DiagnosticOptions, 2138 DiagClient, /*ShouldOwnClient=*/false)); 2139 2140 typedef llvm::DenseMap<const FileEntry *, std::vector<EditEntry> > 2141 FileEditEntriesTy; 2142 FileEditEntriesTy FileEditEntries; 2143 2144 llvm::DenseSet<EditEntry> EntriesSet; 2145 2146 for (ArrayRef<StringRef>::iterator 2147 I = remapFiles.begin(), E = remapFiles.end(); I != E; ++I) { 2148 SmallVector<EditEntry, 16> Entries; 2149 if (Parser.parse(*I, Entries)) 2150 continue; 2151 2152 for (SmallVectorImpl<EditEntry>::iterator 2153 EI = Entries.begin(), EE = Entries.end(); EI != EE; ++EI) { 2154 EditEntry &Entry = *EI; 2155 if (!Entry.File) 2156 continue; 2157 std::pair<llvm::DenseSet<EditEntry>::iterator, bool> 2158 Insert = EntriesSet.insert(Entry); 2159 if (!Insert.second) 2160 continue; 2161 2162 FileEditEntries[Entry.File].push_back(Entry); 2163 } 2164 } 2165 2166 for (FileEditEntriesTy::iterator 2167 I = FileEditEntries.begin(), E = FileEditEntries.end(); I != E; ++I) { 2168 std::string TempFile = applyEditsToTemp(I->first, I->second, 2169 FileMgr, *Diags); 2170 if (TempFile.empty()) { 2171 hasErrorOccurred = true; 2172 continue; 2173 } 2174 2175 remap.push_back(std::make_pair(I->first->getName(), TempFile)); 2176 } 2177 2178 return hasErrorOccurred; 2179 } 2180