1249423Sdim//===--- TransUnbridgedCasts.cpp - Transformations to ARC mode ------------===//
2224135Sdim//
3224135Sdim//                     The LLVM Compiler Infrastructure
4224135Sdim//
5224135Sdim// This file is distributed under the University of Illinois Open Source
6224135Sdim// License. See LICENSE.TXT for details.
7224135Sdim//
8224135Sdim//===----------------------------------------------------------------------===//
9224135Sdim//
10224135Sdim// rewriteUnbridgedCasts:
11224135Sdim//
12224135Sdim// A cast of non-objc pointer to an objc one is checked. If the non-objc pointer
13224135Sdim// is from a file-level variable, __bridge cast is used to convert it.
14224135Sdim// For the result of a function call that we know is +1/+0,
15239462Sdim// __bridge/CFBridgingRelease is used.
16224135Sdim//
17224135Sdim//  NSString *str = (NSString *)kUTTypePlainText;
18224135Sdim//  str = b ? kUTTypeRTF : kUTTypePlainText;
19224135Sdim//  NSString *_uuidString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault,
20224135Sdim//                                                         _uuid);
21224135Sdim// ---->
22224135Sdim//  NSString *str = (__bridge NSString *)kUTTypePlainText;
23224135Sdim//  str = (__bridge NSString *)(b ? kUTTypeRTF : kUTTypePlainText);
24239462Sdim// NSString *_uuidString = (NSString *)
25239462Sdim//            CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, _uuid));
26224135Sdim//
27224135Sdim// For a C pointer to ObjC, for casting 'self', __bridge is used.
28224135Sdim//
29224135Sdim//  CFStringRef str = (CFStringRef)self;
30224135Sdim// ---->
31224135Sdim//  CFStringRef str = (__bridge CFStringRef)self;
32224135Sdim//
33249423Sdim// Uses of Block_copy/Block_release macros are rewritten:
34249423Sdim//
35249423Sdim//  c = Block_copy(b);
36249423Sdim//  Block_release(c);
37249423Sdim// ---->
38249423Sdim//  c = [b copy];
39249423Sdim//  <removed>
40249423Sdim//
41224135Sdim//===----------------------------------------------------------------------===//
42224135Sdim
43224135Sdim#include "Transforms.h"
44224135Sdim#include "Internals.h"
45239462Sdim#include "clang/AST/ASTContext.h"
46249423Sdim#include "clang/AST/Attr.h"
47226633Sdim#include "clang/AST/ParentMap.h"
48249423Sdim#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
49224135Sdim#include "clang/Basic/SourceManager.h"
50239462Sdim#include "clang/Lex/Lexer.h"
51239462Sdim#include "clang/Sema/SemaDiagnostic.h"
52234353Sdim#include "llvm/ADT/SmallString.h"
53224135Sdim
54224135Sdimusing namespace clang;
55224135Sdimusing namespace arcmt;
56224135Sdimusing namespace trans;
57224135Sdim
58224135Sdimnamespace {
59224135Sdim
60224135Sdimclass UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
61224135Sdim  MigrationPass &Pass;
62224135Sdim  IdentifierInfo *SelfII;
63234353Sdim  OwningPtr<ParentMap> StmtMap;
64239462Sdim  Decl *ParentD;
65249423Sdim  Stmt *Body;
66249423Sdim  mutable OwningPtr<ExprSet> Removables;
67226633Sdim
68224135Sdimpublic:
69249423Sdim  UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass), ParentD(0), Body(0) {
70224135Sdim    SelfII = &Pass.Ctx.Idents.get("self");
71224135Sdim  }
72224135Sdim
73239462Sdim  void transformBody(Stmt *body, Decl *ParentD) {
74239462Sdim    this->ParentD = ParentD;
75249423Sdim    Body = body;
76226633Sdim    StmtMap.reset(new ParentMap(body));
77226633Sdim    TraverseStmt(body);
78226633Sdim  }
79226633Sdim
80263508Sdim  bool TraverseBlockDecl(BlockDecl *D) {
81263508Sdim    // ParentMap does not enter into a BlockDecl to record its stmts, so use a
82263508Sdim    // new UnbridgedCastRewriter to handle the block.
83263508Sdim    UnbridgedCastRewriter(Pass).transformBody(D->getBody(), D);
84263508Sdim    return true;
85263508Sdim  }
86263508Sdim
87224135Sdim  bool VisitCastExpr(CastExpr *E) {
88249423Sdim    if (E->getCastKind() != CK_CPointerToObjCPointerCast &&
89249423Sdim        E->getCastKind() != CK_BitCast &&
90249423Sdim        E->getCastKind() != CK_AnyPointerToBlockPointerCast)
91224135Sdim      return true;
92224135Sdim
93224135Sdim    QualType castType = E->getType();
94224135Sdim    Expr *castExpr = E->getSubExpr();
95224135Sdim    QualType castExprType = castExpr->getType();
96224135Sdim
97249423Sdim    if (castType->isObjCRetainableType() == castExprType->isObjCRetainableType())
98224135Sdim      return true;
99224135Sdim
100224135Sdim    bool exprRetainable = castExprType->isObjCIndirectLifetimeType();
101224135Sdim    bool castRetainable = castType->isObjCIndirectLifetimeType();
102224135Sdim    if (exprRetainable == castRetainable) return true;
103224135Sdim
104224135Sdim    if (castExpr->isNullPointerConstant(Pass.Ctx,
105224135Sdim                                        Expr::NPC_ValueDependentIsNull))
106224135Sdim      return true;
107224135Sdim
108224135Sdim    SourceLocation loc = castExpr->getExprLoc();
109224135Sdim    if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc))
110224135Sdim      return true;
111224135Sdim
112249423Sdim    if (castType->isObjCRetainableType())
113224135Sdim      transformNonObjCToObjCCast(E);
114224135Sdim    else
115224135Sdim      transformObjCToNonObjCCast(E);
116224135Sdim
117224135Sdim    return true;
118224135Sdim  }
119224135Sdim
120224135Sdimprivate:
121224135Sdim  void transformNonObjCToObjCCast(CastExpr *E) {
122224135Sdim    if (!E) return;
123224135Sdim
124224135Sdim    // Global vars are assumed that are cast as unretained.
125224135Sdim    if (isGlobalVar(E))
126224135Sdim      if (E->getSubExpr()->getType()->isPointerType()) {
127224135Sdim        castToObjCObject(E, /*retained=*/false);
128224135Sdim        return;
129224135Sdim      }
130224135Sdim
131224135Sdim    // If the cast is directly over the result of a Core Foundation function
132224135Sdim    // try to figure out whether it should be cast as retained or unretained.
133224135Sdim    Expr *inner = E->IgnoreParenCasts();
134224135Sdim    if (CallExpr *callE = dyn_cast<CallExpr>(inner)) {
135224135Sdim      if (FunctionDecl *FD = callE->getDirectCallee()) {
136224135Sdim        if (FD->getAttr<CFReturnsRetainedAttr>()) {
137224135Sdim          castToObjCObject(E, /*retained=*/true);
138224135Sdim          return;
139224135Sdim        }
140224135Sdim        if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
141224135Sdim          castToObjCObject(E, /*retained=*/false);
142224135Sdim          return;
143224135Sdim        }
144224135Sdim        if (FD->isGlobal() &&
145224135Sdim            FD->getIdentifier() &&
146224135Sdim            ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF",
147224135Sdim                                   FD->getIdentifier()->getName())) {
148224135Sdim          StringRef fname = FD->getIdentifier()->getName();
149224135Sdim          if (fname.endswith("Retain") ||
150224135Sdim              fname.find("Create") != StringRef::npos ||
151224135Sdim              fname.find("Copy") != StringRef::npos) {
152234353Sdim            // Do not migrate to couple of bridge transfer casts which
153234353Sdim            // cancel each other out. Leave it unchanged so error gets user
154234353Sdim            // attention instead.
155234353Sdim            if (FD->getName() == "CFRetain" &&
156234353Sdim                FD->getNumParams() == 1 &&
157234353Sdim                FD->getParent()->isTranslationUnit() &&
158263508Sdim                FD->isExternallyVisible()) {
159234353Sdim              Expr *Arg = callE->getArg(0);
160234353Sdim              if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
161234353Sdim                const Expr *sub = ICE->getSubExpr();
162234353Sdim                QualType T = sub->getType();
163234353Sdim                if (T->isObjCObjectPointerType())
164234353Sdim                  return;
165234353Sdim              }
166234353Sdim            }
167224135Sdim            castToObjCObject(E, /*retained=*/true);
168224135Sdim            return;
169224135Sdim          }
170224135Sdim
171224135Sdim          if (fname.find("Get") != StringRef::npos) {
172224135Sdim            castToObjCObject(E, /*retained=*/false);
173224135Sdim            return;
174224135Sdim          }
175224135Sdim        }
176224135Sdim      }
177224135Sdim    }
178239462Sdim
179239462Sdim    // If returning an ivar or a member of an ivar from a +0 method, use
180239462Sdim    // a __bridge cast.
181239462Sdim    Expr *base = inner->IgnoreParenImpCasts();
182239462Sdim    while (isa<MemberExpr>(base))
183239462Sdim      base = cast<MemberExpr>(base)->getBase()->IgnoreParenImpCasts();
184239462Sdim    if (isa<ObjCIvarRefExpr>(base) &&
185239462Sdim        isa<ReturnStmt>(StmtMap->getParentIgnoreParenCasts(E))) {
186239462Sdim      if (ObjCMethodDecl *method = dyn_cast_or_null<ObjCMethodDecl>(ParentD)) {
187239462Sdim        if (!method->hasAttr<NSReturnsRetainedAttr>()) {
188239462Sdim          castToObjCObject(E, /*retained=*/false);
189239462Sdim          return;
190239462Sdim        }
191239462Sdim      }
192239462Sdim    }
193224135Sdim  }
194224135Sdim
195224135Sdim  void castToObjCObject(CastExpr *E, bool retained) {
196224135Sdim    rewriteToBridgedCast(E, retained ? OBC_BridgeTransfer : OBC_Bridge);
197224135Sdim  }
198224135Sdim
199224135Sdim  void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) {
200226633Sdim    Transaction Trans(Pass.TA);
201226633Sdim    rewriteToBridgedCast(E, Kind, Trans);
202226633Sdim  }
203226633Sdim
204226633Sdim  void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind,
205226633Sdim                            Transaction &Trans) {
206224135Sdim    TransformActions &TA = Pass.TA;
207224135Sdim
208224135Sdim    // We will remove the compiler diagnostic.
209224135Sdim    if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast,
210224135Sdim                          diag::err_arc_cast_requires_bridge,
211226633Sdim                          E->getLocStart())) {
212226633Sdim      Trans.abort();
213224135Sdim      return;
214226633Sdim    }
215224135Sdim
216224135Sdim    StringRef bridge;
217224135Sdim    switch(Kind) {
218224135Sdim    case OBC_Bridge:
219224135Sdim      bridge = "__bridge "; break;
220224135Sdim    case OBC_BridgeTransfer:
221224135Sdim      bridge = "__bridge_transfer "; break;
222224135Sdim    case OBC_BridgeRetained:
223224135Sdim      bridge = "__bridge_retained "; break;
224224135Sdim    }
225224135Sdim
226224135Sdim    TA.clearDiagnostic(diag::err_arc_mismatched_cast,
227224135Sdim                       diag::err_arc_cast_requires_bridge,
228224135Sdim                       E->getLocStart());
229239462Sdim    if (Kind == OBC_Bridge || !Pass.CFBridgingFunctionsDefined()) {
230239462Sdim      if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(E)) {
231239462Sdim        TA.insertAfterToken(CCE->getLParenLoc(), bridge);
232239462Sdim      } else {
233239462Sdim        SourceLocation insertLoc = E->getSubExpr()->getLocStart();
234239462Sdim        SmallString<128> newCast;
235239462Sdim        newCast += '(';
236239462Sdim        newCast += bridge;
237239462Sdim        newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
238239462Sdim        newCast += ')';
239239462Sdim
240239462Sdim        if (isa<ParenExpr>(E->getSubExpr())) {
241239462Sdim          TA.insert(insertLoc, newCast.str());
242239462Sdim        } else {
243239462Sdim          newCast += '(';
244239462Sdim          TA.insert(insertLoc, newCast.str());
245239462Sdim          TA.insertAfterToken(E->getLocEnd(), ")");
246239462Sdim        }
247239462Sdim      }
248224135Sdim    } else {
249239462Sdim      assert(Kind == OBC_BridgeTransfer || Kind == OBC_BridgeRetained);
250239462Sdim      SmallString<32> BridgeCall;
251224135Sdim
252239462Sdim      Expr *WrapE = E->getSubExpr();
253239462Sdim      SourceLocation InsertLoc = WrapE->getLocStart();
254239462Sdim
255239462Sdim      SourceManager &SM = Pass.Ctx.getSourceManager();
256239462Sdim      char PrevChar = *SM.getCharacterData(InsertLoc.getLocWithOffset(-1));
257239462Sdim      if (Lexer::isIdentifierBodyChar(PrevChar, Pass.Ctx.getLangOpts()))
258239462Sdim        BridgeCall += ' ';
259239462Sdim
260239462Sdim      if (Kind == OBC_BridgeTransfer)
261239462Sdim        BridgeCall += "CFBridgingRelease";
262239462Sdim      else
263239462Sdim        BridgeCall += "CFBridgingRetain";
264239462Sdim
265239462Sdim      if (isa<ParenExpr>(WrapE)) {
266239462Sdim        TA.insert(InsertLoc, BridgeCall);
267224135Sdim      } else {
268239462Sdim        BridgeCall += '(';
269239462Sdim        TA.insert(InsertLoc, BridgeCall);
270239462Sdim        TA.insertAfterToken(WrapE->getLocEnd(), ")");
271224135Sdim      }
272224135Sdim    }
273224135Sdim  }
274224135Sdim
275226633Sdim  void rewriteCastForCFRetain(CastExpr *castE, CallExpr *callE) {
276226633Sdim    Transaction Trans(Pass.TA);
277226633Sdim    Pass.TA.replace(callE->getSourceRange(), callE->getArg(0)->getSourceRange());
278226633Sdim    rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans);
279226633Sdim  }
280226633Sdim
281249423Sdim  void getBlockMacroRanges(CastExpr *E, SourceRange &Outer, SourceRange &Inner) {
282249423Sdim    SourceManager &SM = Pass.Ctx.getSourceManager();
283249423Sdim    SourceLocation Loc = E->getExprLoc();
284249423Sdim    assert(Loc.isMacroID());
285249423Sdim    SourceLocation MacroBegin, MacroEnd;
286249423Sdim    llvm::tie(MacroBegin, MacroEnd) = SM.getImmediateExpansionRange(Loc);
287249423Sdim    SourceRange SubRange = E->getSubExpr()->IgnoreParenImpCasts()->getSourceRange();
288249423Sdim    SourceLocation InnerBegin = SM.getImmediateMacroCallerLoc(SubRange.getBegin());
289249423Sdim    SourceLocation InnerEnd = SM.getImmediateMacroCallerLoc(SubRange.getEnd());
290249423Sdim
291249423Sdim    Outer = SourceRange(MacroBegin, MacroEnd);
292249423Sdim    Inner = SourceRange(InnerBegin, InnerEnd);
293249423Sdim  }
294249423Sdim
295249423Sdim  void rewriteBlockCopyMacro(CastExpr *E) {
296249423Sdim    SourceRange OuterRange, InnerRange;
297249423Sdim    getBlockMacroRanges(E, OuterRange, InnerRange);
298249423Sdim
299249423Sdim    Transaction Trans(Pass.TA);
300249423Sdim    Pass.TA.replace(OuterRange, InnerRange);
301249423Sdim    Pass.TA.insert(InnerRange.getBegin(), "[");
302249423Sdim    Pass.TA.insertAfterToken(InnerRange.getEnd(), " copy]");
303249423Sdim    Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast,
304249423Sdim                            diag::err_arc_cast_requires_bridge,
305249423Sdim                            OuterRange);
306249423Sdim  }
307249423Sdim
308249423Sdim  void removeBlockReleaseMacro(CastExpr *E) {
309249423Sdim    SourceRange OuterRange, InnerRange;
310249423Sdim    getBlockMacroRanges(E, OuterRange, InnerRange);
311249423Sdim
312249423Sdim    Transaction Trans(Pass.TA);
313249423Sdim    Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast,
314249423Sdim                            diag::err_arc_cast_requires_bridge,
315249423Sdim                            OuterRange);
316249423Sdim    if (!hasSideEffects(E, Pass.Ctx)) {
317249423Sdim      if (tryRemoving(cast<Expr>(StmtMap->getParentIgnoreParenCasts(E))))
318249423Sdim        return;
319249423Sdim    }
320249423Sdim    Pass.TA.replace(OuterRange, InnerRange);
321249423Sdim  }
322249423Sdim
323249423Sdim  bool tryRemoving(Expr *E) const {
324249423Sdim    if (!Removables) {
325249423Sdim      Removables.reset(new ExprSet);
326249423Sdim      collectRemovables(Body, *Removables);
327249423Sdim    }
328249423Sdim
329249423Sdim    if (Removables->count(E)) {
330249423Sdim      Pass.TA.removeStmt(E);
331249423Sdim      return true;
332249423Sdim    }
333249423Sdim
334249423Sdim    return false;
335249423Sdim  }
336249423Sdim
337224135Sdim  void transformObjCToNonObjCCast(CastExpr *E) {
338249423Sdim    SourceLocation CastLoc = E->getExprLoc();
339249423Sdim    if (CastLoc.isMacroID()) {
340249423Sdim      StringRef MacroName = Lexer::getImmediateMacroName(CastLoc,
341249423Sdim                                                    Pass.Ctx.getSourceManager(),
342249423Sdim                                                    Pass.Ctx.getLangOpts());
343249423Sdim      if (MacroName == "Block_copy") {
344249423Sdim        rewriteBlockCopyMacro(E);
345249423Sdim        return;
346249423Sdim      }
347249423Sdim      if (MacroName == "Block_release") {
348249423Sdim        removeBlockReleaseMacro(E);
349249423Sdim        return;
350249423Sdim      }
351249423Sdim    }
352249423Sdim
353224135Sdim    if (isSelf(E->getSubExpr()))
354224135Sdim      return rewriteToBridgedCast(E, OBC_Bridge);
355226633Sdim
356226633Sdim    CallExpr *callE;
357226633Sdim    if (isPassedToCFRetain(E, callE))
358226633Sdim      return rewriteCastForCFRetain(E, callE);
359226633Sdim
360226633Sdim    ObjCMethodFamily family = getFamilyOfMessage(E->getSubExpr());
361226633Sdim    if (family == OMF_retain)
362226633Sdim      return rewriteToBridgedCast(E, OBC_BridgeRetained);
363226633Sdim
364226633Sdim    if (family == OMF_autorelease || family == OMF_release) {
365226633Sdim      std::string err = "it is not safe to cast to '";
366226633Sdim      err += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
367226633Sdim      err += "' the result of '";
368226633Sdim      err += family == OMF_autorelease ? "autorelease" : "release";
369226633Sdim      err += "' message; a __bridge cast may result in a pointer to a "
370226633Sdim          "destroyed object and a __bridge_retained may leak the object";
371226633Sdim      Pass.TA.reportError(err, E->getLocStart(),
372226633Sdim                          E->getSubExpr()->getSourceRange());
373226633Sdim      Stmt *parent = E;
374226633Sdim      do {
375226633Sdim        parent = StmtMap->getParentIgnoreParenImpCasts(parent);
376226633Sdim      } while (parent && isa<ExprWithCleanups>(parent));
377226633Sdim
378226633Sdim      if (ReturnStmt *retS = dyn_cast_or_null<ReturnStmt>(parent)) {
379226633Sdim        std::string note = "remove the cast and change return type of function "
380226633Sdim            "to '";
381226633Sdim        note += E->getSubExpr()->getType().getAsString(Pass.Ctx.getPrintingPolicy());
382226633Sdim        note += "' to have the object automatically autoreleased";
383226633Sdim        Pass.TA.reportNote(note, retS->getLocStart());
384226633Sdim      }
385226633Sdim    }
386226633Sdim
387234353Sdim    Expr *subExpr = E->getSubExpr();
388234353Sdim
389234353Sdim    // Look through pseudo-object expressions.
390234353Sdim    if (PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(subExpr)) {
391234353Sdim      subExpr = pseudo->getResultExpr();
392234353Sdim      assert(subExpr && "no result for pseudo-object of non-void type?");
393234353Sdim    }
394234353Sdim
395234353Sdim    if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(subExpr)) {
396226633Sdim      if (implCE->getCastKind() == CK_ARCConsumeObject)
397226633Sdim        return rewriteToBridgedCast(E, OBC_BridgeRetained);
398226633Sdim      if (implCE->getCastKind() == CK_ARCReclaimReturnedObject)
399226633Sdim        return rewriteToBridgedCast(E, OBC_Bridge);
400226633Sdim    }
401226633Sdim
402226633Sdim    bool isConsumed = false;
403226633Sdim    if (isPassedToCParamWithKnownOwnership(E, isConsumed))
404226633Sdim      return rewriteToBridgedCast(E, isConsumed ? OBC_BridgeRetained
405226633Sdim                                                : OBC_Bridge);
406224135Sdim  }
407224135Sdim
408226633Sdim  static ObjCMethodFamily getFamilyOfMessage(Expr *E) {
409226633Sdim    E = E->IgnoreParenCasts();
410226633Sdim    if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
411226633Sdim      return ME->getMethodFamily();
412226633Sdim
413226633Sdim    return OMF_None;
414226633Sdim  }
415226633Sdim
416226633Sdim  bool isPassedToCFRetain(Expr *E, CallExpr *&callE) const {
417226633Sdim    if ((callE = dyn_cast_or_null<CallExpr>(
418226633Sdim                                     StmtMap->getParentIgnoreParenImpCasts(E))))
419226633Sdim      if (FunctionDecl *
420226633Sdim            FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl()))
421226633Sdim        if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 &&
422226633Sdim            FD->getParent()->isTranslationUnit() &&
423263508Sdim            FD->isExternallyVisible())
424226633Sdim          return true;
425226633Sdim
426226633Sdim    return false;
427226633Sdim  }
428226633Sdim
429226633Sdim  bool isPassedToCParamWithKnownOwnership(Expr *E, bool &isConsumed) const {
430226633Sdim    if (CallExpr *callE = dyn_cast_or_null<CallExpr>(
431226633Sdim                                     StmtMap->getParentIgnoreParenImpCasts(E)))
432226633Sdim      if (FunctionDecl *
433226633Sdim            FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) {
434226633Sdim        unsigned i = 0;
435226633Sdim        for (unsigned e = callE->getNumArgs(); i != e; ++i) {
436226633Sdim          Expr *arg = callE->getArg(i);
437226633Sdim          if (arg == E || arg->IgnoreParenImpCasts() == E)
438226633Sdim            break;
439226633Sdim        }
440249423Sdim        if (i < callE->getNumArgs() && i < FD->getNumParams()) {
441226633Sdim          ParmVarDecl *PD = FD->getParamDecl(i);
442226633Sdim          if (PD->getAttr<CFConsumedAttr>()) {
443226633Sdim            isConsumed = true;
444226633Sdim            return true;
445226633Sdim          }
446226633Sdim        }
447226633Sdim      }
448226633Sdim
449226633Sdim    return false;
450226633Sdim  }
451226633Sdim
452226633Sdim  bool isSelf(Expr *E) const {
453224135Sdim    E = E->IgnoreParenLValueCasts();
454224135Sdim    if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
455226633Sdim      if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
456226633Sdim        if (IPD->getIdentifier() == SelfII)
457226633Sdim          return true;
458226633Sdim
459224135Sdim    return false;
460224135Sdim  }
461224135Sdim};
462224135Sdim
463224135Sdim} // end anonymous namespace
464224135Sdim
465224135Sdimvoid trans::rewriteUnbridgedCasts(MigrationPass &pass) {
466226633Sdim  BodyTransform<UnbridgedCastRewriter> trans(pass);
467224135Sdim  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
468224135Sdim}
469