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 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