clang API Documentation

Transforms.cpp
Go to the documentation of this file.
00001 //===--- Tranforms.cpp - Tranformations to ARC mode -----------------------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 
00010 #include "Transforms.h"
00011 #include "Internals.h"
00012 #include "clang/Sema/SemaDiagnostic.h"
00013 #include "clang/AST/RecursiveASTVisitor.h"
00014 #include "clang/AST/StmtVisitor.h"
00015 #include "clang/Lex/Lexer.h"
00016 #include "clang/Basic/SourceManager.h"
00017 #include "llvm/ADT/StringSwitch.h"
00018 #include "llvm/ADT/DenseSet.h"
00019 #include <map>
00020 
00021 using namespace clang;
00022 using namespace arcmt;
00023 using namespace trans;
00024 
00025 ASTTraverser::~ASTTraverser() { }
00026 
00027 //===----------------------------------------------------------------------===//
00028 // Helpers.
00029 //===----------------------------------------------------------------------===//
00030 
00031 bool trans::canApplyWeak(ASTContext &Ctx, QualType type,
00032                          bool AllowOnUnknownClass) {
00033   if (!Ctx.getLangOpts().ObjCRuntimeHasWeak)
00034     return false;
00035 
00036   QualType T = type;
00037   if (T.isNull())
00038     return false;
00039 
00040   // iOS is always safe to use 'weak'.
00041   if (Ctx.getTargetInfo().getTriple().getOS() == llvm::Triple::IOS)
00042     AllowOnUnknownClass = true;
00043 
00044   while (const PointerType *ptr = T->getAs<PointerType>())
00045     T = ptr->getPointeeType();
00046   if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) {
00047     ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl();
00048     if (!AllowOnUnknownClass && (!Class || Class->getName() == "NSObject"))
00049       return false; // id/NSObject is not safe for weak.
00050     if (!AllowOnUnknownClass && !Class->hasDefinition())
00051       return false; // forward classes are not verifiable, therefore not safe.
00052     if (Class->isArcWeakrefUnavailable())
00053       return false;
00054   }
00055 
00056   return true;
00057 }
00058 
00059 /// \brief 'Loc' is the end of a statement range. This returns the location
00060 /// immediately after the semicolon following the statement.
00061 /// If no semicolon is found or the location is inside a macro, the returned
00062 /// source location will be invalid.
00063 SourceLocation trans::findLocationAfterSemi(SourceLocation loc,
00064                                             ASTContext &Ctx) {
00065   SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx);
00066   if (SemiLoc.isInvalid())
00067     return SourceLocation();
00068   return SemiLoc.getLocWithOffset(1);
00069 }
00070 
00071 /// \brief \arg Loc is the end of a statement range. This returns the location
00072 /// of the semicolon following the statement.
00073 /// If no semicolon is found or the location is inside a macro, the returned
00074 /// source location will be invalid.
00075 SourceLocation trans::findSemiAfterLocation(SourceLocation loc,
00076                                             ASTContext &Ctx) {
00077   SourceManager &SM = Ctx.getSourceManager();
00078   if (loc.isMacroID()) {
00079     if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOpts(), &loc))
00080       return SourceLocation();
00081   }
00082   loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOpts());
00083 
00084   // Break down the source location.
00085   std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
00086 
00087   // Try to load the file buffer.
00088   bool invalidTemp = false;
00089   StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
00090   if (invalidTemp)
00091     return SourceLocation();
00092 
00093   const char *tokenBegin = file.data() + locInfo.second;
00094 
00095   // Lex from the start of the given location.
00096   Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
00097               Ctx.getLangOpts(),
00098               file.begin(), tokenBegin, file.end());
00099   Token tok;
00100   lexer.LexFromRawLexer(tok);
00101   if (tok.isNot(tok::semi))
00102     return SourceLocation();
00103 
00104   return tok.getLocation();
00105 }
00106 
00107 bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) {
00108   if (!E || !E->HasSideEffects(Ctx))
00109     return false;
00110 
00111   E = E->IgnoreParenCasts();
00112   ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E);
00113   if (!ME)
00114     return true;
00115   switch (ME->getMethodFamily()) {
00116   case OMF_autorelease:
00117   case OMF_dealloc:
00118   case OMF_release:
00119   case OMF_retain:
00120     switch (ME->getReceiverKind()) {
00121     case ObjCMessageExpr::SuperInstance:
00122       return false;
00123     case ObjCMessageExpr::Instance:
00124       return hasSideEffects(ME->getInstanceReceiver(), Ctx);
00125     default:
00126       break;
00127     }
00128     break;
00129   default:
00130     break;
00131   }
00132 
00133   return true;
00134 }
00135 
00136 bool trans::isGlobalVar(Expr *E) {
00137   E = E->IgnoreParenCasts();
00138   if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
00139     return DRE->getDecl()->getDeclContext()->isFileContext() &&
00140            DRE->getDecl()->getLinkage() == ExternalLinkage;
00141   if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E))
00142     return isGlobalVar(condOp->getTrueExpr()) &&
00143            isGlobalVar(condOp->getFalseExpr());
00144 
00145   return false;  
00146 }
00147 
00148 StringRef trans::getNilString(ASTContext &Ctx) {
00149   if (Ctx.Idents.get("nil").hasMacroDefinition())
00150     return "nil";
00151   else
00152     return "0";
00153 }
00154 
00155 namespace {
00156 
00157 class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> {
00158   ExprSet &Refs;
00159 public:
00160   ReferenceClear(ExprSet &refs) : Refs(refs) { }
00161   bool VisitDeclRefExpr(DeclRefExpr *E) { Refs.erase(E); return true; }
00162 };
00163 
00164 class ReferenceCollector : public RecursiveASTVisitor<ReferenceCollector> {
00165   ValueDecl *Dcl;
00166   ExprSet &Refs;
00167 
00168 public:
00169   ReferenceCollector(ValueDecl *D, ExprSet &refs)
00170     : Dcl(D), Refs(refs) { }
00171 
00172   bool VisitDeclRefExpr(DeclRefExpr *E) {
00173     if (E->getDecl() == Dcl)
00174       Refs.insert(E);
00175     return true;
00176   }
00177 };
00178 
00179 class RemovablesCollector : public RecursiveASTVisitor<RemovablesCollector> {
00180   ExprSet &Removables;
00181 
00182 public:
00183   RemovablesCollector(ExprSet &removables)
00184   : Removables(removables) { }
00185   
00186   bool shouldWalkTypesOfTypeLocs() const { return false; }
00187   
00188   bool TraverseStmtExpr(StmtExpr *E) {
00189     CompoundStmt *S = E->getSubStmt();
00190     for (CompoundStmt::body_iterator
00191         I = S->body_begin(), E = S->body_end(); I != E; ++I) {
00192       if (I != E - 1)
00193         mark(*I);
00194       TraverseStmt(*I);
00195     }
00196     return true;
00197   }
00198   
00199   bool VisitCompoundStmt(CompoundStmt *S) {
00200     for (CompoundStmt::body_iterator
00201         I = S->body_begin(), E = S->body_end(); I != E; ++I)
00202       mark(*I);
00203     return true;
00204   }
00205   
00206   bool VisitIfStmt(IfStmt *S) {
00207     mark(S->getThen());
00208     mark(S->getElse());
00209     return true;
00210   }
00211   
00212   bool VisitWhileStmt(WhileStmt *S) {
00213     mark(S->getBody());
00214     return true;
00215   }
00216   
00217   bool VisitDoStmt(DoStmt *S) {
00218     mark(S->getBody());
00219     return true;
00220   }
00221   
00222   bool VisitForStmt(ForStmt *S) {
00223     mark(S->getInit());
00224     mark(S->getInc());
00225     mark(S->getBody());
00226     return true;
00227   }
00228   
00229 private:
00230   void mark(Stmt *S) {
00231     if (!S) return;
00232     
00233     while (LabelStmt *Label = dyn_cast<LabelStmt>(S))
00234       S = Label->getSubStmt();
00235     S = S->IgnoreImplicit();
00236     if (Expr *E = dyn_cast<Expr>(S))
00237       Removables.insert(E);
00238   }
00239 };
00240 
00241 } // end anonymous namespace
00242 
00243 void trans::clearRefsIn(Stmt *S, ExprSet &refs) {
00244   ReferenceClear(refs).TraverseStmt(S);
00245 }
00246 
00247 void trans::collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs) {
00248   ReferenceCollector(D, refs).TraverseStmt(S);
00249 }
00250 
00251 void trans::collectRemovables(Stmt *S, ExprSet &exprs) {
00252   RemovablesCollector(exprs).TraverseStmt(S);
00253 }
00254 
00255 //===----------------------------------------------------------------------===//
00256 // MigrationContext
00257 //===----------------------------------------------------------------------===//
00258 
00259 namespace {
00260 
00261 class ASTTransform : public RecursiveASTVisitor<ASTTransform> {
00262   MigrationContext &MigrateCtx;
00263   typedef RecursiveASTVisitor<ASTTransform> base;
00264 
00265 public:
00266   ASTTransform(MigrationContext &MigrateCtx) : MigrateCtx(MigrateCtx) { }
00267 
00268   bool shouldWalkTypesOfTypeLocs() const { return false; }
00269 
00270   bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) {
00271     ObjCImplementationContext ImplCtx(MigrateCtx, D);
00272     for (MigrationContext::traverser_iterator
00273            I = MigrateCtx.traversers_begin(),
00274            E = MigrateCtx.traversers_end(); I != E; ++I)
00275       (*I)->traverseObjCImplementation(ImplCtx);
00276 
00277     return base::TraverseObjCImplementationDecl(D);
00278   }
00279 
00280   bool TraverseStmt(Stmt *rootS) {
00281     if (!rootS)
00282       return true;
00283 
00284     BodyContext BodyCtx(MigrateCtx, rootS);
00285     for (MigrationContext::traverser_iterator
00286            I = MigrateCtx.traversers_begin(),
00287            E = MigrateCtx.traversers_end(); I != E; ++I)
00288       (*I)->traverseBody(BodyCtx);
00289 
00290     return true;
00291   }
00292 };
00293 
00294 }
00295 
00296 MigrationContext::~MigrationContext() {
00297   for (traverser_iterator
00298          I = traversers_begin(), E = traversers_end(); I != E; ++I)
00299     delete *I;
00300 }
00301 
00302 bool MigrationContext::isGCOwnedNonObjC(QualType T) {
00303   while (!T.isNull()) {
00304     if (const AttributedType *AttrT = T->getAs<AttributedType>()) {
00305       if (AttrT->getAttrKind() == AttributedType::attr_objc_ownership)
00306         return !AttrT->getModifiedType()->isObjCRetainableType();
00307     }
00308 
00309     if (T->isArrayType())
00310       T = Pass.Ctx.getBaseElementType(T);
00311     else if (const PointerType *PT = T->getAs<PointerType>())
00312       T = PT->getPointeeType();
00313     else if (const ReferenceType *RT = T->getAs<ReferenceType>())
00314       T = RT->getPointeeType();
00315     else
00316       break;
00317   }
00318 
00319   return false;
00320 }
00321 
00322 bool MigrationContext::rewritePropertyAttribute(StringRef fromAttr,
00323                                                 StringRef toAttr,
00324                                                 SourceLocation atLoc) {
00325   if (atLoc.isMacroID())
00326     return false;
00327 
00328   SourceManager &SM = Pass.Ctx.getSourceManager();
00329 
00330   // Break down the source location.
00331   std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
00332 
00333   // Try to load the file buffer.
00334   bool invalidTemp = false;
00335   StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
00336   if (invalidTemp)
00337     return false;
00338 
00339   const char *tokenBegin = file.data() + locInfo.second;
00340 
00341   // Lex from the start of the given location.
00342   Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
00343               Pass.Ctx.getLangOpts(),
00344               file.begin(), tokenBegin, file.end());
00345   Token tok;
00346   lexer.LexFromRawLexer(tok);
00347   if (tok.isNot(tok::at)) return false;
00348   lexer.LexFromRawLexer(tok);
00349   if (tok.isNot(tok::raw_identifier)) return false;
00350   if (StringRef(tok.getRawIdentifierData(), tok.getLength())
00351         != "property")
00352     return false;
00353   lexer.LexFromRawLexer(tok);
00354   if (tok.isNot(tok::l_paren)) return false;
00355   
00356   Token BeforeTok = tok;
00357   Token AfterTok;
00358   AfterTok.startToken();
00359   SourceLocation AttrLoc;
00360   
00361   lexer.LexFromRawLexer(tok);
00362   if (tok.is(tok::r_paren))
00363     return false;
00364 
00365   while (1) {
00366     if (tok.isNot(tok::raw_identifier)) return false;
00367     StringRef ident(tok.getRawIdentifierData(), tok.getLength());
00368     if (ident == fromAttr) {
00369       if (!toAttr.empty()) {
00370         Pass.TA.replaceText(tok.getLocation(), fromAttr, toAttr);
00371         return true;
00372       }
00373       // We want to remove the attribute.
00374       AttrLoc = tok.getLocation();
00375     }
00376 
00377     do {
00378       lexer.LexFromRawLexer(tok);
00379       if (AttrLoc.isValid() && AfterTok.is(tok::unknown))
00380         AfterTok = tok;
00381     } while (tok.isNot(tok::comma) && tok.isNot(tok::r_paren));
00382     if (tok.is(tok::r_paren))
00383       break;
00384     if (AttrLoc.isInvalid())
00385       BeforeTok = tok;
00386     lexer.LexFromRawLexer(tok);
00387   }
00388 
00389   if (toAttr.empty() && AttrLoc.isValid() && AfterTok.isNot(tok::unknown)) {
00390     // We want to remove the attribute.
00391     if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::r_paren)) {
00392       Pass.TA.remove(SourceRange(BeforeTok.getLocation(),
00393                                  AfterTok.getLocation()));
00394     } else if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::comma)) {
00395       Pass.TA.remove(SourceRange(AttrLoc, AfterTok.getLocation()));
00396     } else {
00397       Pass.TA.remove(SourceRange(BeforeTok.getLocation(), AttrLoc));
00398     }
00399 
00400     return true;
00401   }
00402   
00403   return false;
00404 }
00405 
00406 bool MigrationContext::addPropertyAttribute(StringRef attr,
00407                                             SourceLocation atLoc) {
00408   if (atLoc.isMacroID())
00409     return false;
00410 
00411   SourceManager &SM = Pass.Ctx.getSourceManager();
00412 
00413   // Break down the source location.
00414   std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
00415 
00416   // Try to load the file buffer.
00417   bool invalidTemp = false;
00418   StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
00419   if (invalidTemp)
00420     return false;
00421 
00422   const char *tokenBegin = file.data() + locInfo.second;
00423 
00424   // Lex from the start of the given location.
00425   Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
00426               Pass.Ctx.getLangOpts(),
00427               file.begin(), tokenBegin, file.end());
00428   Token tok;
00429   lexer.LexFromRawLexer(tok);
00430   if (tok.isNot(tok::at)) return false;
00431   lexer.LexFromRawLexer(tok);
00432   if (tok.isNot(tok::raw_identifier)) return false;
00433   if (StringRef(tok.getRawIdentifierData(), tok.getLength())
00434         != "property")
00435     return false;
00436   lexer.LexFromRawLexer(tok);
00437 
00438   if (tok.isNot(tok::l_paren)) {
00439     Pass.TA.insert(tok.getLocation(), std::string("(") + attr.str() + ") ");
00440     return true;
00441   }
00442   
00443   lexer.LexFromRawLexer(tok);
00444   if (tok.is(tok::r_paren)) {
00445     Pass.TA.insert(tok.getLocation(), attr);
00446     return true;
00447   }
00448 
00449   if (tok.isNot(tok::raw_identifier)) return false;
00450 
00451   Pass.TA.insert(tok.getLocation(), std::string(attr) + ", ");
00452   return true;
00453 }
00454 
00455 void MigrationContext::traverse(TranslationUnitDecl *TU) {
00456   for (traverser_iterator
00457          I = traversers_begin(), E = traversers_end(); I != E; ++I)
00458     (*I)->traverseTU(*this);
00459 
00460   ASTTransform(*this).TraverseDecl(TU);
00461 }
00462 
00463 static void GCRewriteFinalize(MigrationPass &pass) {
00464   ASTContext &Ctx = pass.Ctx;
00465   TransformActions &TA = pass.TA;
00466   DeclContext *DC = Ctx.getTranslationUnitDecl();
00467   Selector FinalizeSel =
00468    Ctx.Selectors.getNullarySelector(&pass.Ctx.Idents.get("finalize"));
00469   
00470   typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl>
00471   impl_iterator;
00472   for (impl_iterator I = impl_iterator(DC->decls_begin()),
00473        E = impl_iterator(DC->decls_end()); I != E; ++I) {
00474     for (ObjCImplementationDecl::instmeth_iterator
00475          MI = I->instmeth_begin(),
00476          ME = I->instmeth_end(); MI != ME; ++MI) {
00477       ObjCMethodDecl *MD = *MI;
00478       if (!MD->hasBody())
00479         continue;
00480       
00481       if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) {
00482         ObjCMethodDecl *FinalizeM = MD;
00483         Transaction Trans(TA);
00484         TA.insert(FinalizeM->getSourceRange().getBegin(), 
00485                   "#if !__has_feature(objc_arc)\n");
00486         CharSourceRange::getTokenRange(FinalizeM->getSourceRange());
00487         const SourceManager &SM = pass.Ctx.getSourceManager();
00488         const LangOptions &LangOpts = pass.Ctx.getLangOpts();
00489         bool Invalid;
00490         std::string str = "\n#endif\n";
00491         str += Lexer::getSourceText(
00492                   CharSourceRange::getTokenRange(FinalizeM->getSourceRange()), 
00493                                     SM, LangOpts, &Invalid);
00494         TA.insertAfterToken(FinalizeM->getSourceRange().getEnd(), str);
00495         
00496         break;
00497       }
00498     }
00499   }
00500 }
00501 
00502 //===----------------------------------------------------------------------===//
00503 // getAllTransformations.
00504 //===----------------------------------------------------------------------===//
00505 
00506 static void traverseAST(MigrationPass &pass) {
00507   MigrationContext MigrateCtx(pass);
00508 
00509   if (pass.isGCMigration()) {
00510     MigrateCtx.addTraverser(new GCCollectableCallsTraverser);
00511     MigrateCtx.addTraverser(new GCAttrsTraverser());
00512   }
00513   MigrateCtx.addTraverser(new PropertyRewriteTraverser());
00514   MigrateCtx.addTraverser(new BlockObjCVariableTraverser());
00515 
00516   MigrateCtx.traverse(pass.Ctx.getTranslationUnitDecl());
00517 }
00518 
00519 static void independentTransforms(MigrationPass &pass) {
00520   rewriteAutoreleasePool(pass);
00521   removeRetainReleaseDeallocFinalize(pass);
00522   rewriteUnusedInitDelegate(pass);
00523   removeZeroOutPropsInDeallocFinalize(pass);
00524   makeAssignARCSafe(pass);
00525   rewriteUnbridgedCasts(pass);
00526   checkAPIUses(pass);
00527   traverseAST(pass);
00528 }
00529 
00530 std::vector<TransformFn> arcmt::getAllTransformations(
00531                                                LangOptions::GCMode OrigGCMode,
00532                                                bool NoFinalizeRemoval) {
00533   std::vector<TransformFn> transforms;
00534 
00535   if (OrigGCMode ==  LangOptions::GCOnly && NoFinalizeRemoval)
00536     transforms.push_back(GCRewriteFinalize);
00537   transforms.push_back(independentTransforms);
00538   // This depends on previous transformations removing various expressions.
00539   transforms.push_back(removeEmptyStatementsAndDeallocFinalize);
00540 
00541   return transforms;
00542 }