Transforms.cpp revision 263d66718365aadc621c3feb9badedf46d787e0e
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/AST/RecursiveASTVisitor.h" 14#include "clang/AST/StmtVisitor.h" 15#include "clang/Analysis/DomainSpecific/CocoaConventions.h" 16#include "clang/Lex/Lexer.h" 17#include "clang/Basic/SourceManager.h" 18#include "llvm/ADT/StringSwitch.h" 19#include "llvm/ADT/DenseSet.h" 20#include <map> 21 22using namespace clang; 23using namespace arcmt; 24using namespace trans; 25 26ASTTraverser::~ASTTraverser() { } 27 28//===----------------------------------------------------------------------===// 29// Helpers. 30//===----------------------------------------------------------------------===// 31 32/// \brief True if the class is one that does not support weak. 33static bool isClassInWeakBlacklist(ObjCInterfaceDecl *cls) { 34 if (!cls) 35 return false; 36 37 bool inList = llvm::StringSwitch<bool>(cls->getName()) 38 .Case("NSColorSpace", true) 39 .Case("NSFont", true) 40 .Case("NSFontPanel", true) 41 .Case("NSImage", true) 42 .Case("NSLazyBrowserCell", true) 43 .Case("NSWindow", true) 44 .Case("NSWindowController", true) 45 .Case("NSViewController", true) 46 .Case("NSMenuView", true) 47 .Case("NSPersistentUIWindowInfo", true) 48 .Case("NSTableCellView", true) 49 .Case("NSATSTypeSetter", true) 50 .Case("NSATSGlyphStorage", true) 51 .Case("NSLineFragmentRenderingContext", true) 52 .Case("NSAttributeDictionary", true) 53 .Case("NSParagraphStyle", true) 54 .Case("NSTextTab", true) 55 .Case("NSSimpleHorizontalTypesetter", true) 56 .Case("_NSCachedAttributedString", true) 57 .Case("NSStringDrawingTextStorage", true) 58 .Case("NSTextView", true) 59 .Case("NSSubTextStorage", true) 60 .Default(false); 61 62 if (inList) 63 return true; 64 65 return isClassInWeakBlacklist(cls->getSuperClass()); 66} 67 68bool trans::canApplyWeak(ASTContext &Ctx, QualType type, 69 bool AllowOnUnknownClass) { 70 if (!Ctx.getLangOptions().ObjCRuntimeHasWeak) 71 return false; 72 73 QualType T = type; 74 if (T.isNull()) 75 return false; 76 77 while (const PointerType *ptr = T->getAs<PointerType>()) 78 T = ptr->getPointeeType(); 79 if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) { 80 ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl(); 81 if (!AllowOnUnknownClass && (!Class || Class->getName() == "NSObject")) 82 return false; // id/NSObject is not safe for weak. 83 if (!AllowOnUnknownClass && Class->isForwardDecl()) 84 return false; // forward classes are not verifiable, therefore not safe. 85 if (Class->isArcWeakrefUnavailable()) 86 return false; 87 if (isClassInWeakBlacklist(Class)) 88 return false; 89 } 90 91 return true; 92} 93 94/// \brief 'Loc' is the end of a statement range. This returns the location 95/// immediately after the semicolon following the statement. 96/// If no semicolon is found or the location is inside a macro, the returned 97/// source location will be invalid. 98SourceLocation trans::findLocationAfterSemi(SourceLocation loc, 99 ASTContext &Ctx) { 100 SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx); 101 if (SemiLoc.isInvalid()) 102 return SourceLocation(); 103 return SemiLoc.getLocWithOffset(1); 104} 105 106/// \brief \arg Loc is the end of a statement range. This returns the location 107/// of the semicolon following the statement. 108/// If no semicolon is found or the location is inside a macro, the returned 109/// source location will be invalid. 110SourceLocation trans::findSemiAfterLocation(SourceLocation loc, 111 ASTContext &Ctx) { 112 SourceManager &SM = Ctx.getSourceManager(); 113 if (loc.isMacroID()) { 114 if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOptions())) 115 return SourceLocation(); 116 loc = SM.getExpansionRange(loc).second; 117 } 118 loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOptions()); 119 120 // Break down the source location. 121 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc); 122 123 // Try to load the file buffer. 124 bool invalidTemp = false; 125 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); 126 if (invalidTemp) 127 return SourceLocation(); 128 129 const char *tokenBegin = file.data() + locInfo.second; 130 131 // Lex from the start of the given location. 132 Lexer lexer(SM.getLocForStartOfFile(locInfo.first), 133 Ctx.getLangOptions(), 134 file.begin(), tokenBegin, file.end()); 135 Token tok; 136 lexer.LexFromRawLexer(tok); 137 if (tok.isNot(tok::semi)) 138 return SourceLocation(); 139 140 return tok.getLocation(); 141} 142 143bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) { 144 if (!E || !E->HasSideEffects(Ctx)) 145 return false; 146 147 E = E->IgnoreParenCasts(); 148 ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E); 149 if (!ME) 150 return true; 151 switch (ME->getMethodFamily()) { 152 case OMF_autorelease: 153 case OMF_dealloc: 154 case OMF_release: 155 case OMF_retain: 156 switch (ME->getReceiverKind()) { 157 case ObjCMessageExpr::SuperInstance: 158 return false; 159 case ObjCMessageExpr::Instance: 160 return hasSideEffects(ME->getInstanceReceiver(), Ctx); 161 default: 162 break; 163 } 164 break; 165 default: 166 break; 167 } 168 169 return true; 170} 171 172bool trans::isGlobalVar(Expr *E) { 173 E = E->IgnoreParenCasts(); 174 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) 175 return DRE->getDecl()->getDeclContext()->isFileContext() && 176 DRE->getDecl()->getLinkage() == ExternalLinkage; 177 if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E)) 178 return isGlobalVar(condOp->getTrueExpr()) && 179 isGlobalVar(condOp->getFalseExpr()); 180 181 return false; 182} 183 184StringRef trans::getNilString(ASTContext &Ctx) { 185 if (Ctx.Idents.get("nil").hasMacroDefinition()) 186 return "nil"; 187 else 188 return "0"; 189} 190 191namespace { 192 193class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> { 194 ExprSet &Refs; 195public: 196 ReferenceClear(ExprSet &refs) : Refs(refs) { } 197 bool VisitDeclRefExpr(DeclRefExpr *E) { Refs.erase(E); return true; } 198 bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { Refs.erase(E); return true; } 199}; 200 201class ReferenceCollector : public RecursiveASTVisitor<ReferenceCollector> { 202 ValueDecl *Dcl; 203 ExprSet &Refs; 204 205public: 206 ReferenceCollector(ValueDecl *D, ExprSet &refs) 207 : Dcl(D), Refs(refs) { } 208 209 bool VisitDeclRefExpr(DeclRefExpr *E) { 210 if (E->getDecl() == Dcl) 211 Refs.insert(E); 212 return true; 213 } 214 215 bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { 216 if (E->getDecl() == Dcl) 217 Refs.insert(E); 218 return true; 219 } 220}; 221 222class RemovablesCollector : public RecursiveASTVisitor<RemovablesCollector> { 223 ExprSet &Removables; 224 225public: 226 RemovablesCollector(ExprSet &removables) 227 : Removables(removables) { } 228 229 bool shouldWalkTypesOfTypeLocs() const { return false; } 230 231 bool TraverseStmtExpr(StmtExpr *E) { 232 CompoundStmt *S = E->getSubStmt(); 233 for (CompoundStmt::body_iterator 234 I = S->body_begin(), E = S->body_end(); I != E; ++I) { 235 if (I != E - 1) 236 mark(*I); 237 TraverseStmt(*I); 238 } 239 return true; 240 } 241 242 bool VisitCompoundStmt(CompoundStmt *S) { 243 for (CompoundStmt::body_iterator 244 I = S->body_begin(), E = S->body_end(); I != E; ++I) 245 mark(*I); 246 return true; 247 } 248 249 bool VisitIfStmt(IfStmt *S) { 250 mark(S->getThen()); 251 mark(S->getElse()); 252 return true; 253 } 254 255 bool VisitWhileStmt(WhileStmt *S) { 256 mark(S->getBody()); 257 return true; 258 } 259 260 bool VisitDoStmt(DoStmt *S) { 261 mark(S->getBody()); 262 return true; 263 } 264 265 bool VisitForStmt(ForStmt *S) { 266 mark(S->getInit()); 267 mark(S->getInc()); 268 mark(S->getBody()); 269 return true; 270 } 271 272private: 273 void mark(Stmt *S) { 274 if (!S) return; 275 276 while (LabelStmt *Label = dyn_cast<LabelStmt>(S)) 277 S = Label->getSubStmt(); 278 S = S->IgnoreImplicit(); 279 if (Expr *E = dyn_cast<Expr>(S)) 280 Removables.insert(E); 281 } 282}; 283 284} // end anonymous namespace 285 286void trans::clearRefsIn(Stmt *S, ExprSet &refs) { 287 ReferenceClear(refs).TraverseStmt(S); 288} 289 290void trans::collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs) { 291 ReferenceCollector(D, refs).TraverseStmt(S); 292} 293 294void trans::collectRemovables(Stmt *S, ExprSet &exprs) { 295 RemovablesCollector(exprs).TraverseStmt(S); 296} 297 298//===----------------------------------------------------------------------===// 299// MigrationContext 300//===----------------------------------------------------------------------===// 301 302namespace { 303 304class ASTTransform : public RecursiveASTVisitor<ASTTransform> { 305 MigrationContext &MigrateCtx; 306 typedef RecursiveASTVisitor<ASTTransform> base; 307 308public: 309 ASTTransform(MigrationContext &MigrateCtx) : MigrateCtx(MigrateCtx) { } 310 311 bool shouldWalkTypesOfTypeLocs() const { return false; } 312 313 bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) { 314 ObjCImplementationContext ImplCtx(MigrateCtx, D); 315 for (MigrationContext::traverser_iterator 316 I = MigrateCtx.traversers_begin(), 317 E = MigrateCtx.traversers_end(); I != E; ++I) 318 (*I)->traverseObjCImplementation(ImplCtx); 319 320 return base::TraverseObjCImplementationDecl(D); 321 } 322 323 bool TraverseStmt(Stmt *rootS) { 324 if (!rootS) 325 return true; 326 327 BodyContext BodyCtx(MigrateCtx, rootS); 328 for (MigrationContext::traverser_iterator 329 I = MigrateCtx.traversers_begin(), 330 E = MigrateCtx.traversers_end(); I != E; ++I) 331 (*I)->traverseBody(BodyCtx); 332 333 return true; 334 } 335}; 336 337} 338 339MigrationContext::~MigrationContext() { 340 for (traverser_iterator 341 I = traversers_begin(), E = traversers_end(); I != E; ++I) 342 delete *I; 343} 344 345bool MigrationContext::isGCOwnedNonObjC(QualType T) { 346 while (!T.isNull()) { 347 if (const AttributedType *AttrT = T->getAs<AttributedType>()) { 348 if (AttrT->getAttrKind() == AttributedType::attr_objc_ownership) 349 return !AttrT->getModifiedType()->isObjCRetainableType(); 350 } 351 352 if (T->isArrayType()) 353 T = Pass.Ctx.getBaseElementType(T); 354 else if (const PointerType *PT = T->getAs<PointerType>()) 355 T = PT->getPointeeType(); 356 else if (const ReferenceType *RT = T->getAs<ReferenceType>()) 357 T = RT->getPointeeType(); 358 else 359 break; 360 } 361 362 return false; 363} 364 365bool MigrationContext::rewritePropertyAttribute(StringRef fromAttr, 366 StringRef toAttr, 367 SourceLocation atLoc) { 368 if (atLoc.isMacroID()) 369 return false; 370 371 SourceManager &SM = Pass.Ctx.getSourceManager(); 372 373 // Break down the source location. 374 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc); 375 376 // Try to load the file buffer. 377 bool invalidTemp = false; 378 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); 379 if (invalidTemp) 380 return false; 381 382 const char *tokenBegin = file.data() + locInfo.second; 383 384 // Lex from the start of the given location. 385 Lexer lexer(SM.getLocForStartOfFile(locInfo.first), 386 Pass.Ctx.getLangOptions(), 387 file.begin(), tokenBegin, file.end()); 388 Token tok; 389 lexer.LexFromRawLexer(tok); 390 if (tok.isNot(tok::at)) return false; 391 lexer.LexFromRawLexer(tok); 392 if (tok.isNot(tok::raw_identifier)) return false; 393 if (StringRef(tok.getRawIdentifierData(), tok.getLength()) 394 != "property") 395 return false; 396 lexer.LexFromRawLexer(tok); 397 if (tok.isNot(tok::l_paren)) return false; 398 399 Token BeforeTok = tok; 400 Token AfterTok; 401 AfterTok.startToken(); 402 SourceLocation AttrLoc; 403 404 lexer.LexFromRawLexer(tok); 405 if (tok.is(tok::r_paren)) 406 return false; 407 408 while (1) { 409 if (tok.isNot(tok::raw_identifier)) return false; 410 StringRef ident(tok.getRawIdentifierData(), tok.getLength()); 411 if (ident == fromAttr) { 412 if (!toAttr.empty()) { 413 Pass.TA.replaceText(tok.getLocation(), fromAttr, toAttr); 414 return true; 415 } 416 // We want to remove the attribute. 417 AttrLoc = tok.getLocation(); 418 } 419 420 do { 421 lexer.LexFromRawLexer(tok); 422 if (AttrLoc.isValid() && AfterTok.is(tok::unknown)) 423 AfterTok = tok; 424 } while (tok.isNot(tok::comma) && tok.isNot(tok::r_paren)); 425 if (tok.is(tok::r_paren)) 426 break; 427 if (AttrLoc.isInvalid()) 428 BeforeTok = tok; 429 lexer.LexFromRawLexer(tok); 430 } 431 432 if (toAttr.empty() && AttrLoc.isValid() && AfterTok.isNot(tok::unknown)) { 433 // We want to remove the attribute. 434 if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::r_paren)) { 435 Pass.TA.remove(SourceRange(BeforeTok.getLocation(), 436 AfterTok.getLocation())); 437 } else if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::comma)) { 438 Pass.TA.remove(SourceRange(AttrLoc, AfterTok.getLocation())); 439 } else { 440 Pass.TA.remove(SourceRange(BeforeTok.getLocation(), AttrLoc)); 441 } 442 443 return true; 444 } 445 446 return false; 447} 448 449void MigrationContext::traverse(TranslationUnitDecl *TU) { 450 for (traverser_iterator 451 I = traversers_begin(), E = traversers_end(); I != E; ++I) 452 (*I)->traverseTU(*this); 453 454 ASTTransform(*this).TraverseDecl(TU); 455} 456 457//===----------------------------------------------------------------------===// 458// getAllTransformations. 459//===----------------------------------------------------------------------===// 460 461static void traverseAST(MigrationPass &pass) { 462 MigrationContext MigrateCtx(pass); 463 464 if (pass.isGCMigration()) { 465 MigrateCtx.addTraverser(new GCCollectableCallsTraverser); 466 MigrateCtx.addTraverser(new GCAttrsTraverser()); 467 } 468 MigrateCtx.addTraverser(new PropertyRewriteTraverser()); 469 470 MigrateCtx.traverse(pass.Ctx.getTranslationUnitDecl()); 471} 472 473static void independentTransforms(MigrationPass &pass) { 474 rewriteAutoreleasePool(pass); 475 removeRetainReleaseDeallocFinalize(pass); 476 rewriteUnusedInitDelegate(pass); 477 removeZeroOutPropsInDeallocFinalize(pass); 478 makeAssignARCSafe(pass); 479 rewriteUnbridgedCasts(pass); 480 rewriteBlockObjCVariable(pass); 481 checkAPIUses(pass); 482 traverseAST(pass); 483} 484 485std::vector<TransformFn> arcmt::getAllTransformations( 486 LangOptions::GCMode OrigGCMode) { 487 std::vector<TransformFn> transforms; 488 489 transforms.push_back(independentTransforms); 490 // This depends on previous transformations removing various expressions. 491 transforms.push_back(removeEmptyStatementsAndDeallocFinalize); 492 493 return transforms; 494} 495