Transforms.cpp revision ea2224d7078c4d31ad32adbaba4bdc2d85a3d609
1//===--- Transforms.cpp - Transformations 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/AST/ASTContext.h"
13#include "clang/AST/RecursiveASTVisitor.h"
14#include "clang/AST/StmtVisitor.h"
15#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
16#include "clang/Basic/SourceManager.h"
17#include "clang/Basic/TargetInfo.h"
18#include "clang/Lex/Lexer.h"
19#include "clang/Sema/Sema.h"
20#include "clang/Sema/SemaDiagnostic.h"
21#include "llvm/ADT/DenseSet.h"
22#include "llvm/ADT/StringSwitch.h"
23#include <map>
24
25using namespace clang;
26using namespace arcmt;
27using namespace trans;
28
29ASTTraverser::~ASTTraverser() { }
30
31bool MigrationPass::CFBridgingFunctionsDefined() {
32  if (!EnableCFBridgeFns.hasValue())
33    EnableCFBridgeFns = SemaRef.isKnownName("CFBridgingRetain") &&
34                        SemaRef.isKnownName("CFBridgingRelease");
35  return *EnableCFBridgeFns;
36}
37
38//===----------------------------------------------------------------------===//
39// Helpers.
40//===----------------------------------------------------------------------===//
41
42bool trans::canApplyWeak(ASTContext &Ctx, QualType type,
43                         bool AllowOnUnknownClass) {
44  if (!Ctx.getLangOpts().ObjCARCWeak)
45    return false;
46
47  QualType T = type;
48  if (T.isNull())
49    return false;
50
51  // iOS is always safe to use 'weak'.
52  if (Ctx.getTargetInfo().getTriple().getOS() == llvm::Triple::IOS)
53    AllowOnUnknownClass = true;
54
55  while (const PointerType *ptr = T->getAs<PointerType>())
56    T = ptr->getPointeeType();
57  if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) {
58    ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl();
59    if (!AllowOnUnknownClass && (!Class || Class->getName() == "NSObject"))
60      return false; // id/NSObject is not safe for weak.
61    if (!AllowOnUnknownClass && !Class->hasDefinition())
62      return false; // forward classes are not verifiable, therefore not safe.
63    if (Class && Class->isArcWeakrefUnavailable())
64      return false;
65  }
66
67  return true;
68}
69
70bool trans::isPlusOneAssign(const BinaryOperator *E) {
71  if (E->getOpcode() != BO_Assign)
72    return false;
73
74  if (const ObjCMessageExpr *
75        ME = dyn_cast<ObjCMessageExpr>(E->getRHS()->IgnoreParenCasts()))
76    if (ME->getMethodFamily() == OMF_retain)
77      return true;
78
79  if (const CallExpr *
80        callE = dyn_cast<CallExpr>(E->getRHS()->IgnoreParenCasts())) {
81    if (const FunctionDecl *FD = callE->getDirectCallee()) {
82      if (FD->getAttr<CFReturnsRetainedAttr>())
83        return true;
84
85      if (FD->isGlobal() &&
86          FD->getIdentifier() &&
87          FD->getParent()->isTranslationUnit() &&
88          FD->getLinkage() == ExternalLinkage &&
89          ento::cocoa::isRefType(callE->getType(), "CF",
90                                 FD->getIdentifier()->getName())) {
91        StringRef fname = FD->getIdentifier()->getName();
92        if (fname.endswith("Retain") ||
93            fname.find("Create") != StringRef::npos ||
94            fname.find("Copy") != StringRef::npos) {
95          return true;
96        }
97      }
98    }
99  }
100
101  const ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getRHS());
102  while (implCE && implCE->getCastKind() ==  CK_BitCast)
103    implCE = dyn_cast<ImplicitCastExpr>(implCE->getSubExpr());
104
105  if (implCE && implCE->getCastKind() == CK_ARCConsumeObject)
106    return true;
107
108  return false;
109}
110
111/// \brief 'Loc' is the end of a statement range. This returns the location
112/// immediately after the semicolon following the statement.
113/// If no semicolon is found or the location is inside a macro, the returned
114/// source location will be invalid.
115SourceLocation trans::findLocationAfterSemi(SourceLocation loc,
116                                            ASTContext &Ctx) {
117  SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx);
118  if (SemiLoc.isInvalid())
119    return SourceLocation();
120  return SemiLoc.getLocWithOffset(1);
121}
122
123/// \brief \arg Loc is the end of a statement range. This returns the location
124/// of the semicolon following the statement.
125/// If no semicolon is found or the location is inside a macro, the returned
126/// source location will be invalid.
127SourceLocation trans::findSemiAfterLocation(SourceLocation loc,
128                                            ASTContext &Ctx) {
129  SourceManager &SM = Ctx.getSourceManager();
130  if (loc.isMacroID()) {
131    if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOpts(), &loc))
132      return SourceLocation();
133  }
134  loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOpts());
135
136  // Break down the source location.
137  std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
138
139  // Try to load the file buffer.
140  bool invalidTemp = false;
141  StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
142  if (invalidTemp)
143    return SourceLocation();
144
145  const char *tokenBegin = file.data() + locInfo.second;
146
147  // Lex from the start of the given location.
148  Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
149              Ctx.getLangOpts(),
150              file.begin(), tokenBegin, file.end());
151  Token tok;
152  lexer.LexFromRawLexer(tok);
153  if (tok.isNot(tok::semi))
154    return SourceLocation();
155
156  return tok.getLocation();
157}
158
159bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) {
160  if (!E || !E->HasSideEffects(Ctx))
161    return false;
162
163  E = E->IgnoreParenCasts();
164  ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E);
165  if (!ME)
166    return true;
167  switch (ME->getMethodFamily()) {
168  case OMF_autorelease:
169  case OMF_dealloc:
170  case OMF_release:
171  case OMF_retain:
172    switch (ME->getReceiverKind()) {
173    case ObjCMessageExpr::SuperInstance:
174      return false;
175    case ObjCMessageExpr::Instance:
176      return hasSideEffects(ME->getInstanceReceiver(), Ctx);
177    default:
178      break;
179    }
180    break;
181  default:
182    break;
183  }
184
185  return true;
186}
187
188bool trans::isGlobalVar(Expr *E) {
189  E = E->IgnoreParenCasts();
190  if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
191    return DRE->getDecl()->getDeclContext()->isFileContext() &&
192           DRE->getDecl()->getLinkage() == ExternalLinkage;
193  if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E))
194    return isGlobalVar(condOp->getTrueExpr()) &&
195           isGlobalVar(condOp->getFalseExpr());
196
197  return false;
198}
199
200StringRef trans::getNilString(ASTContext &Ctx) {
201  if (Ctx.Idents.get("nil").hasMacroDefinition())
202    return "nil";
203  else
204    return "0";
205}
206
207namespace {
208
209class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> {
210  ExprSet &Refs;
211public:
212  ReferenceClear(ExprSet &refs) : Refs(refs) { }
213  bool VisitDeclRefExpr(DeclRefExpr *E) { Refs.erase(E); return true; }
214};
215
216class ReferenceCollector : public RecursiveASTVisitor<ReferenceCollector> {
217  ValueDecl *Dcl;
218  ExprSet &Refs;
219
220public:
221  ReferenceCollector(ValueDecl *D, ExprSet &refs)
222    : Dcl(D), Refs(refs) { }
223
224  bool VisitDeclRefExpr(DeclRefExpr *E) {
225    if (E->getDecl() == Dcl)
226      Refs.insert(E);
227    return true;
228  }
229};
230
231class RemovablesCollector : public RecursiveASTVisitor<RemovablesCollector> {
232  ExprSet &Removables;
233
234public:
235  RemovablesCollector(ExprSet &removables)
236  : Removables(removables) { }
237
238  bool shouldWalkTypesOfTypeLocs() const { return false; }
239
240  bool TraverseStmtExpr(StmtExpr *E) {
241    CompoundStmt *S = E->getSubStmt();
242    for (CompoundStmt::body_iterator
243        I = S->body_begin(), E = S->body_end(); I != E; ++I) {
244      if (I != E - 1)
245        mark(*I);
246      TraverseStmt(*I);
247    }
248    return true;
249  }
250
251  bool VisitCompoundStmt(CompoundStmt *S) {
252    for (CompoundStmt::body_iterator
253        I = S->body_begin(), E = S->body_end(); I != E; ++I)
254      mark(*I);
255    return true;
256  }
257
258  bool VisitIfStmt(IfStmt *S) {
259    mark(S->getThen());
260    mark(S->getElse());
261    return true;
262  }
263
264  bool VisitWhileStmt(WhileStmt *S) {
265    mark(S->getBody());
266    return true;
267  }
268
269  bool VisitDoStmt(DoStmt *S) {
270    mark(S->getBody());
271    return true;
272  }
273
274  bool VisitForStmt(ForStmt *S) {
275    mark(S->getInit());
276    mark(S->getInc());
277    mark(S->getBody());
278    return true;
279  }
280
281private:
282  void mark(Stmt *S) {
283    if (!S) return;
284
285    while (LabelStmt *Label = dyn_cast<LabelStmt>(S))
286      S = Label->getSubStmt();
287    S = S->IgnoreImplicit();
288    if (Expr *E = dyn_cast<Expr>(S))
289      Removables.insert(E);
290  }
291};
292
293} // end anonymous namespace
294
295void trans::clearRefsIn(Stmt *S, ExprSet &refs) {
296  ReferenceClear(refs).TraverseStmt(S);
297}
298
299void trans::collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs) {
300  ReferenceCollector(D, refs).TraverseStmt(S);
301}
302
303void trans::collectRemovables(Stmt *S, ExprSet &exprs) {
304  RemovablesCollector(exprs).TraverseStmt(S);
305}
306
307//===----------------------------------------------------------------------===//
308// MigrationContext
309//===----------------------------------------------------------------------===//
310
311namespace {
312
313class ASTTransform : public RecursiveASTVisitor<ASTTransform> {
314  MigrationContext &MigrateCtx;
315  typedef RecursiveASTVisitor<ASTTransform> base;
316
317public:
318  ASTTransform(MigrationContext &MigrateCtx) : MigrateCtx(MigrateCtx) { }
319
320  bool shouldWalkTypesOfTypeLocs() const { return false; }
321
322  bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) {
323    ObjCImplementationContext ImplCtx(MigrateCtx, D);
324    for (MigrationContext::traverser_iterator
325           I = MigrateCtx.traversers_begin(),
326           E = MigrateCtx.traversers_end(); I != E; ++I)
327      (*I)->traverseObjCImplementation(ImplCtx);
328
329    return base::TraverseObjCImplementationDecl(D);
330  }
331
332  bool TraverseStmt(Stmt *rootS) {
333    if (!rootS)
334      return true;
335
336    BodyContext BodyCtx(MigrateCtx, rootS);
337    for (MigrationContext::traverser_iterator
338           I = MigrateCtx.traversers_begin(),
339           E = MigrateCtx.traversers_end(); I != E; ++I)
340      (*I)->traverseBody(BodyCtx);
341
342    return true;
343  }
344};
345
346}
347
348MigrationContext::~MigrationContext() {
349  for (traverser_iterator
350         I = traversers_begin(), E = traversers_end(); I != E; ++I)
351    delete *I;
352}
353
354bool MigrationContext::isGCOwnedNonObjC(QualType T) {
355  while (!T.isNull()) {
356    if (const AttributedType *AttrT = T->getAs<AttributedType>()) {
357      if (AttrT->getAttrKind() == AttributedType::attr_objc_ownership)
358        return !AttrT->getModifiedType()->isObjCRetainableType();
359    }
360
361    if (T->isArrayType())
362      T = Pass.Ctx.getBaseElementType(T);
363    else if (const PointerType *PT = T->getAs<PointerType>())
364      T = PT->getPointeeType();
365    else if (const ReferenceType *RT = T->getAs<ReferenceType>())
366      T = RT->getPointeeType();
367    else
368      break;
369  }
370
371  return false;
372}
373
374bool MigrationContext::rewritePropertyAttribute(StringRef fromAttr,
375                                                StringRef toAttr,
376                                                SourceLocation atLoc) {
377  if (atLoc.isMacroID())
378    return false;
379
380  SourceManager &SM = Pass.Ctx.getSourceManager();
381
382  // Break down the source location.
383  std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
384
385  // Try to load the file buffer.
386  bool invalidTemp = false;
387  StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
388  if (invalidTemp)
389    return false;
390
391  const char *tokenBegin = file.data() + locInfo.second;
392
393  // Lex from the start of the given location.
394  Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
395              Pass.Ctx.getLangOpts(),
396              file.begin(), tokenBegin, file.end());
397  Token tok;
398  lexer.LexFromRawLexer(tok);
399  if (tok.isNot(tok::at)) return false;
400  lexer.LexFromRawLexer(tok);
401  if (tok.isNot(tok::raw_identifier)) return false;
402  if (StringRef(tok.getRawIdentifierData(), tok.getLength())
403        != "property")
404    return false;
405  lexer.LexFromRawLexer(tok);
406  if (tok.isNot(tok::l_paren)) return false;
407
408  Token BeforeTok = tok;
409  Token AfterTok;
410  AfterTok.startToken();
411  SourceLocation AttrLoc;
412
413  lexer.LexFromRawLexer(tok);
414  if (tok.is(tok::r_paren))
415    return false;
416
417  while (1) {
418    if (tok.isNot(tok::raw_identifier)) return false;
419    StringRef ident(tok.getRawIdentifierData(), tok.getLength());
420    if (ident == fromAttr) {
421      if (!toAttr.empty()) {
422        Pass.TA.replaceText(tok.getLocation(), fromAttr, toAttr);
423        return true;
424      }
425      // We want to remove the attribute.
426      AttrLoc = tok.getLocation();
427    }
428
429    do {
430      lexer.LexFromRawLexer(tok);
431      if (AttrLoc.isValid() && AfterTok.is(tok::unknown))
432        AfterTok = tok;
433    } while (tok.isNot(tok::comma) && tok.isNot(tok::r_paren));
434    if (tok.is(tok::r_paren))
435      break;
436    if (AttrLoc.isInvalid())
437      BeforeTok = tok;
438    lexer.LexFromRawLexer(tok);
439  }
440
441  if (toAttr.empty() && AttrLoc.isValid() && AfterTok.isNot(tok::unknown)) {
442    // We want to remove the attribute.
443    if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::r_paren)) {
444      Pass.TA.remove(SourceRange(BeforeTok.getLocation(),
445                                 AfterTok.getLocation()));
446    } else if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::comma)) {
447      Pass.TA.remove(SourceRange(AttrLoc, AfterTok.getLocation()));
448    } else {
449      Pass.TA.remove(SourceRange(BeforeTok.getLocation(), AttrLoc));
450    }
451
452    return true;
453  }
454
455  return false;
456}
457
458bool MigrationContext::addPropertyAttribute(StringRef attr,
459                                            SourceLocation atLoc) {
460  if (atLoc.isMacroID())
461    return false;
462
463  SourceManager &SM = Pass.Ctx.getSourceManager();
464
465  // Break down the source location.
466  std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
467
468  // Try to load the file buffer.
469  bool invalidTemp = false;
470  StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
471  if (invalidTemp)
472    return false;
473
474  const char *tokenBegin = file.data() + locInfo.second;
475
476  // Lex from the start of the given location.
477  Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
478              Pass.Ctx.getLangOpts(),
479              file.begin(), tokenBegin, file.end());
480  Token tok;
481  lexer.LexFromRawLexer(tok);
482  if (tok.isNot(tok::at)) return false;
483  lexer.LexFromRawLexer(tok);
484  if (tok.isNot(tok::raw_identifier)) return false;
485  if (StringRef(tok.getRawIdentifierData(), tok.getLength())
486        != "property")
487    return false;
488  lexer.LexFromRawLexer(tok);
489
490  if (tok.isNot(tok::l_paren)) {
491    Pass.TA.insert(tok.getLocation(), std::string("(") + attr.str() + ") ");
492    return true;
493  }
494
495  lexer.LexFromRawLexer(tok);
496  if (tok.is(tok::r_paren)) {
497    Pass.TA.insert(tok.getLocation(), attr);
498    return true;
499  }
500
501  if (tok.isNot(tok::raw_identifier)) return false;
502
503  Pass.TA.insert(tok.getLocation(), std::string(attr) + ", ");
504  return true;
505}
506
507void MigrationContext::traverse(TranslationUnitDecl *TU) {
508  for (traverser_iterator
509         I = traversers_begin(), E = traversers_end(); I != E; ++I)
510    (*I)->traverseTU(*this);
511
512  ASTTransform(*this).TraverseDecl(TU);
513}
514
515static void GCRewriteFinalize(MigrationPass &pass) {
516  ASTContext &Ctx = pass.Ctx;
517  TransformActions &TA = pass.TA;
518  DeclContext *DC = Ctx.getTranslationUnitDecl();
519  Selector FinalizeSel =
520   Ctx.Selectors.getNullarySelector(&pass.Ctx.Idents.get("finalize"));
521
522  typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl>
523  impl_iterator;
524  for (impl_iterator I = impl_iterator(DC->decls_begin()),
525       E = impl_iterator(DC->decls_end()); I != E; ++I) {
526    for (ObjCImplementationDecl::instmeth_iterator
527         MI = I->instmeth_begin(),
528         ME = I->instmeth_end(); MI != ME; ++MI) {
529      ObjCMethodDecl *MD = *MI;
530      if (!MD->hasBody())
531        continue;
532
533      if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) {
534        ObjCMethodDecl *FinalizeM = MD;
535        Transaction Trans(TA);
536        TA.insert(FinalizeM->getSourceRange().getBegin(),
537                  "#if !__has_feature(objc_arc)\n");
538        CharSourceRange::getTokenRange(FinalizeM->getSourceRange());
539        const SourceManager &SM = pass.Ctx.getSourceManager();
540        const LangOptions &LangOpts = pass.Ctx.getLangOpts();
541        bool Invalid;
542        std::string str = "\n#endif\n";
543        str += Lexer::getSourceText(
544                  CharSourceRange::getTokenRange(FinalizeM->getSourceRange()),
545                                    SM, LangOpts, &Invalid);
546        TA.insertAfterToken(FinalizeM->getSourceRange().getEnd(), str);
547
548        break;
549      }
550    }
551  }
552}
553
554//===----------------------------------------------------------------------===//
555// getAllTransformations.
556//===----------------------------------------------------------------------===//
557
558static void traverseAST(MigrationPass &pass) {
559  MigrationContext MigrateCtx(pass);
560
561  if (pass.isGCMigration()) {
562    MigrateCtx.addTraverser(new GCCollectableCallsTraverser);
563    MigrateCtx.addTraverser(new GCAttrsTraverser());
564  }
565  MigrateCtx.addTraverser(new PropertyRewriteTraverser());
566  MigrateCtx.addTraverser(new BlockObjCVariableTraverser());
567  MigrateCtx.addTraverser(new ProtectedScopeTraverser());
568
569  MigrateCtx.traverse(pass.Ctx.getTranslationUnitDecl());
570}
571
572static void independentTransforms(MigrationPass &pass) {
573  rewriteAutoreleasePool(pass);
574  removeRetainReleaseDeallocFinalize(pass);
575  rewriteUnusedInitDelegate(pass);
576  removeZeroOutPropsInDeallocFinalize(pass);
577  makeAssignARCSafe(pass);
578  rewriteUnbridgedCasts(pass);
579  checkAPIUses(pass);
580  traverseAST(pass);
581}
582
583std::vector<TransformFn> arcmt::getAllTransformations(
584                                               LangOptions::GCMode OrigGCMode,
585                                               bool NoFinalizeRemoval) {
586  std::vector<TransformFn> transforms;
587
588  if (OrigGCMode ==  LangOptions::GCOnly && NoFinalizeRemoval)
589    transforms.push_back(GCRewriteFinalize);
590  transforms.push_back(independentTransforms);
591  // This depends on previous transformations removing various expressions.
592  transforms.push_back(removeEmptyStatementsAndDeallocFinalize);
593
594  return transforms;
595}
596