Transforms.cpp revision 1fe4203ca05d0a3283efc8a2e8c01ecdf78fbf2e
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("NSMenuView", true) 46 .Case("NSPersistentUIWindowInfo", true) 47 .Case("NSTableCellView", true) 48 .Case("NSATSTypeSetter", true) 49 .Case("NSATSGlyphStorage", true) 50 .Case("NSLineFragmentRenderingContext", true) 51 .Case("NSAttributeDictionary", true) 52 .Case("NSParagraphStyle", true) 53 .Case("NSTextTab", true) 54 .Case("NSSimpleHorizontalTypesetter", true) 55 .Case("_NSCachedAttributedString", true) 56 .Case("NSStringDrawingTextStorage", true) 57 .Case("NSTextView", true) 58 .Case("NSSubTextStorage", true) 59 .Default(false); 60 61 if (inList) 62 return true; 63 64 return isClassInWeakBlacklist(cls->getSuperClass()); 65} 66 67bool trans::canApplyWeak(ASTContext &Ctx, QualType type) { 68 if (!Ctx.getLangOptions().ObjCRuntimeHasWeak) 69 return false; 70 71 QualType T = type; 72 while (const PointerType *ptr = T->getAs<PointerType>()) 73 T = ptr->getPointeeType(); 74 if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) { 75 ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl(); 76 if (!Class || Class->getName() == "NSObject") 77 return false; // id/NSObject is not safe for weak. 78 if (Class->isForwardDecl()) 79 return false; // forward classes are not verifiable, therefore not safe. 80 if (Class->isArcWeakrefUnavailable()) 81 return false; 82 if (isClassInWeakBlacklist(Class)) 83 return false; 84 } 85 86 return true; 87} 88 89/// \brief 'Loc' is the end of a statement range. This returns the location 90/// immediately after the semicolon following the statement. 91/// If no semicolon is found or the location is inside a macro, the returned 92/// source location will be invalid. 93SourceLocation trans::findLocationAfterSemi(SourceLocation loc, 94 ASTContext &Ctx) { 95 SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx); 96 if (SemiLoc.isInvalid()) 97 return SourceLocation(); 98 return SemiLoc.getLocWithOffset(1); 99} 100 101/// \brief \arg Loc is the end of a statement range. This returns the location 102/// of the semicolon following the statement. 103/// If no semicolon is found or the location is inside a macro, the returned 104/// source location will be invalid. 105SourceLocation trans::findSemiAfterLocation(SourceLocation loc, 106 ASTContext &Ctx) { 107 SourceManager &SM = Ctx.getSourceManager(); 108 if (loc.isMacroID()) { 109 if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOptions())) 110 return SourceLocation(); 111 loc = SM.getExpansionRange(loc).second; 112 } 113 loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOptions()); 114 115 // Break down the source location. 116 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc); 117 118 // Try to load the file buffer. 119 bool invalidTemp = false; 120 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); 121 if (invalidTemp) 122 return SourceLocation(); 123 124 const char *tokenBegin = file.data() + locInfo.second; 125 126 // Lex from the start of the given location. 127 Lexer lexer(SM.getLocForStartOfFile(locInfo.first), 128 Ctx.getLangOptions(), 129 file.begin(), tokenBegin, file.end()); 130 Token tok; 131 lexer.LexFromRawLexer(tok); 132 if (tok.isNot(tok::semi)) 133 return SourceLocation(); 134 135 return tok.getLocation(); 136} 137 138bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) { 139 if (!E || !E->HasSideEffects(Ctx)) 140 return false; 141 142 E = E->IgnoreParenCasts(); 143 ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E); 144 if (!ME) 145 return true; 146 switch (ME->getMethodFamily()) { 147 case OMF_autorelease: 148 case OMF_dealloc: 149 case OMF_release: 150 case OMF_retain: 151 switch (ME->getReceiverKind()) { 152 case ObjCMessageExpr::SuperInstance: 153 return false; 154 case ObjCMessageExpr::Instance: 155 return hasSideEffects(ME->getInstanceReceiver(), Ctx); 156 default: 157 break; 158 } 159 break; 160 default: 161 break; 162 } 163 164 return true; 165} 166 167bool trans::isGlobalVar(Expr *E) { 168 E = E->IgnoreParenCasts(); 169 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) 170 return DRE->getDecl()->getDeclContext()->isFileContext() && 171 DRE->getDecl()->getLinkage() == ExternalLinkage; 172 if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E)) 173 return isGlobalVar(condOp->getTrueExpr()) && 174 isGlobalVar(condOp->getFalseExpr()); 175 176 return false; 177} 178 179StringRef trans::getNilString(ASTContext &Ctx) { 180 if (Ctx.Idents.get("nil").hasMacroDefinition()) 181 return "nil"; 182 else 183 return "0"; 184} 185 186namespace { 187 188class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> { 189 ExprSet &Refs; 190public: 191 ReferenceClear(ExprSet &refs) : Refs(refs) { } 192 bool VisitDeclRefExpr(DeclRefExpr *E) { Refs.erase(E); return true; } 193 bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { Refs.erase(E); return true; } 194}; 195 196class ReferenceCollector : public RecursiveASTVisitor<ReferenceCollector> { 197 ValueDecl *Dcl; 198 ExprSet &Refs; 199 200public: 201 ReferenceCollector(ValueDecl *D, ExprSet &refs) 202 : Dcl(D), Refs(refs) { } 203 204 bool VisitDeclRefExpr(DeclRefExpr *E) { 205 if (E->getDecl() == Dcl) 206 Refs.insert(E); 207 return true; 208 } 209 210 bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { 211 if (E->getDecl() == Dcl) 212 Refs.insert(E); 213 return true; 214 } 215}; 216 217class RemovablesCollector : public RecursiveASTVisitor<RemovablesCollector> { 218 ExprSet &Removables; 219 220public: 221 RemovablesCollector(ExprSet &removables) 222 : Removables(removables) { } 223 224 bool shouldWalkTypesOfTypeLocs() const { return false; } 225 226 bool TraverseStmtExpr(StmtExpr *E) { 227 CompoundStmt *S = E->getSubStmt(); 228 for (CompoundStmt::body_iterator 229 I = S->body_begin(), E = S->body_end(); I != E; ++I) { 230 if (I != E - 1) 231 mark(*I); 232 TraverseStmt(*I); 233 } 234 return true; 235 } 236 237 bool VisitCompoundStmt(CompoundStmt *S) { 238 for (CompoundStmt::body_iterator 239 I = S->body_begin(), E = S->body_end(); I != E; ++I) 240 mark(*I); 241 return true; 242 } 243 244 bool VisitIfStmt(IfStmt *S) { 245 mark(S->getThen()); 246 mark(S->getElse()); 247 return true; 248 } 249 250 bool VisitWhileStmt(WhileStmt *S) { 251 mark(S->getBody()); 252 return true; 253 } 254 255 bool VisitDoStmt(DoStmt *S) { 256 mark(S->getBody()); 257 return true; 258 } 259 260 bool VisitForStmt(ForStmt *S) { 261 mark(S->getInit()); 262 mark(S->getInc()); 263 mark(S->getBody()); 264 return true; 265 } 266 267private: 268 void mark(Stmt *S) { 269 if (!S) return; 270 271 while (LabelStmt *Label = dyn_cast<LabelStmt>(S)) 272 S = Label->getSubStmt(); 273 S = S->IgnoreImplicit(); 274 if (Expr *E = dyn_cast<Expr>(S)) 275 Removables.insert(E); 276 } 277}; 278 279} // end anonymous namespace 280 281void trans::clearRefsIn(Stmt *S, ExprSet &refs) { 282 ReferenceClear(refs).TraverseStmt(S); 283} 284 285void trans::collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs) { 286 ReferenceCollector(D, refs).TraverseStmt(S); 287} 288 289void trans::collectRemovables(Stmt *S, ExprSet &exprs) { 290 RemovablesCollector(exprs).TraverseStmt(S); 291} 292 293//===----------------------------------------------------------------------===// 294// MigrationContext 295//===----------------------------------------------------------------------===// 296 297namespace { 298 299class ASTTransform : public RecursiveASTVisitor<ASTTransform> { 300 MigrationContext &MigrateCtx; 301 302public: 303 ASTTransform(MigrationContext &MigrateCtx) : MigrateCtx(MigrateCtx) { } 304 305 bool TraverseStmt(Stmt *rootS) { 306 if (!rootS) 307 return true; 308 309 BodyContext BodyCtx(MigrateCtx, rootS); 310 for (MigrationContext::traverser_iterator 311 I = MigrateCtx.traversers_begin(), 312 E = MigrateCtx.traversers_end(); I != E; ++I) 313 (*I)->traverseBody(BodyCtx); 314 315 return true; 316 } 317}; 318 319} 320 321MigrationContext::~MigrationContext() { 322 for (traverser_iterator 323 I = traversers_begin(), E = traversers_end(); I != E; ++I) 324 delete *I; 325} 326 327bool MigrationContext::isGCOwnedNonObjC(QualType T) { 328 while (!T.isNull()) { 329 if (const AttributedType *AttrT = T->getAs<AttributedType>()) { 330 if (AttrT->getAttrKind() == AttributedType::attr_objc_ownership) 331 return !AttrT->getModifiedType()->isObjCRetainableType(); 332 } 333 334 if (T->isArrayType()) 335 T = Pass.Ctx.getBaseElementType(T); 336 else if (const PointerType *PT = T->getAs<PointerType>()) 337 T = PT->getPointeeType(); 338 else if (const ReferenceType *RT = T->getAs<ReferenceType>()) 339 T = RT->getPointeeType(); 340 else 341 break; 342 } 343 344 return false; 345} 346 347void MigrationContext::traverse(TranslationUnitDecl *TU) { 348 ASTTransform(*this).TraverseDecl(TU); 349} 350 351//===----------------------------------------------------------------------===// 352// getAllTransformations. 353//===----------------------------------------------------------------------===// 354 355static void traverseAST(MigrationPass &pass) { 356 MigrationContext MigrateCtx(pass); 357 358 if (pass.isGCMigration()) { 359 MigrateCtx.addTraverser(new GCCollectableCallsTraverser); 360 } 361 362 MigrateCtx.traverse(pass.Ctx.getTranslationUnitDecl()); 363} 364 365static void independentTransforms(MigrationPass &pass) { 366 rewriteAutoreleasePool(pass); 367 rewriteProperties(pass); 368 removeRetainReleaseDeallocFinalize(pass); 369 rewriteUnusedInitDelegate(pass); 370 removeZeroOutPropsInDeallocFinalize(pass); 371 makeAssignARCSafe(pass); 372 rewriteUnbridgedCasts(pass); 373 rewriteBlockObjCVariable(pass); 374 checkAPIUses(pass); 375 traverseAST(pass); 376} 377 378std::vector<TransformFn> arcmt::getAllTransformations( 379 LangOptions::GCMode OrigGCMode) { 380 std::vector<TransformFn> transforms; 381 382 transforms.push_back(independentTransforms); 383 // This depends on previous transformations removing various expressions. 384 transforms.push_back(removeEmptyStatementsAndDeallocFinalize); 385 386 return transforms; 387} 388