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/AST/ParentMap.h" 16 #include "clang/Analysis/DomainSpecific/CocoaConventions.h" 17 #include "clang/Lex/Lexer.h" 18 #include "clang/Basic/SourceManager.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 using llvm::StringRef; 27 28 //===----------------------------------------------------------------------===// 29 // Helpers. 30 //===----------------------------------------------------------------------===// 31 32 /// \brief True if the class is one that does not support weak. 33 static 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 67 bool 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. 93 SourceLocation trans::findLocationAfterSemi(SourceLocation loc, 94 ASTContext &Ctx) { 95 SourceManager &SM = Ctx.getSourceManager(); 96 if (loc.isMacroID()) { 97 if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOptions())) 98 return SourceLocation(); 99 loc = SM.getInstantiationRange(loc).second; 100 } 101 loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOptions()); 102 103 // Break down the source location. 104 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc); 105 106 // Try to load the file buffer. 107 bool invalidTemp = false; 108 llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); 109 if (invalidTemp) 110 return SourceLocation(); 111 112 const char *tokenBegin = file.data() + locInfo.second; 113 114 // Lex from the start of the given location. 115 Lexer lexer(SM.getLocForStartOfFile(locInfo.first), 116 Ctx.getLangOptions(), 117 file.begin(), tokenBegin, file.end()); 118 Token tok; 119 lexer.LexFromRawLexer(tok); 120 if (tok.isNot(tok::semi)) 121 return SourceLocation(); 122 123 return tok.getLocation().getFileLocWithOffset(1); 124 } 125 126 bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) { 127 if (!E || !E->HasSideEffects(Ctx)) 128 return false; 129 130 E = E->IgnoreParenCasts(); 131 ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E); 132 if (!ME) 133 return true; 134 switch (ME->getMethodFamily()) { 135 case OMF_autorelease: 136 case OMF_dealloc: 137 case OMF_release: 138 case OMF_retain: 139 switch (ME->getReceiverKind()) { 140 case ObjCMessageExpr::SuperInstance: 141 return false; 142 case ObjCMessageExpr::Instance: 143 return hasSideEffects(ME->getInstanceReceiver(), Ctx); 144 default: 145 break; 146 } 147 break; 148 default: 149 break; 150 } 151 152 return true; 153 } 154 155 bool trans::isGlobalVar(Expr *E) { 156 E = E->IgnoreParenCasts(); 157 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) 158 return DRE->getDecl()->getDeclContext()->isFileContext(); 159 if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E)) 160 return isGlobalVar(condOp->getTrueExpr()) && 161 isGlobalVar(condOp->getFalseExpr()); 162 163 return false; 164 } 165 166 namespace { 167 168 class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> { 169 ExprSet &Refs; 170 public: 171 ReferenceClear(ExprSet &refs) : Refs(refs) { } 172 bool VisitDeclRefExpr(DeclRefExpr *E) { Refs.erase(E); return true; } 173 bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { Refs.erase(E); return true; } 174 }; 175 176 class ReferenceCollector : public RecursiveASTVisitor<ReferenceCollector> { 177 ValueDecl *Dcl; 178 ExprSet &Refs; 179 180 public: 181 ReferenceCollector(ValueDecl *D, ExprSet &refs) 182 : Dcl(D), Refs(refs) { } 183 184 bool VisitDeclRefExpr(DeclRefExpr *E) { 185 if (E->getDecl() == Dcl) 186 Refs.insert(E); 187 return true; 188 } 189 190 bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { 191 if (E->getDecl() == Dcl) 192 Refs.insert(E); 193 return true; 194 } 195 }; 196 197 class RemovablesCollector : public RecursiveASTVisitor<RemovablesCollector> { 198 ExprSet &Removables; 199 200 public: 201 RemovablesCollector(ExprSet &removables) 202 : Removables(removables) { } 203 204 bool shouldWalkTypesOfTypeLocs() const { return false; } 205 206 bool TraverseStmtExpr(StmtExpr *E) { 207 CompoundStmt *S = E->getSubStmt(); 208 for (CompoundStmt::body_iterator 209 I = S->body_begin(), E = S->body_end(); I != E; ++I) { 210 if (I != E - 1) 211 mark(*I); 212 TraverseStmt(*I); 213 } 214 return true; 215 } 216 217 bool VisitCompoundStmt(CompoundStmt *S) { 218 for (CompoundStmt::body_iterator 219 I = S->body_begin(), E = S->body_end(); I != E; ++I) 220 mark(*I); 221 return true; 222 } 223 224 bool VisitIfStmt(IfStmt *S) { 225 mark(S->getThen()); 226 mark(S->getElse()); 227 return true; 228 } 229 230 bool VisitWhileStmt(WhileStmt *S) { 231 mark(S->getBody()); 232 return true; 233 } 234 235 bool VisitDoStmt(DoStmt *S) { 236 mark(S->getBody()); 237 return true; 238 } 239 240 bool VisitForStmt(ForStmt *S) { 241 mark(S->getInit()); 242 mark(S->getInc()); 243 mark(S->getBody()); 244 return true; 245 } 246 247 private: 248 void mark(Stmt *S) { 249 if (!S) return; 250 251 while (LabelStmt *Label = dyn_cast<LabelStmt>(S)) 252 S = Label->getSubStmt(); 253 S = S->IgnoreImplicit(); 254 if (Expr *E = dyn_cast<Expr>(S)) 255 Removables.insert(E); 256 } 257 }; 258 259 } // end anonymous namespace 260 261 void trans::clearRefsIn(Stmt *S, ExprSet &refs) { 262 ReferenceClear(refs).TraverseStmt(S); 263 } 264 265 void trans::collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs) { 266 ReferenceCollector(D, refs).TraverseStmt(S); 267 } 268 269 void trans::collectRemovables(Stmt *S, ExprSet &exprs) { 270 RemovablesCollector(exprs).TraverseStmt(S); 271 } 272 273 //===----------------------------------------------------------------------===// 274 // getAllTransformations. 275 //===----------------------------------------------------------------------===// 276 277 static void independentTransforms(MigrationPass &pass) { 278 rewriteAutoreleasePool(pass); 279 rewriteProperties(pass); 280 removeRetainReleaseDealloc(pass); 281 rewriteUnusedInitDelegate(pass); 282 removeZeroOutPropsInDealloc(pass); 283 makeAssignARCSafe(pass); 284 rewriteUnbridgedCasts(pass); 285 rewriteBlockObjCVariable(pass); 286 checkAPIUses(pass); 287 } 288 289 std::vector<TransformFn> arcmt::getAllTransformations() { 290 std::vector<TransformFn> transforms; 291 292 transforms.push_back(independentTransforms); 293 // This depends on previous transformations removing various expressions. 294 transforms.push_back(removeEmptyStatementsAndDealloc); 295 296 return transforms; 297 } 298