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