1 //===--- Transforms.cpp - Transformations to ARC mode ---------------------===// 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 "Internals.h" 12 #include "clang/AST/ASTContext.h" 13 #include "clang/AST/RecursiveASTVisitor.h" 14 #include "clang/AST/StmtVisitor.h" 15 #include "clang/Analysis/DomainSpecific/CocoaConventions.h" 16 #include "clang/Basic/SourceManager.h" 17 #include "clang/Basic/TargetInfo.h" 18 #include "clang/Lex/Lexer.h" 19 #include "clang/Lex/Preprocessor.h" 20 #include "clang/Sema/Sema.h" 21 #include "clang/Sema/SemaDiagnostic.h" 22 #include "llvm/ADT/DenseSet.h" 23 #include "llvm/ADT/StringSwitch.h" 24 #include <map> 25 26 using namespace clang; 27 using namespace arcmt; 28 using namespace trans; 29 30 ASTTraverser::~ASTTraverser() { } 31 32 bool MigrationPass::CFBridgingFunctionsDefined() { 33 if (!EnableCFBridgeFns.hasValue()) 34 EnableCFBridgeFns = SemaRef.isKnownName("CFBridgingRetain") && 35 SemaRef.isKnownName("CFBridgingRelease"); 36 return *EnableCFBridgeFns; 37 } 38 39 //===----------------------------------------------------------------------===// 40 // Helpers. 41 //===----------------------------------------------------------------------===// 42 43 bool trans::canApplyWeak(ASTContext &Ctx, QualType type, 44 bool AllowOnUnknownClass) { 45 if (!Ctx.getLangOpts().ObjCWeakRuntime) 46 return false; 47 48 QualType T = type; 49 if (T.isNull()) 50 return false; 51 52 // iOS is always safe to use 'weak'. 53 if (Ctx.getTargetInfo().getTriple().isiOS() || 54 Ctx.getTargetInfo().getTriple().isWatchOS()) 55 AllowOnUnknownClass = true; 56 57 while (const PointerType *ptr = T->getAs<PointerType>()) 58 T = ptr->getPointeeType(); 59 if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) { 60 ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl(); 61 if (!AllowOnUnknownClass && (!Class || Class->getName() == "NSObject")) 62 return false; // id/NSObject is not safe for weak. 63 if (!AllowOnUnknownClass && !Class->hasDefinition()) 64 return false; // forward classes are not verifiable, therefore not safe. 65 if (Class && Class->isArcWeakrefUnavailable()) 66 return false; 67 } 68 69 return true; 70 } 71 72 bool trans::isPlusOneAssign(const BinaryOperator *E) { 73 if (E->getOpcode() != BO_Assign) 74 return false; 75 76 return isPlusOne(E->getRHS()); 77 } 78 79 bool trans::isPlusOne(const Expr *E) { 80 if (!E) 81 return false; 82 if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(E)) 83 E = EWC->getSubExpr(); 84 85 if (const ObjCMessageExpr * 86 ME = dyn_cast<ObjCMessageExpr>(E->IgnoreParenCasts())) 87 if (ME->getMethodFamily() == OMF_retain) 88 return true; 89 90 if (const CallExpr * 91 callE = dyn_cast<CallExpr>(E->IgnoreParenCasts())) { 92 if (const FunctionDecl *FD = callE->getDirectCallee()) { 93 if (FD->hasAttr<CFReturnsRetainedAttr>()) 94 return true; 95 96 if (FD->isGlobal() && 97 FD->getIdentifier() && 98 FD->getParent()->isTranslationUnit() && 99 FD->isExternallyVisible() && 100 ento::cocoa::isRefType(callE->getType(), "CF", 101 FD->getIdentifier()->getName())) { 102 StringRef fname = FD->getIdentifier()->getName(); 103 if (fname.endswith("Retain") || 104 fname.find("Create") != StringRef::npos || 105 fname.find("Copy") != StringRef::npos) { 106 return true; 107 } 108 } 109 } 110 } 111 112 const ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E); 113 while (implCE && implCE->getCastKind() == CK_BitCast) 114 implCE = dyn_cast<ImplicitCastExpr>(implCE->getSubExpr()); 115 116 return implCE && implCE->getCastKind() == CK_ARCConsumeObject; 117 } 118 119 /// \brief 'Loc' is the end of a statement range. This returns the location 120 /// immediately after the semicolon following the statement. 121 /// If no semicolon is found or the location is inside a macro, the returned 122 /// source location will be invalid. 123 SourceLocation trans::findLocationAfterSemi(SourceLocation loc, 124 ASTContext &Ctx, bool IsDecl) { 125 SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx, IsDecl); 126 if (SemiLoc.isInvalid()) 127 return SourceLocation(); 128 return SemiLoc.getLocWithOffset(1); 129 } 130 131 /// \brief \arg Loc is the end of a statement range. This returns the location 132 /// of the semicolon following the statement. 133 /// If no semicolon is found or the location is inside a macro, the returned 134 /// source location will be invalid. 135 SourceLocation trans::findSemiAfterLocation(SourceLocation loc, 136 ASTContext &Ctx, 137 bool IsDecl) { 138 SourceManager &SM = Ctx.getSourceManager(); 139 if (loc.isMacroID()) { 140 if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOpts(), &loc)) 141 return SourceLocation(); 142 } 143 loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOpts()); 144 145 // Break down the source location. 146 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc); 147 148 // Try to load the file buffer. 149 bool invalidTemp = false; 150 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); 151 if (invalidTemp) 152 return SourceLocation(); 153 154 const char *tokenBegin = file.data() + locInfo.second; 155 156 // Lex from the start of the given location. 157 Lexer lexer(SM.getLocForStartOfFile(locInfo.first), 158 Ctx.getLangOpts(), 159 file.begin(), tokenBegin, file.end()); 160 Token tok; 161 lexer.LexFromRawLexer(tok); 162 if (tok.isNot(tok::semi)) { 163 if (!IsDecl) 164 return SourceLocation(); 165 // Declaration may be followed with other tokens; such as an __attribute, 166 // before ending with a semicolon. 167 return findSemiAfterLocation(tok.getLocation(), Ctx, /*IsDecl*/true); 168 } 169 170 return tok.getLocation(); 171 } 172 173 bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) { 174 if (!E || !E->HasSideEffects(Ctx)) 175 return false; 176 177 E = E->IgnoreParenCasts(); 178 ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E); 179 if (!ME) 180 return true; 181 switch (ME->getMethodFamily()) { 182 case OMF_autorelease: 183 case OMF_dealloc: 184 case OMF_release: 185 case OMF_retain: 186 switch (ME->getReceiverKind()) { 187 case ObjCMessageExpr::SuperInstance: 188 return false; 189 case ObjCMessageExpr::Instance: 190 return hasSideEffects(ME->getInstanceReceiver(), Ctx); 191 default: 192 break; 193 } 194 break; 195 default: 196 break; 197 } 198 199 return true; 200 } 201 202 bool trans::isGlobalVar(Expr *E) { 203 E = E->IgnoreParenCasts(); 204 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) 205 return DRE->getDecl()->getDeclContext()->isFileContext() && 206 DRE->getDecl()->isExternallyVisible(); 207 if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E)) 208 return isGlobalVar(condOp->getTrueExpr()) && 209 isGlobalVar(condOp->getFalseExpr()); 210 211 return false; 212 } 213 214 StringRef trans::getNilString(MigrationPass &Pass) { 215 return Pass.SemaRef.PP.isMacroDefined("nil") ? "nil" : "0"; 216 } 217 218 namespace { 219 220 class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> { 221 ExprSet &Refs; 222 public: 223 ReferenceClear(ExprSet &refs) : Refs(refs) { } 224 bool VisitDeclRefExpr(DeclRefExpr *E) { Refs.erase(E); return true; } 225 }; 226 227 class ReferenceCollector : public RecursiveASTVisitor<ReferenceCollector> { 228 ValueDecl *Dcl; 229 ExprSet &Refs; 230 231 public: 232 ReferenceCollector(ValueDecl *D, ExprSet &refs) 233 : Dcl(D), Refs(refs) { } 234 235 bool VisitDeclRefExpr(DeclRefExpr *E) { 236 if (E->getDecl() == Dcl) 237 Refs.insert(E); 238 return true; 239 } 240 }; 241 242 class RemovablesCollector : public RecursiveASTVisitor<RemovablesCollector> { 243 ExprSet &Removables; 244 245 public: 246 RemovablesCollector(ExprSet &removables) 247 : Removables(removables) { } 248 249 bool shouldWalkTypesOfTypeLocs() const { return false; } 250 251 bool TraverseStmtExpr(StmtExpr *E) { 252 CompoundStmt *S = E->getSubStmt(); 253 for (CompoundStmt::body_iterator 254 I = S->body_begin(), E = S->body_end(); I != E; ++I) { 255 if (I != E - 1) 256 mark(*I); 257 TraverseStmt(*I); 258 } 259 return true; 260 } 261 262 bool VisitCompoundStmt(CompoundStmt *S) { 263 for (auto *I : S->body()) 264 mark(I); 265 return true; 266 } 267 268 bool VisitIfStmt(IfStmt *S) { 269 mark(S->getThen()); 270 mark(S->getElse()); 271 return true; 272 } 273 274 bool VisitWhileStmt(WhileStmt *S) { 275 mark(S->getBody()); 276 return true; 277 } 278 279 bool VisitDoStmt(DoStmt *S) { 280 mark(S->getBody()); 281 return true; 282 } 283 284 bool VisitForStmt(ForStmt *S) { 285 mark(S->getInit()); 286 mark(S->getInc()); 287 mark(S->getBody()); 288 return true; 289 } 290 291 private: 292 void mark(Stmt *S) { 293 if (!S) return; 294 295 while (LabelStmt *Label = dyn_cast<LabelStmt>(S)) 296 S = Label->getSubStmt(); 297 S = S->IgnoreImplicit(); 298 if (Expr *E = dyn_cast<Expr>(S)) 299 Removables.insert(E); 300 } 301 }; 302 303 } // end anonymous namespace 304 305 void trans::clearRefsIn(Stmt *S, ExprSet &refs) { 306 ReferenceClear(refs).TraverseStmt(S); 307 } 308 309 void trans::collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs) { 310 ReferenceCollector(D, refs).TraverseStmt(S); 311 } 312 313 void trans::collectRemovables(Stmt *S, ExprSet &exprs) { 314 RemovablesCollector(exprs).TraverseStmt(S); 315 } 316 317 //===----------------------------------------------------------------------===// 318 // MigrationContext 319 //===----------------------------------------------------------------------===// 320 321 namespace { 322 323 class ASTTransform : public RecursiveASTVisitor<ASTTransform> { 324 MigrationContext &MigrateCtx; 325 typedef RecursiveASTVisitor<ASTTransform> base; 326 327 public: 328 ASTTransform(MigrationContext &MigrateCtx) : MigrateCtx(MigrateCtx) { } 329 330 bool shouldWalkTypesOfTypeLocs() const { return false; } 331 332 bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) { 333 ObjCImplementationContext ImplCtx(MigrateCtx, D); 334 for (MigrationContext::traverser_iterator 335 I = MigrateCtx.traversers_begin(), 336 E = MigrateCtx.traversers_end(); I != E; ++I) 337 (*I)->traverseObjCImplementation(ImplCtx); 338 339 return base::TraverseObjCImplementationDecl(D); 340 } 341 342 bool TraverseStmt(Stmt *rootS) { 343 if (!rootS) 344 return true; 345 346 BodyContext BodyCtx(MigrateCtx, rootS); 347 for (MigrationContext::traverser_iterator 348 I = MigrateCtx.traversers_begin(), 349 E = MigrateCtx.traversers_end(); I != E; ++I) 350 (*I)->traverseBody(BodyCtx); 351 352 return true; 353 } 354 }; 355 356 } 357 358 MigrationContext::~MigrationContext() { 359 for (traverser_iterator 360 I = traversers_begin(), E = traversers_end(); I != E; ++I) 361 delete *I; 362 } 363 364 bool MigrationContext::isGCOwnedNonObjC(QualType T) { 365 while (!T.isNull()) { 366 if (const AttributedType *AttrT = T->getAs<AttributedType>()) { 367 if (AttrT->getAttrKind() == AttributedType::attr_objc_ownership) 368 return !AttrT->getModifiedType()->isObjCRetainableType(); 369 } 370 371 if (T->isArrayType()) 372 T = Pass.Ctx.getBaseElementType(T); 373 else if (const PointerType *PT = T->getAs<PointerType>()) 374 T = PT->getPointeeType(); 375 else if (const ReferenceType *RT = T->getAs<ReferenceType>()) 376 T = RT->getPointeeType(); 377 else 378 break; 379 } 380 381 return false; 382 } 383 384 bool MigrationContext::rewritePropertyAttribute(StringRef fromAttr, 385 StringRef toAttr, 386 SourceLocation atLoc) { 387 if (atLoc.isMacroID()) 388 return false; 389 390 SourceManager &SM = Pass.Ctx.getSourceManager(); 391 392 // Break down the source location. 393 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc); 394 395 // Try to load the file buffer. 396 bool invalidTemp = false; 397 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); 398 if (invalidTemp) 399 return false; 400 401 const char *tokenBegin = file.data() + locInfo.second; 402 403 // Lex from the start of the given location. 404 Lexer lexer(SM.getLocForStartOfFile(locInfo.first), 405 Pass.Ctx.getLangOpts(), 406 file.begin(), tokenBegin, file.end()); 407 Token tok; 408 lexer.LexFromRawLexer(tok); 409 if (tok.isNot(tok::at)) return false; 410 lexer.LexFromRawLexer(tok); 411 if (tok.isNot(tok::raw_identifier)) return false; 412 if (tok.getRawIdentifier() != "property") 413 return false; 414 lexer.LexFromRawLexer(tok); 415 if (tok.isNot(tok::l_paren)) return false; 416 417 Token BeforeTok = tok; 418 Token AfterTok; 419 AfterTok.startToken(); 420 SourceLocation AttrLoc; 421 422 lexer.LexFromRawLexer(tok); 423 if (tok.is(tok::r_paren)) 424 return false; 425 426 while (1) { 427 if (tok.isNot(tok::raw_identifier)) return false; 428 if (tok.getRawIdentifier() == fromAttr) { 429 if (!toAttr.empty()) { 430 Pass.TA.replaceText(tok.getLocation(), fromAttr, toAttr); 431 return true; 432 } 433 // We want to remove the attribute. 434 AttrLoc = tok.getLocation(); 435 } 436 437 do { 438 lexer.LexFromRawLexer(tok); 439 if (AttrLoc.isValid() && AfterTok.is(tok::unknown)) 440 AfterTok = tok; 441 } while (tok.isNot(tok::comma) && tok.isNot(tok::r_paren)); 442 if (tok.is(tok::r_paren)) 443 break; 444 if (AttrLoc.isInvalid()) 445 BeforeTok = tok; 446 lexer.LexFromRawLexer(tok); 447 } 448 449 if (toAttr.empty() && AttrLoc.isValid() && AfterTok.isNot(tok::unknown)) { 450 // We want to remove the attribute. 451 if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::r_paren)) { 452 Pass.TA.remove(SourceRange(BeforeTok.getLocation(), 453 AfterTok.getLocation())); 454 } else if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::comma)) { 455 Pass.TA.remove(SourceRange(AttrLoc, AfterTok.getLocation())); 456 } else { 457 Pass.TA.remove(SourceRange(BeforeTok.getLocation(), AttrLoc)); 458 } 459 460 return true; 461 } 462 463 return false; 464 } 465 466 bool MigrationContext::addPropertyAttribute(StringRef attr, 467 SourceLocation atLoc) { 468 if (atLoc.isMacroID()) 469 return false; 470 471 SourceManager &SM = Pass.Ctx.getSourceManager(); 472 473 // Break down the source location. 474 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc); 475 476 // Try to load the file buffer. 477 bool invalidTemp = false; 478 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); 479 if (invalidTemp) 480 return false; 481 482 const char *tokenBegin = file.data() + locInfo.second; 483 484 // Lex from the start of the given location. 485 Lexer lexer(SM.getLocForStartOfFile(locInfo.first), 486 Pass.Ctx.getLangOpts(), 487 file.begin(), tokenBegin, file.end()); 488 Token tok; 489 lexer.LexFromRawLexer(tok); 490 if (tok.isNot(tok::at)) return false; 491 lexer.LexFromRawLexer(tok); 492 if (tok.isNot(tok::raw_identifier)) return false; 493 if (tok.getRawIdentifier() != "property") 494 return false; 495 lexer.LexFromRawLexer(tok); 496 497 if (tok.isNot(tok::l_paren)) { 498 Pass.TA.insert(tok.getLocation(), std::string("(") + attr.str() + ") "); 499 return true; 500 } 501 502 lexer.LexFromRawLexer(tok); 503 if (tok.is(tok::r_paren)) { 504 Pass.TA.insert(tok.getLocation(), attr); 505 return true; 506 } 507 508 if (tok.isNot(tok::raw_identifier)) return false; 509 510 Pass.TA.insert(tok.getLocation(), std::string(attr) + ", "); 511 return true; 512 } 513 514 void MigrationContext::traverse(TranslationUnitDecl *TU) { 515 for (traverser_iterator 516 I = traversers_begin(), E = traversers_end(); I != E; ++I) 517 (*I)->traverseTU(*this); 518 519 ASTTransform(*this).TraverseDecl(TU); 520 } 521 522 static void GCRewriteFinalize(MigrationPass &pass) { 523 ASTContext &Ctx = pass.Ctx; 524 TransformActions &TA = pass.TA; 525 DeclContext *DC = Ctx.getTranslationUnitDecl(); 526 Selector FinalizeSel = 527 Ctx.Selectors.getNullarySelector(&pass.Ctx.Idents.get("finalize")); 528 529 typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl> 530 impl_iterator; 531 for (impl_iterator I = impl_iterator(DC->decls_begin()), 532 E = impl_iterator(DC->decls_end()); I != E; ++I) { 533 for (const auto *MD : I->instance_methods()) { 534 if (!MD->hasBody()) 535 continue; 536 537 if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) { 538 const ObjCMethodDecl *FinalizeM = MD; 539 Transaction Trans(TA); 540 TA.insert(FinalizeM->getSourceRange().getBegin(), 541 "#if !__has_feature(objc_arc)\n"); 542 CharSourceRange::getTokenRange(FinalizeM->getSourceRange()); 543 const SourceManager &SM = pass.Ctx.getSourceManager(); 544 const LangOptions &LangOpts = pass.Ctx.getLangOpts(); 545 bool Invalid; 546 std::string str = "\n#endif\n"; 547 str += Lexer::getSourceText( 548 CharSourceRange::getTokenRange(FinalizeM->getSourceRange()), 549 SM, LangOpts, &Invalid); 550 TA.insertAfterToken(FinalizeM->getSourceRange().getEnd(), str); 551 552 break; 553 } 554 } 555 } 556 } 557 558 //===----------------------------------------------------------------------===// 559 // getAllTransformations. 560 //===----------------------------------------------------------------------===// 561 562 static void traverseAST(MigrationPass &pass) { 563 MigrationContext MigrateCtx(pass); 564 565 if (pass.isGCMigration()) { 566 MigrateCtx.addTraverser(new GCCollectableCallsTraverser); 567 MigrateCtx.addTraverser(new GCAttrsTraverser()); 568 } 569 MigrateCtx.addTraverser(new PropertyRewriteTraverser()); 570 MigrateCtx.addTraverser(new BlockObjCVariableTraverser()); 571 MigrateCtx.addTraverser(new ProtectedScopeTraverser()); 572 573 MigrateCtx.traverse(pass.Ctx.getTranslationUnitDecl()); 574 } 575 576 static void independentTransforms(MigrationPass &pass) { 577 rewriteAutoreleasePool(pass); 578 removeRetainReleaseDeallocFinalize(pass); 579 rewriteUnusedInitDelegate(pass); 580 removeZeroOutPropsInDeallocFinalize(pass); 581 makeAssignARCSafe(pass); 582 rewriteUnbridgedCasts(pass); 583 checkAPIUses(pass); 584 traverseAST(pass); 585 } 586 587 std::vector<TransformFn> arcmt::getAllTransformations( 588 LangOptions::GCMode OrigGCMode, 589 bool NoFinalizeRemoval) { 590 std::vector<TransformFn> transforms; 591 592 if (OrigGCMode == LangOptions::GCOnly && NoFinalizeRemoval) 593 transforms.push_back(GCRewriteFinalize); 594 transforms.push_back(independentTransforms); 595 // This depends on previous transformations removing various expressions. 596 transforms.push_back(removeEmptyStatementsAndDeallocFinalize); 597 598 return transforms; 599 } 600