Transforms.cpp revision 433db06b614f26dc6829e86d6ff469e2cca7d4f9
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 23using namespace clang; 24using namespace arcmt; 25using namespace trans; 26using llvm::StringRef; 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 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 126bool 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 155namespace { 156 157class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> { 158 ExprSet &Refs; 159public: 160 ReferenceClear(ExprSet &refs) : Refs(refs) { } 161 bool VisitDeclRefExpr(DeclRefExpr *E) { Refs.erase(E); return true; } 162 bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { Refs.erase(E); return true; } 163}; 164 165class ReferenceCollector : public RecursiveASTVisitor<ReferenceCollector> { 166 ValueDecl *Dcl; 167 ExprSet &Refs; 168 169public: 170 ReferenceCollector(ValueDecl *D, ExprSet &refs) 171 : Dcl(D), Refs(refs) { } 172 173 bool VisitDeclRefExpr(DeclRefExpr *E) { 174 if (E->getDecl() == Dcl) 175 Refs.insert(E); 176 return true; 177 } 178 179 bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { 180 if (E->getDecl() == Dcl) 181 Refs.insert(E); 182 return true; 183 } 184}; 185 186class RemovablesCollector : public RecursiveASTVisitor<RemovablesCollector> { 187 ExprSet &Removables; 188 189public: 190 RemovablesCollector(ExprSet &removables) 191 : Removables(removables) { } 192 193 bool shouldWalkTypesOfTypeLocs() const { return false; } 194 195 bool TraverseStmtExpr(StmtExpr *E) { 196 CompoundStmt *S = E->getSubStmt(); 197 for (CompoundStmt::body_iterator 198 I = S->body_begin(), E = S->body_end(); I != E; ++I) { 199 if (I != E - 1) 200 mark(*I); 201 TraverseStmt(*I); 202 } 203 return true; 204 } 205 206 bool VisitCompoundStmt(CompoundStmt *S) { 207 for (CompoundStmt::body_iterator 208 I = S->body_begin(), E = S->body_end(); I != E; ++I) 209 mark(*I); 210 return true; 211 } 212 213 bool VisitIfStmt(IfStmt *S) { 214 mark(S->getThen()); 215 mark(S->getElse()); 216 return true; 217 } 218 219 bool VisitWhileStmt(WhileStmt *S) { 220 mark(S->getBody()); 221 return true; 222 } 223 224 bool VisitDoStmt(DoStmt *S) { 225 mark(S->getBody()); 226 return true; 227 } 228 229 bool VisitForStmt(ForStmt *S) { 230 mark(S->getInit()); 231 mark(S->getInc()); 232 mark(S->getBody()); 233 return true; 234 } 235 236private: 237 void mark(Stmt *S) { 238 if (!S) return; 239 240 while (LabelStmt *Label = dyn_cast<LabelStmt>(S)) 241 S = Label->getSubStmt(); 242 S = S->IgnoreImplicit(); 243 if (Expr *E = dyn_cast<Expr>(S)) 244 Removables.insert(E); 245 } 246}; 247 248} // end anonymous namespace 249 250void trans::clearRefsIn(Stmt *S, ExprSet &refs) { 251 ReferenceClear(refs).TraverseStmt(S); 252} 253 254void trans::collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs) { 255 ReferenceCollector(D, refs).TraverseStmt(S); 256} 257 258void trans::collectRemovables(Stmt *S, ExprSet &exprs) { 259 RemovablesCollector(exprs).TraverseStmt(S); 260} 261 262//===----------------------------------------------------------------------===// 263// getAllTransformations. 264//===----------------------------------------------------------------------===// 265 266static void independentTransforms(MigrationPass &pass) { 267 rewriteAutoreleasePool(pass); 268 rewriteProperties(pass); 269 removeRetainReleaseDealloc(pass); 270 rewriteUnusedInitDelegate(pass); 271 removeZeroOutPropsInDealloc(pass); 272 makeAssignARCSafe(pass); 273 rewriteUnbridgedCasts(pass); 274 rewriteBlockObjCVariable(pass); 275} 276 277std::vector<TransformFn> arcmt::getAllTransformations() { 278 std::vector<TransformFn> transforms; 279 280 transforms.push_back(independentTransforms); 281 // This depends on previous transformations removing various expressions. 282 transforms.push_back(removeEmptyStatementsAndDealloc); 283 284 return transforms; 285} 286