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 27 //===----------------------------------------------------------------------===// 28 // Helpers. 29 //===----------------------------------------------------------------------===// 30 31 /// \brief True if the class is one that does not support weak. 32 static bool isClassInWeakBlacklist(ObjCInterfaceDecl *cls) { 33 if (!cls) 34 return false; 35 36 bool inList = llvm::StringSwitch<bool>(cls->getName()) 37 .Case("NSColorSpace", true) 38 .Case("NSFont", true) 39 .Case("NSFontPanel", true) 40 .Case("NSImage", true) 41 .Case("NSLazyBrowserCell", true) 42 .Case("NSWindow", true) 43 .Case("NSWindowController", true) 44 .Case("NSMenuView", true) 45 .Case("NSPersistentUIWindowInfo", true) 46 .Case("NSTableCellView", true) 47 .Case("NSATSTypeSetter", true) 48 .Case("NSATSGlyphStorage", true) 49 .Case("NSLineFragmentRenderingContext", true) 50 .Case("NSAttributeDictionary", true) 51 .Case("NSParagraphStyle", true) 52 .Case("NSTextTab", true) 53 .Case("NSSimpleHorizontalTypesetter", true) 54 .Case("_NSCachedAttributedString", true) 55 .Case("NSStringDrawingTextStorage", true) 56 .Case("NSTextView", true) 57 .Case("NSSubTextStorage", true) 58 .Default(false); 59 60 if (inList) 61 return true; 62 63 return isClassInWeakBlacklist(cls->getSuperClass()); 64 } 65 66 bool trans::canApplyWeak(ASTContext &Ctx, QualType type) { 67 if (!Ctx.getLangOptions().ObjCRuntimeHasWeak) 68 return false; 69 70 QualType T = type; 71 while (const PointerType *ptr = T->getAs<PointerType>()) 72 T = ptr->getPointeeType(); 73 if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) { 74 ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl(); 75 if (!Class || Class->getName() == "NSObject") 76 return false; // id/NSObject is not safe for weak. 77 if (Class->isForwardDecl()) 78 return false; // forward classes are not verifiable, therefore not safe. 79 if (Class->isArcWeakrefUnavailable()) 80 return false; 81 if (isClassInWeakBlacklist(Class)) 82 return false; 83 } 84 85 return true; 86 } 87 88 /// \brief 'Loc' is the end of a statement range. This returns the location 89 /// immediately after the semicolon following the statement. 90 /// If no semicolon is found or the location is inside a macro, the returned 91 /// source location will be invalid. 92 SourceLocation trans::findLocationAfterSemi(SourceLocation loc, 93 ASTContext &Ctx) { 94 SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx); 95 if (SemiLoc.isInvalid()) 96 return SourceLocation(); 97 return SemiLoc.getLocWithOffset(1); 98 } 99 100 /// \brief \arg Loc is the end of a statement range. This returns the location 101 /// of the semicolon following the statement. 102 /// If no semicolon is found or the location is inside a macro, the returned 103 /// source location will be invalid. 104 SourceLocation trans::findSemiAfterLocation(SourceLocation loc, 105 ASTContext &Ctx) { 106 SourceManager &SM = Ctx.getSourceManager(); 107 if (loc.isMacroID()) { 108 if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOptions())) 109 return SourceLocation(); 110 loc = SM.getExpansionRange(loc).second; 111 } 112 loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOptions()); 113 114 // Break down the source location. 115 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc); 116 117 // Try to load the file buffer. 118 bool invalidTemp = false; 119 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); 120 if (invalidTemp) 121 return SourceLocation(); 122 123 const char *tokenBegin = file.data() + locInfo.second; 124 125 // Lex from the start of the given location. 126 Lexer lexer(SM.getLocForStartOfFile(locInfo.first), 127 Ctx.getLangOptions(), 128 file.begin(), tokenBegin, file.end()); 129 Token tok; 130 lexer.LexFromRawLexer(tok); 131 if (tok.isNot(tok::semi)) 132 return SourceLocation(); 133 134 return tok.getLocation(); 135 } 136 137 bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) { 138 if (!E || !E->HasSideEffects(Ctx)) 139 return false; 140 141 E = E->IgnoreParenCasts(); 142 ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E); 143 if (!ME) 144 return true; 145 switch (ME->getMethodFamily()) { 146 case OMF_autorelease: 147 case OMF_dealloc: 148 case OMF_release: 149 case OMF_retain: 150 switch (ME->getReceiverKind()) { 151 case ObjCMessageExpr::SuperInstance: 152 return false; 153 case ObjCMessageExpr::Instance: 154 return hasSideEffects(ME->getInstanceReceiver(), Ctx); 155 default: 156 break; 157 } 158 break; 159 default: 160 break; 161 } 162 163 return true; 164 } 165 166 bool trans::isGlobalVar(Expr *E) { 167 E = E->IgnoreParenCasts(); 168 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) 169 return DRE->getDecl()->getDeclContext()->isFileContext() && 170 DRE->getDecl()->getLinkage() == ExternalLinkage; 171 if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E)) 172 return isGlobalVar(condOp->getTrueExpr()) && 173 isGlobalVar(condOp->getFalseExpr()); 174 175 return false; 176 } 177 178 StringRef trans::getNilString(ASTContext &Ctx) { 179 if (Ctx.Idents.get("nil").hasMacroDefinition()) 180 return "nil"; 181 else 182 return "0"; 183 } 184 185 namespace { 186 187 class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> { 188 ExprSet &Refs; 189 public: 190 ReferenceClear(ExprSet &refs) : Refs(refs) { } 191 bool VisitDeclRefExpr(DeclRefExpr *E) { Refs.erase(E); return true; } 192 bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { Refs.erase(E); return true; } 193 }; 194 195 class ReferenceCollector : public RecursiveASTVisitor<ReferenceCollector> { 196 ValueDecl *Dcl; 197 ExprSet &Refs; 198 199 public: 200 ReferenceCollector(ValueDecl *D, ExprSet &refs) 201 : Dcl(D), Refs(refs) { } 202 203 bool VisitDeclRefExpr(DeclRefExpr *E) { 204 if (E->getDecl() == Dcl) 205 Refs.insert(E); 206 return true; 207 } 208 209 bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { 210 if (E->getDecl() == Dcl) 211 Refs.insert(E); 212 return true; 213 } 214 }; 215 216 class RemovablesCollector : public RecursiveASTVisitor<RemovablesCollector> { 217 ExprSet &Removables; 218 219 public: 220 RemovablesCollector(ExprSet &removables) 221 : Removables(removables) { } 222 223 bool shouldWalkTypesOfTypeLocs() const { return false; } 224 225 bool TraverseStmtExpr(StmtExpr *E) { 226 CompoundStmt *S = E->getSubStmt(); 227 for (CompoundStmt::body_iterator 228 I = S->body_begin(), E = S->body_end(); I != E; ++I) { 229 if (I != E - 1) 230 mark(*I); 231 TraverseStmt(*I); 232 } 233 return true; 234 } 235 236 bool VisitCompoundStmt(CompoundStmt *S) { 237 for (CompoundStmt::body_iterator 238 I = S->body_begin(), E = S->body_end(); I != E; ++I) 239 mark(*I); 240 return true; 241 } 242 243 bool VisitIfStmt(IfStmt *S) { 244 mark(S->getThen()); 245 mark(S->getElse()); 246 return true; 247 } 248 249 bool VisitWhileStmt(WhileStmt *S) { 250 mark(S->getBody()); 251 return true; 252 } 253 254 bool VisitDoStmt(DoStmt *S) { 255 mark(S->getBody()); 256 return true; 257 } 258 259 bool VisitForStmt(ForStmt *S) { 260 mark(S->getInit()); 261 mark(S->getInc()); 262 mark(S->getBody()); 263 return true; 264 } 265 266 private: 267 void mark(Stmt *S) { 268 if (!S) return; 269 270 while (LabelStmt *Label = dyn_cast<LabelStmt>(S)) 271 S = Label->getSubStmt(); 272 S = S->IgnoreImplicit(); 273 if (Expr *E = dyn_cast<Expr>(S)) 274 Removables.insert(E); 275 } 276 }; 277 278 } // end anonymous namespace 279 280 void trans::clearRefsIn(Stmt *S, ExprSet &refs) { 281 ReferenceClear(refs).TraverseStmt(S); 282 } 283 284 void trans::collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs) { 285 ReferenceCollector(D, refs).TraverseStmt(S); 286 } 287 288 void trans::collectRemovables(Stmt *S, ExprSet &exprs) { 289 RemovablesCollector(exprs).TraverseStmt(S); 290 } 291 292 //===----------------------------------------------------------------------===// 293 // getAllTransformations. 294 //===----------------------------------------------------------------------===// 295 296 static void independentTransforms(MigrationPass &pass) { 297 rewriteAutoreleasePool(pass); 298 rewriteProperties(pass); 299 removeRetainReleaseDealloc(pass); 300 rewriteUnusedInitDelegate(pass); 301 removeZeroOutPropsInDealloc(pass); 302 makeAssignARCSafe(pass); 303 rewriteUnbridgedCasts(pass); 304 rewriteBlockObjCVariable(pass); 305 checkAPIUses(pass); 306 } 307 308 std::vector<TransformFn> arcmt::getAllTransformations() { 309 std::vector<TransformFn> transforms; 310 311 transforms.push_back(independentTransforms); 312 // This depends on previous transformations removing various expressions. 313 transforms.push_back(removeEmptyStatementsAndDealloc); 314 315 return transforms; 316 } 317