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