Transforms.cpp revision 1fe4203ca05d0a3283efc8a2e8c01ecdf78fbf2e
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/Analysis/DomainSpecific/CocoaConventions.h"
16#include "clang/Lex/Lexer.h"
17#include "clang/Basic/SourceManager.h"
18#include "llvm/ADT/StringSwitch.h"
19#include "llvm/ADT/DenseSet.h"
20#include <map>
21
22using namespace clang;
23using namespace arcmt;
24using namespace trans;
25
26ASTTraverser::~ASTTraverser() { }
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  SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx);
96  if (SemiLoc.isInvalid())
97    return SourceLocation();
98  return SemiLoc.getLocWithOffset(1);
99}
100
101/// \brief \arg Loc is the end of a statement range. This returns the location
102/// of the semicolon following the statement.
103/// If no semicolon is found or the location is inside a macro, the returned
104/// source location will be invalid.
105SourceLocation trans::findSemiAfterLocation(SourceLocation loc,
106                                            ASTContext &Ctx) {
107  SourceManager &SM = Ctx.getSourceManager();
108  if (loc.isMacroID()) {
109    if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOptions()))
110      return SourceLocation();
111    loc = SM.getExpansionRange(loc).second;
112  }
113  loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOptions());
114
115  // Break down the source location.
116  std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
117
118  // Try to load the file buffer.
119  bool invalidTemp = false;
120  StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
121  if (invalidTemp)
122    return SourceLocation();
123
124  const char *tokenBegin = file.data() + locInfo.second;
125
126  // Lex from the start of the given location.
127  Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
128              Ctx.getLangOptions(),
129              file.begin(), tokenBegin, file.end());
130  Token tok;
131  lexer.LexFromRawLexer(tok);
132  if (tok.isNot(tok::semi))
133    return SourceLocation();
134
135  return tok.getLocation();
136}
137
138bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) {
139  if (!E || !E->HasSideEffects(Ctx))
140    return false;
141
142  E = E->IgnoreParenCasts();
143  ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E);
144  if (!ME)
145    return true;
146  switch (ME->getMethodFamily()) {
147  case OMF_autorelease:
148  case OMF_dealloc:
149  case OMF_release:
150  case OMF_retain:
151    switch (ME->getReceiverKind()) {
152    case ObjCMessageExpr::SuperInstance:
153      return false;
154    case ObjCMessageExpr::Instance:
155      return hasSideEffects(ME->getInstanceReceiver(), Ctx);
156    default:
157      break;
158    }
159    break;
160  default:
161    break;
162  }
163
164  return true;
165}
166
167bool trans::isGlobalVar(Expr *E) {
168  E = E->IgnoreParenCasts();
169  if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
170    return DRE->getDecl()->getDeclContext()->isFileContext() &&
171           DRE->getDecl()->getLinkage() == ExternalLinkage;
172  if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E))
173    return isGlobalVar(condOp->getTrueExpr()) &&
174           isGlobalVar(condOp->getFalseExpr());
175
176  return false;
177}
178
179StringRef trans::getNilString(ASTContext &Ctx) {
180  if (Ctx.Idents.get("nil").hasMacroDefinition())
181    return "nil";
182  else
183    return "0";
184}
185
186namespace {
187
188class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> {
189  ExprSet &Refs;
190public:
191  ReferenceClear(ExprSet &refs) : Refs(refs) { }
192  bool VisitDeclRefExpr(DeclRefExpr *E) { Refs.erase(E); return true; }
193  bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { Refs.erase(E); return true; }
194};
195
196class ReferenceCollector : public RecursiveASTVisitor<ReferenceCollector> {
197  ValueDecl *Dcl;
198  ExprSet &Refs;
199
200public:
201  ReferenceCollector(ValueDecl *D, ExprSet &refs)
202    : Dcl(D), Refs(refs) { }
203
204  bool VisitDeclRefExpr(DeclRefExpr *E) {
205    if (E->getDecl() == Dcl)
206      Refs.insert(E);
207    return true;
208  }
209
210  bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
211    if (E->getDecl() == Dcl)
212      Refs.insert(E);
213    return true;
214  }
215};
216
217class RemovablesCollector : public RecursiveASTVisitor<RemovablesCollector> {
218  ExprSet &Removables;
219
220public:
221  RemovablesCollector(ExprSet &removables)
222  : Removables(removables) { }
223
224  bool shouldWalkTypesOfTypeLocs() const { return false; }
225
226  bool TraverseStmtExpr(StmtExpr *E) {
227    CompoundStmt *S = E->getSubStmt();
228    for (CompoundStmt::body_iterator
229        I = S->body_begin(), E = S->body_end(); I != E; ++I) {
230      if (I != E - 1)
231        mark(*I);
232      TraverseStmt(*I);
233    }
234    return true;
235  }
236
237  bool VisitCompoundStmt(CompoundStmt *S) {
238    for (CompoundStmt::body_iterator
239        I = S->body_begin(), E = S->body_end(); I != E; ++I)
240      mark(*I);
241    return true;
242  }
243
244  bool VisitIfStmt(IfStmt *S) {
245    mark(S->getThen());
246    mark(S->getElse());
247    return true;
248  }
249
250  bool VisitWhileStmt(WhileStmt *S) {
251    mark(S->getBody());
252    return true;
253  }
254
255  bool VisitDoStmt(DoStmt *S) {
256    mark(S->getBody());
257    return true;
258  }
259
260  bool VisitForStmt(ForStmt *S) {
261    mark(S->getInit());
262    mark(S->getInc());
263    mark(S->getBody());
264    return true;
265  }
266
267private:
268  void mark(Stmt *S) {
269    if (!S) return;
270
271    while (LabelStmt *Label = dyn_cast<LabelStmt>(S))
272      S = Label->getSubStmt();
273    S = S->IgnoreImplicit();
274    if (Expr *E = dyn_cast<Expr>(S))
275      Removables.insert(E);
276  }
277};
278
279} // end anonymous namespace
280
281void trans::clearRefsIn(Stmt *S, ExprSet &refs) {
282  ReferenceClear(refs).TraverseStmt(S);
283}
284
285void trans::collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs) {
286  ReferenceCollector(D, refs).TraverseStmt(S);
287}
288
289void trans::collectRemovables(Stmt *S, ExprSet &exprs) {
290  RemovablesCollector(exprs).TraverseStmt(S);
291}
292
293//===----------------------------------------------------------------------===//
294// MigrationContext
295//===----------------------------------------------------------------------===//
296
297namespace {
298
299class ASTTransform : public RecursiveASTVisitor<ASTTransform> {
300  MigrationContext &MigrateCtx;
301
302public:
303  ASTTransform(MigrationContext &MigrateCtx) : MigrateCtx(MigrateCtx) { }
304
305  bool TraverseStmt(Stmt *rootS) {
306    if (!rootS)
307      return true;
308
309    BodyContext BodyCtx(MigrateCtx, rootS);
310    for (MigrationContext::traverser_iterator
311           I = MigrateCtx.traversers_begin(),
312           E = MigrateCtx.traversers_end(); I != E; ++I)
313      (*I)->traverseBody(BodyCtx);
314
315    return true;
316  }
317};
318
319}
320
321MigrationContext::~MigrationContext() {
322  for (traverser_iterator
323         I = traversers_begin(), E = traversers_end(); I != E; ++I)
324    delete *I;
325}
326
327bool MigrationContext::isGCOwnedNonObjC(QualType T) {
328  while (!T.isNull()) {
329    if (const AttributedType *AttrT = T->getAs<AttributedType>()) {
330      if (AttrT->getAttrKind() == AttributedType::attr_objc_ownership)
331        return !AttrT->getModifiedType()->isObjCRetainableType();
332    }
333
334    if (T->isArrayType())
335      T = Pass.Ctx.getBaseElementType(T);
336    else if (const PointerType *PT = T->getAs<PointerType>())
337      T = PT->getPointeeType();
338    else if (const ReferenceType *RT = T->getAs<ReferenceType>())
339      T = RT->getPointeeType();
340    else
341      break;
342  }
343
344  return false;
345}
346
347void MigrationContext::traverse(TranslationUnitDecl *TU) {
348  ASTTransform(*this).TraverseDecl(TU);
349}
350
351//===----------------------------------------------------------------------===//
352// getAllTransformations.
353//===----------------------------------------------------------------------===//
354
355static void traverseAST(MigrationPass &pass) {
356  MigrationContext MigrateCtx(pass);
357
358  if (pass.isGCMigration()) {
359    MigrateCtx.addTraverser(new GCCollectableCallsTraverser);
360  }
361
362  MigrateCtx.traverse(pass.Ctx.getTranslationUnitDecl());
363}
364
365static void independentTransforms(MigrationPass &pass) {
366  rewriteAutoreleasePool(pass);
367  rewriteProperties(pass);
368  removeRetainReleaseDeallocFinalize(pass);
369  rewriteUnusedInitDelegate(pass);
370  removeZeroOutPropsInDeallocFinalize(pass);
371  makeAssignARCSafe(pass);
372  rewriteUnbridgedCasts(pass);
373  rewriteBlockObjCVariable(pass);
374  checkAPIUses(pass);
375  traverseAST(pass);
376}
377
378std::vector<TransformFn> arcmt::getAllTransformations(
379                                               LangOptions::GCMode OrigGCMode) {
380  std::vector<TransformFn> transforms;
381
382  transforms.push_back(independentTransforms);
383  // This depends on previous transformations removing various expressions.
384  transforms.push_back(removeEmptyStatementsAndDeallocFinalize);
385
386  return transforms;
387}
388