clang API Documentation
00001 //===--- Tranforms.cpp - Tranformations to ARC mode -----------------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 00010 #include "Transforms.h" 00011 #include "Internals.h" 00012 #include "clang/Sema/SemaDiagnostic.h" 00013 #include "clang/AST/RecursiveASTVisitor.h" 00014 #include "clang/AST/StmtVisitor.h" 00015 #include "clang/Lex/Lexer.h" 00016 #include "clang/Basic/SourceManager.h" 00017 #include "llvm/ADT/StringSwitch.h" 00018 #include "llvm/ADT/DenseSet.h" 00019 #include <map> 00020 00021 using namespace clang; 00022 using namespace arcmt; 00023 using namespace trans; 00024 00025 ASTTraverser::~ASTTraverser() { } 00026 00027 //===----------------------------------------------------------------------===// 00028 // Helpers. 00029 //===----------------------------------------------------------------------===// 00030 00031 bool trans::canApplyWeak(ASTContext &Ctx, QualType type, 00032 bool AllowOnUnknownClass) { 00033 if (!Ctx.getLangOpts().ObjCRuntimeHasWeak) 00034 return false; 00035 00036 QualType T = type; 00037 if (T.isNull()) 00038 return false; 00039 00040 // iOS is always safe to use 'weak'. 00041 if (Ctx.getTargetInfo().getTriple().getOS() == llvm::Triple::IOS) 00042 AllowOnUnknownClass = true; 00043 00044 while (const PointerType *ptr = T->getAs<PointerType>()) 00045 T = ptr->getPointeeType(); 00046 if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) { 00047 ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl(); 00048 if (!AllowOnUnknownClass && (!Class || Class->getName() == "NSObject")) 00049 return false; // id/NSObject is not safe for weak. 00050 if (!AllowOnUnknownClass && !Class->hasDefinition()) 00051 return false; // forward classes are not verifiable, therefore not safe. 00052 if (Class->isArcWeakrefUnavailable()) 00053 return false; 00054 } 00055 00056 return true; 00057 } 00058 00059 /// \brief 'Loc' is the end of a statement range. This returns the location 00060 /// immediately after the semicolon following the statement. 00061 /// If no semicolon is found or the location is inside a macro, the returned 00062 /// source location will be invalid. 00063 SourceLocation trans::findLocationAfterSemi(SourceLocation loc, 00064 ASTContext &Ctx) { 00065 SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx); 00066 if (SemiLoc.isInvalid()) 00067 return SourceLocation(); 00068 return SemiLoc.getLocWithOffset(1); 00069 } 00070 00071 /// \brief \arg Loc is the end of a statement range. This returns the location 00072 /// of the semicolon following the statement. 00073 /// If no semicolon is found or the location is inside a macro, the returned 00074 /// source location will be invalid. 00075 SourceLocation trans::findSemiAfterLocation(SourceLocation loc, 00076 ASTContext &Ctx) { 00077 SourceManager &SM = Ctx.getSourceManager(); 00078 if (loc.isMacroID()) { 00079 if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOpts(), &loc)) 00080 return SourceLocation(); 00081 } 00082 loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOpts()); 00083 00084 // Break down the source location. 00085 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc); 00086 00087 // Try to load the file buffer. 00088 bool invalidTemp = false; 00089 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); 00090 if (invalidTemp) 00091 return SourceLocation(); 00092 00093 const char *tokenBegin = file.data() + locInfo.second; 00094 00095 // Lex from the start of the given location. 00096 Lexer lexer(SM.getLocForStartOfFile(locInfo.first), 00097 Ctx.getLangOpts(), 00098 file.begin(), tokenBegin, file.end()); 00099 Token tok; 00100 lexer.LexFromRawLexer(tok); 00101 if (tok.isNot(tok::semi)) 00102 return SourceLocation(); 00103 00104 return tok.getLocation(); 00105 } 00106 00107 bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) { 00108 if (!E || !E->HasSideEffects(Ctx)) 00109 return false; 00110 00111 E = E->IgnoreParenCasts(); 00112 ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E); 00113 if (!ME) 00114 return true; 00115 switch (ME->getMethodFamily()) { 00116 case OMF_autorelease: 00117 case OMF_dealloc: 00118 case OMF_release: 00119 case OMF_retain: 00120 switch (ME->getReceiverKind()) { 00121 case ObjCMessageExpr::SuperInstance: 00122 return false; 00123 case ObjCMessageExpr::Instance: 00124 return hasSideEffects(ME->getInstanceReceiver(), Ctx); 00125 default: 00126 break; 00127 } 00128 break; 00129 default: 00130 break; 00131 } 00132 00133 return true; 00134 } 00135 00136 bool trans::isGlobalVar(Expr *E) { 00137 E = E->IgnoreParenCasts(); 00138 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) 00139 return DRE->getDecl()->getDeclContext()->isFileContext() && 00140 DRE->getDecl()->getLinkage() == ExternalLinkage; 00141 if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E)) 00142 return isGlobalVar(condOp->getTrueExpr()) && 00143 isGlobalVar(condOp->getFalseExpr()); 00144 00145 return false; 00146 } 00147 00148 StringRef trans::getNilString(ASTContext &Ctx) { 00149 if (Ctx.Idents.get("nil").hasMacroDefinition()) 00150 return "nil"; 00151 else 00152 return "0"; 00153 } 00154 00155 namespace { 00156 00157 class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> { 00158 ExprSet &Refs; 00159 public: 00160 ReferenceClear(ExprSet &refs) : Refs(refs) { } 00161 bool VisitDeclRefExpr(DeclRefExpr *E) { Refs.erase(E); return true; } 00162 }; 00163 00164 class ReferenceCollector : public RecursiveASTVisitor<ReferenceCollector> { 00165 ValueDecl *Dcl; 00166 ExprSet &Refs; 00167 00168 public: 00169 ReferenceCollector(ValueDecl *D, ExprSet &refs) 00170 : Dcl(D), Refs(refs) { } 00171 00172 bool VisitDeclRefExpr(DeclRefExpr *E) { 00173 if (E->getDecl() == Dcl) 00174 Refs.insert(E); 00175 return true; 00176 } 00177 }; 00178 00179 class RemovablesCollector : public RecursiveASTVisitor<RemovablesCollector> { 00180 ExprSet &Removables; 00181 00182 public: 00183 RemovablesCollector(ExprSet &removables) 00184 : Removables(removables) { } 00185 00186 bool shouldWalkTypesOfTypeLocs() const { return false; } 00187 00188 bool TraverseStmtExpr(StmtExpr *E) { 00189 CompoundStmt *S = E->getSubStmt(); 00190 for (CompoundStmt::body_iterator 00191 I = S->body_begin(), E = S->body_end(); I != E; ++I) { 00192 if (I != E - 1) 00193 mark(*I); 00194 TraverseStmt(*I); 00195 } 00196 return true; 00197 } 00198 00199 bool VisitCompoundStmt(CompoundStmt *S) { 00200 for (CompoundStmt::body_iterator 00201 I = S->body_begin(), E = S->body_end(); I != E; ++I) 00202 mark(*I); 00203 return true; 00204 } 00205 00206 bool VisitIfStmt(IfStmt *S) { 00207 mark(S->getThen()); 00208 mark(S->getElse()); 00209 return true; 00210 } 00211 00212 bool VisitWhileStmt(WhileStmt *S) { 00213 mark(S->getBody()); 00214 return true; 00215 } 00216 00217 bool VisitDoStmt(DoStmt *S) { 00218 mark(S->getBody()); 00219 return true; 00220 } 00221 00222 bool VisitForStmt(ForStmt *S) { 00223 mark(S->getInit()); 00224 mark(S->getInc()); 00225 mark(S->getBody()); 00226 return true; 00227 } 00228 00229 private: 00230 void mark(Stmt *S) { 00231 if (!S) return; 00232 00233 while (LabelStmt *Label = dyn_cast<LabelStmt>(S)) 00234 S = Label->getSubStmt(); 00235 S = S->IgnoreImplicit(); 00236 if (Expr *E = dyn_cast<Expr>(S)) 00237 Removables.insert(E); 00238 } 00239 }; 00240 00241 } // end anonymous namespace 00242 00243 void trans::clearRefsIn(Stmt *S, ExprSet &refs) { 00244 ReferenceClear(refs).TraverseStmt(S); 00245 } 00246 00247 void trans::collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs) { 00248 ReferenceCollector(D, refs).TraverseStmt(S); 00249 } 00250 00251 void trans::collectRemovables(Stmt *S, ExprSet &exprs) { 00252 RemovablesCollector(exprs).TraverseStmt(S); 00253 } 00254 00255 //===----------------------------------------------------------------------===// 00256 // MigrationContext 00257 //===----------------------------------------------------------------------===// 00258 00259 namespace { 00260 00261 class ASTTransform : public RecursiveASTVisitor<ASTTransform> { 00262 MigrationContext &MigrateCtx; 00263 typedef RecursiveASTVisitor<ASTTransform> base; 00264 00265 public: 00266 ASTTransform(MigrationContext &MigrateCtx) : MigrateCtx(MigrateCtx) { } 00267 00268 bool shouldWalkTypesOfTypeLocs() const { return false; } 00269 00270 bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) { 00271 ObjCImplementationContext ImplCtx(MigrateCtx, D); 00272 for (MigrationContext::traverser_iterator 00273 I = MigrateCtx.traversers_begin(), 00274 E = MigrateCtx.traversers_end(); I != E; ++I) 00275 (*I)->traverseObjCImplementation(ImplCtx); 00276 00277 return base::TraverseObjCImplementationDecl(D); 00278 } 00279 00280 bool TraverseStmt(Stmt *rootS) { 00281 if (!rootS) 00282 return true; 00283 00284 BodyContext BodyCtx(MigrateCtx, rootS); 00285 for (MigrationContext::traverser_iterator 00286 I = MigrateCtx.traversers_begin(), 00287 E = MigrateCtx.traversers_end(); I != E; ++I) 00288 (*I)->traverseBody(BodyCtx); 00289 00290 return true; 00291 } 00292 }; 00293 00294 } 00295 00296 MigrationContext::~MigrationContext() { 00297 for (traverser_iterator 00298 I = traversers_begin(), E = traversers_end(); I != E; ++I) 00299 delete *I; 00300 } 00301 00302 bool MigrationContext::isGCOwnedNonObjC(QualType T) { 00303 while (!T.isNull()) { 00304 if (const AttributedType *AttrT = T->getAs<AttributedType>()) { 00305 if (AttrT->getAttrKind() == AttributedType::attr_objc_ownership) 00306 return !AttrT->getModifiedType()->isObjCRetainableType(); 00307 } 00308 00309 if (T->isArrayType()) 00310 T = Pass.Ctx.getBaseElementType(T); 00311 else if (const PointerType *PT = T->getAs<PointerType>()) 00312 T = PT->getPointeeType(); 00313 else if (const ReferenceType *RT = T->getAs<ReferenceType>()) 00314 T = RT->getPointeeType(); 00315 else 00316 break; 00317 } 00318 00319 return false; 00320 } 00321 00322 bool MigrationContext::rewritePropertyAttribute(StringRef fromAttr, 00323 StringRef toAttr, 00324 SourceLocation atLoc) { 00325 if (atLoc.isMacroID()) 00326 return false; 00327 00328 SourceManager &SM = Pass.Ctx.getSourceManager(); 00329 00330 // Break down the source location. 00331 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc); 00332 00333 // Try to load the file buffer. 00334 bool invalidTemp = false; 00335 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); 00336 if (invalidTemp) 00337 return false; 00338 00339 const char *tokenBegin = file.data() + locInfo.second; 00340 00341 // Lex from the start of the given location. 00342 Lexer lexer(SM.getLocForStartOfFile(locInfo.first), 00343 Pass.Ctx.getLangOpts(), 00344 file.begin(), tokenBegin, file.end()); 00345 Token tok; 00346 lexer.LexFromRawLexer(tok); 00347 if (tok.isNot(tok::at)) return false; 00348 lexer.LexFromRawLexer(tok); 00349 if (tok.isNot(tok::raw_identifier)) return false; 00350 if (StringRef(tok.getRawIdentifierData(), tok.getLength()) 00351 != "property") 00352 return false; 00353 lexer.LexFromRawLexer(tok); 00354 if (tok.isNot(tok::l_paren)) return false; 00355 00356 Token BeforeTok = tok; 00357 Token AfterTok; 00358 AfterTok.startToken(); 00359 SourceLocation AttrLoc; 00360 00361 lexer.LexFromRawLexer(tok); 00362 if (tok.is(tok::r_paren)) 00363 return false; 00364 00365 while (1) { 00366 if (tok.isNot(tok::raw_identifier)) return false; 00367 StringRef ident(tok.getRawIdentifierData(), tok.getLength()); 00368 if (ident == fromAttr) { 00369 if (!toAttr.empty()) { 00370 Pass.TA.replaceText(tok.getLocation(), fromAttr, toAttr); 00371 return true; 00372 } 00373 // We want to remove the attribute. 00374 AttrLoc = tok.getLocation(); 00375 } 00376 00377 do { 00378 lexer.LexFromRawLexer(tok); 00379 if (AttrLoc.isValid() && AfterTok.is(tok::unknown)) 00380 AfterTok = tok; 00381 } while (tok.isNot(tok::comma) && tok.isNot(tok::r_paren)); 00382 if (tok.is(tok::r_paren)) 00383 break; 00384 if (AttrLoc.isInvalid()) 00385 BeforeTok = tok; 00386 lexer.LexFromRawLexer(tok); 00387 } 00388 00389 if (toAttr.empty() && AttrLoc.isValid() && AfterTok.isNot(tok::unknown)) { 00390 // We want to remove the attribute. 00391 if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::r_paren)) { 00392 Pass.TA.remove(SourceRange(BeforeTok.getLocation(), 00393 AfterTok.getLocation())); 00394 } else if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::comma)) { 00395 Pass.TA.remove(SourceRange(AttrLoc, AfterTok.getLocation())); 00396 } else { 00397 Pass.TA.remove(SourceRange(BeforeTok.getLocation(), AttrLoc)); 00398 } 00399 00400 return true; 00401 } 00402 00403 return false; 00404 } 00405 00406 bool MigrationContext::addPropertyAttribute(StringRef attr, 00407 SourceLocation atLoc) { 00408 if (atLoc.isMacroID()) 00409 return false; 00410 00411 SourceManager &SM = Pass.Ctx.getSourceManager(); 00412 00413 // Break down the source location. 00414 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc); 00415 00416 // Try to load the file buffer. 00417 bool invalidTemp = false; 00418 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); 00419 if (invalidTemp) 00420 return false; 00421 00422 const char *tokenBegin = file.data() + locInfo.second; 00423 00424 // Lex from the start of the given location. 00425 Lexer lexer(SM.getLocForStartOfFile(locInfo.first), 00426 Pass.Ctx.getLangOpts(), 00427 file.begin(), tokenBegin, file.end()); 00428 Token tok; 00429 lexer.LexFromRawLexer(tok); 00430 if (tok.isNot(tok::at)) return false; 00431 lexer.LexFromRawLexer(tok); 00432 if (tok.isNot(tok::raw_identifier)) return false; 00433 if (StringRef(tok.getRawIdentifierData(), tok.getLength()) 00434 != "property") 00435 return false; 00436 lexer.LexFromRawLexer(tok); 00437 00438 if (tok.isNot(tok::l_paren)) { 00439 Pass.TA.insert(tok.getLocation(), std::string("(") + attr.str() + ") "); 00440 return true; 00441 } 00442 00443 lexer.LexFromRawLexer(tok); 00444 if (tok.is(tok::r_paren)) { 00445 Pass.TA.insert(tok.getLocation(), attr); 00446 return true; 00447 } 00448 00449 if (tok.isNot(tok::raw_identifier)) return false; 00450 00451 Pass.TA.insert(tok.getLocation(), std::string(attr) + ", "); 00452 return true; 00453 } 00454 00455 void MigrationContext::traverse(TranslationUnitDecl *TU) { 00456 for (traverser_iterator 00457 I = traversers_begin(), E = traversers_end(); I != E; ++I) 00458 (*I)->traverseTU(*this); 00459 00460 ASTTransform(*this).TraverseDecl(TU); 00461 } 00462 00463 static void GCRewriteFinalize(MigrationPass &pass) { 00464 ASTContext &Ctx = pass.Ctx; 00465 TransformActions &TA = pass.TA; 00466 DeclContext *DC = Ctx.getTranslationUnitDecl(); 00467 Selector FinalizeSel = 00468 Ctx.Selectors.getNullarySelector(&pass.Ctx.Idents.get("finalize")); 00469 00470 typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl> 00471 impl_iterator; 00472 for (impl_iterator I = impl_iterator(DC->decls_begin()), 00473 E = impl_iterator(DC->decls_end()); I != E; ++I) { 00474 for (ObjCImplementationDecl::instmeth_iterator 00475 MI = I->instmeth_begin(), 00476 ME = I->instmeth_end(); MI != ME; ++MI) { 00477 ObjCMethodDecl *MD = *MI; 00478 if (!MD->hasBody()) 00479 continue; 00480 00481 if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) { 00482 ObjCMethodDecl *FinalizeM = MD; 00483 Transaction Trans(TA); 00484 TA.insert(FinalizeM->getSourceRange().getBegin(), 00485 "#if !__has_feature(objc_arc)\n"); 00486 CharSourceRange::getTokenRange(FinalizeM->getSourceRange()); 00487 const SourceManager &SM = pass.Ctx.getSourceManager(); 00488 const LangOptions &LangOpts = pass.Ctx.getLangOpts(); 00489 bool Invalid; 00490 std::string str = "\n#endif\n"; 00491 str += Lexer::getSourceText( 00492 CharSourceRange::getTokenRange(FinalizeM->getSourceRange()), 00493 SM, LangOpts, &Invalid); 00494 TA.insertAfterToken(FinalizeM->getSourceRange().getEnd(), str); 00495 00496 break; 00497 } 00498 } 00499 } 00500 } 00501 00502 //===----------------------------------------------------------------------===// 00503 // getAllTransformations. 00504 //===----------------------------------------------------------------------===// 00505 00506 static void traverseAST(MigrationPass &pass) { 00507 MigrationContext MigrateCtx(pass); 00508 00509 if (pass.isGCMigration()) { 00510 MigrateCtx.addTraverser(new GCCollectableCallsTraverser); 00511 MigrateCtx.addTraverser(new GCAttrsTraverser()); 00512 } 00513 MigrateCtx.addTraverser(new PropertyRewriteTraverser()); 00514 MigrateCtx.addTraverser(new BlockObjCVariableTraverser()); 00515 00516 MigrateCtx.traverse(pass.Ctx.getTranslationUnitDecl()); 00517 } 00518 00519 static void independentTransforms(MigrationPass &pass) { 00520 rewriteAutoreleasePool(pass); 00521 removeRetainReleaseDeallocFinalize(pass); 00522 rewriteUnusedInitDelegate(pass); 00523 removeZeroOutPropsInDeallocFinalize(pass); 00524 makeAssignARCSafe(pass); 00525 rewriteUnbridgedCasts(pass); 00526 checkAPIUses(pass); 00527 traverseAST(pass); 00528 } 00529 00530 std::vector<TransformFn> arcmt::getAllTransformations( 00531 LangOptions::GCMode OrigGCMode, 00532 bool NoFinalizeRemoval) { 00533 std::vector<TransformFn> transforms; 00534 00535 if (OrigGCMode == LangOptions::GCOnly && NoFinalizeRemoval) 00536 transforms.push_back(GCRewriteFinalize); 00537 transforms.push_back(independentTransforms); 00538 // This depends on previous transformations removing various expressions. 00539 transforms.push_back(removeEmptyStatementsAndDeallocFinalize); 00540 00541 return transforms; 00542 }