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