Home | History | Annotate | Download | only in ARCMigrate
      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