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