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
80224135Sdim  bool VisitCastExpr(CastExpr *E) {
81249423Sdim    if (E->getCastKind() != CK_CPointerToObjCPointerCast &&
82249423Sdim        E->getCastKind() != CK_BitCast &&
83249423Sdim        E->getCastKind() != CK_AnyPointerToBlockPointerCast)
84224135Sdim      return true;
85224135Sdim
86224135Sdim    QualType castType = E->getType();
87224135Sdim    Expr *castExpr = E->getSubExpr();
88224135Sdim    QualType castExprType = castExpr->getType();
89224135Sdim
90249423Sdim    if (castType->isObjCRetainableType() == castExprType->isObjCRetainableType())
91224135Sdim      return true;
92224135Sdim
93224135Sdim    bool exprRetainable = castExprType->isObjCIndirectLifetimeType();
94224135Sdim    bool castRetainable = castType->isObjCIndirectLifetimeType();
95224135Sdim    if (exprRetainable == castRetainable) return true;
96224135Sdim
97224135Sdim    if (castExpr->isNullPointerConstant(Pass.Ctx,
98224135Sdim                                        Expr::NPC_ValueDependentIsNull))
99224135Sdim      return true;
100224135Sdim
101224135Sdim    SourceLocation loc = castExpr->getExprLoc();
102224135Sdim    if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc))
103224135Sdim      return true;
104224135Sdim
105249423Sdim    if (castType->isObjCRetainableType())
106224135Sdim      transformNonObjCToObjCCast(E);
107224135Sdim    else
108224135Sdim      transformObjCToNonObjCCast(E);
109224135Sdim
110224135Sdim    return true;
111224135Sdim  }
112224135Sdim
113224135Sdimprivate:
114224135Sdim  void transformNonObjCToObjCCast(CastExpr *E) {
115224135Sdim    if (!E) return;
116224135Sdim
117224135Sdim    // Global vars are assumed that are cast as unretained.
118224135Sdim    if (isGlobalVar(E))
119224135Sdim      if (E->getSubExpr()->getType()->isPointerType()) {
120224135Sdim        castToObjCObject(E, /*retained=*/false);
121224135Sdim        return;
122224135Sdim      }
123224135Sdim
124224135Sdim    // If the cast is directly over the result of a Core Foundation function
125224135Sdim    // try to figure out whether it should be cast as retained or unretained.
126224135Sdim    Expr *inner = E->IgnoreParenCasts();
127224135Sdim    if (CallExpr *callE = dyn_cast<CallExpr>(inner)) {
128224135Sdim      if (FunctionDecl *FD = callE->getDirectCallee()) {
129224135Sdim        if (FD->getAttr<CFReturnsRetainedAttr>()) {
130224135Sdim          castToObjCObject(E, /*retained=*/true);
131224135Sdim          return;
132224135Sdim        }
133224135Sdim        if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
134224135Sdim          castToObjCObject(E, /*retained=*/false);
135224135Sdim          return;
136224135Sdim        }
137224135Sdim        if (FD->isGlobal() &&
138224135Sdim            FD->getIdentifier() &&
139224135Sdim            ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF",
140224135Sdim                                   FD->getIdentifier()->getName())) {
141224135Sdim          StringRef fname = FD->getIdentifier()->getName();
142224135Sdim          if (fname.endswith("Retain") ||
143224135Sdim              fname.find("Create") != StringRef::npos ||
144224135Sdim              fname.find("Copy") != StringRef::npos) {
145234353Sdim            // Do not migrate to couple of bridge transfer casts which
146234353Sdim            // cancel each other out. Leave it unchanged so error gets user
147234353Sdim            // attention instead.
148234353Sdim            if (FD->getName() == "CFRetain" &&
149234353Sdim                FD->getNumParams() == 1 &&
150234353Sdim                FD->getParent()->isTranslationUnit() &&
151249423Sdim                FD->hasExternalLinkage()) {
152234353Sdim              Expr *Arg = callE->getArg(0);
153234353Sdim              if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
154234353Sdim                const Expr *sub = ICE->getSubExpr();
155234353Sdim                QualType T = sub->getType();
156234353Sdim                if (T->isObjCObjectPointerType())
157234353Sdim                  return;
158234353Sdim              }
159234353Sdim            }
160224135Sdim            castToObjCObject(E, /*retained=*/true);
161224135Sdim            return;
162224135Sdim          }
163224135Sdim
164224135Sdim          if (fname.find("Get") != StringRef::npos) {
165224135Sdim            castToObjCObject(E, /*retained=*/false);
166224135Sdim            return;
167224135Sdim          }
168224135Sdim        }
169224135Sdim      }
170224135Sdim    }
171239462Sdim
172239462Sdim    // If returning an ivar or a member of an ivar from a +0 method, use
173239462Sdim    // a __bridge cast.
174239462Sdim    Expr *base = inner->IgnoreParenImpCasts();
175239462Sdim    while (isa<MemberExpr>(base))
176239462Sdim      base = cast<MemberExpr>(base)->getBase()->IgnoreParenImpCasts();
177239462Sdim    if (isa<ObjCIvarRefExpr>(base) &&
178239462Sdim        isa<ReturnStmt>(StmtMap->getParentIgnoreParenCasts(E))) {
179239462Sdim      if (ObjCMethodDecl *method = dyn_cast_or_null<ObjCMethodDecl>(ParentD)) {
180239462Sdim        if (!method->hasAttr<NSReturnsRetainedAttr>()) {
181239462Sdim          castToObjCObject(E, /*retained=*/false);
182239462Sdim          return;
183239462Sdim        }
184239462Sdim      }
185239462Sdim    }
186224135Sdim  }
187224135Sdim
188224135Sdim  void castToObjCObject(CastExpr *E, bool retained) {
189224135Sdim    rewriteToBridgedCast(E, retained ? OBC_BridgeTransfer : OBC_Bridge);
190224135Sdim  }
191224135Sdim
192224135Sdim  void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) {
193226633Sdim    Transaction Trans(Pass.TA);
194226633Sdim    rewriteToBridgedCast(E, Kind, Trans);
195226633Sdim  }
196226633Sdim
197226633Sdim  void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind,
198226633Sdim                            Transaction &Trans) {
199224135Sdim    TransformActions &TA = Pass.TA;
200224135Sdim
201224135Sdim    // We will remove the compiler diagnostic.
202224135Sdim    if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast,
203224135Sdim                          diag::err_arc_cast_requires_bridge,
204226633Sdim                          E->getLocStart())) {
205226633Sdim      Trans.abort();
206224135Sdim      return;
207226633Sdim    }
208224135Sdim
209224135Sdim    StringRef bridge;
210224135Sdim    switch(Kind) {
211224135Sdim    case OBC_Bridge:
212224135Sdim      bridge = "__bridge "; break;
213224135Sdim    case OBC_BridgeTransfer:
214224135Sdim      bridge = "__bridge_transfer "; break;
215224135Sdim    case OBC_BridgeRetained:
216224135Sdim      bridge = "__bridge_retained "; break;
217224135Sdim    }
218224135Sdim
219224135Sdim    TA.clearDiagnostic(diag::err_arc_mismatched_cast,
220224135Sdim                       diag::err_arc_cast_requires_bridge,
221224135Sdim                       E->getLocStart());
222239462Sdim    if (Kind == OBC_Bridge || !Pass.CFBridgingFunctionsDefined()) {
223239462Sdim      if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(E)) {
224239462Sdim        TA.insertAfterToken(CCE->getLParenLoc(), bridge);
225239462Sdim      } else {
226239462Sdim        SourceLocation insertLoc = E->getSubExpr()->getLocStart();
227239462Sdim        SmallString<128> newCast;
228239462Sdim        newCast += '(';
229239462Sdim        newCast += bridge;
230239462Sdim        newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
231239462Sdim        newCast += ')';
232239462Sdim
233239462Sdim        if (isa<ParenExpr>(E->getSubExpr())) {
234239462Sdim          TA.insert(insertLoc, newCast.str());
235239462Sdim        } else {
236239462Sdim          newCast += '(';
237239462Sdim          TA.insert(insertLoc, newCast.str());
238239462Sdim          TA.insertAfterToken(E->getLocEnd(), ")");
239239462Sdim        }
240239462Sdim      }
241224135Sdim    } else {
242239462Sdim      assert(Kind == OBC_BridgeTransfer || Kind == OBC_BridgeRetained);
243239462Sdim      SmallString<32> BridgeCall;
244224135Sdim
245239462Sdim      Expr *WrapE = E->getSubExpr();
246239462Sdim      SourceLocation InsertLoc = WrapE->getLocStart();
247239462Sdim
248239462Sdim      SourceManager &SM = Pass.Ctx.getSourceManager();
249239462Sdim      char PrevChar = *SM.getCharacterData(InsertLoc.getLocWithOffset(-1));
250239462Sdim      if (Lexer::isIdentifierBodyChar(PrevChar, Pass.Ctx.getLangOpts()))
251239462Sdim        BridgeCall += ' ';
252239462Sdim
253239462Sdim      if (Kind == OBC_BridgeTransfer)
254239462Sdim        BridgeCall += "CFBridgingRelease";
255239462Sdim      else
256239462Sdim        BridgeCall += "CFBridgingRetain";
257239462Sdim
258239462Sdim      if (isa<ParenExpr>(WrapE)) {
259239462Sdim        TA.insert(InsertLoc, BridgeCall);
260224135Sdim      } else {
261239462Sdim        BridgeCall += '(';
262239462Sdim        TA.insert(InsertLoc, BridgeCall);
263239462Sdim        TA.insertAfterToken(WrapE->getLocEnd(), ")");
264224135Sdim      }
265224135Sdim    }
266224135Sdim  }
267224135Sdim
268226633Sdim  void rewriteCastForCFRetain(CastExpr *castE, CallExpr *callE) {
269226633Sdim    Transaction Trans(Pass.TA);
270226633Sdim    Pass.TA.replace(callE->getSourceRange(), callE->getArg(0)->getSourceRange());
271226633Sdim    rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans);
272226633Sdim  }
273226633Sdim
274249423Sdim  void getBlockMacroRanges(CastExpr *E, SourceRange &Outer, SourceRange &Inner) {
275249423Sdim    SourceManager &SM = Pass.Ctx.getSourceManager();
276249423Sdim    SourceLocation Loc = E->getExprLoc();
277249423Sdim    assert(Loc.isMacroID());
278249423Sdim    SourceLocation MacroBegin, MacroEnd;
279249423Sdim    llvm::tie(MacroBegin, MacroEnd) = SM.getImmediateExpansionRange(Loc);
280249423Sdim    SourceRange SubRange = E->getSubExpr()->IgnoreParenImpCasts()->getSourceRange();
281249423Sdim    SourceLocation InnerBegin = SM.getImmediateMacroCallerLoc(SubRange.getBegin());
282249423Sdim    SourceLocation InnerEnd = SM.getImmediateMacroCallerLoc(SubRange.getEnd());
283249423Sdim
284249423Sdim    Outer = SourceRange(MacroBegin, MacroEnd);
285249423Sdim    Inner = SourceRange(InnerBegin, InnerEnd);
286249423Sdim  }
287249423Sdim
288249423Sdim  void rewriteBlockCopyMacro(CastExpr *E) {
289249423Sdim    SourceRange OuterRange, InnerRange;
290249423Sdim    getBlockMacroRanges(E, OuterRange, InnerRange);
291249423Sdim
292249423Sdim    Transaction Trans(Pass.TA);
293249423Sdim    Pass.TA.replace(OuterRange, InnerRange);
294249423Sdim    Pass.TA.insert(InnerRange.getBegin(), "[");
295249423Sdim    Pass.TA.insertAfterToken(InnerRange.getEnd(), " copy]");
296249423Sdim    Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast,
297249423Sdim                            diag::err_arc_cast_requires_bridge,
298249423Sdim                            OuterRange);
299249423Sdim  }
300249423Sdim
301249423Sdim  void removeBlockReleaseMacro(CastExpr *E) {
302249423Sdim    SourceRange OuterRange, InnerRange;
303249423Sdim    getBlockMacroRanges(E, OuterRange, InnerRange);
304249423Sdim
305249423Sdim    Transaction Trans(Pass.TA);
306249423Sdim    Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast,
307249423Sdim                            diag::err_arc_cast_requires_bridge,
308249423Sdim                            OuterRange);
309249423Sdim    if (!hasSideEffects(E, Pass.Ctx)) {
310249423Sdim      if (tryRemoving(cast<Expr>(StmtMap->getParentIgnoreParenCasts(E))))
311249423Sdim        return;
312249423Sdim    }
313249423Sdim    Pass.TA.replace(OuterRange, InnerRange);
314249423Sdim  }
315249423Sdim
316249423Sdim  bool tryRemoving(Expr *E) const {
317249423Sdim    if (!Removables) {
318249423Sdim      Removables.reset(new ExprSet);
319249423Sdim      collectRemovables(Body, *Removables);
320249423Sdim    }
321249423Sdim
322249423Sdim    if (Removables->count(E)) {
323249423Sdim      Pass.TA.removeStmt(E);
324249423Sdim      return true;
325249423Sdim    }
326249423Sdim
327249423Sdim    return false;
328249423Sdim  }
329249423Sdim
330224135Sdim  void transformObjCToNonObjCCast(CastExpr *E) {
331249423Sdim    SourceLocation CastLoc = E->getExprLoc();
332249423Sdim    if (CastLoc.isMacroID()) {
333249423Sdim      StringRef MacroName = Lexer::getImmediateMacroName(CastLoc,
334249423Sdim                                                    Pass.Ctx.getSourceManager(),
335249423Sdim                                                    Pass.Ctx.getLangOpts());
336249423Sdim      if (MacroName == "Block_copy") {
337249423Sdim        rewriteBlockCopyMacro(E);
338249423Sdim        return;
339249423Sdim      }
340249423Sdim      if (MacroName == "Block_release") {
341249423Sdim        removeBlockReleaseMacro(E);
342249423Sdim        return;
343249423Sdim      }
344249423Sdim    }
345249423Sdim
346224135Sdim    if (isSelf(E->getSubExpr()))
347224135Sdim      return rewriteToBridgedCast(E, OBC_Bridge);
348226633Sdim
349226633Sdim    CallExpr *callE;
350226633Sdim    if (isPassedToCFRetain(E, callE))
351226633Sdim      return rewriteCastForCFRetain(E, callE);
352226633Sdim
353226633Sdim    ObjCMethodFamily family = getFamilyOfMessage(E->getSubExpr());
354226633Sdim    if (family == OMF_retain)
355226633Sdim      return rewriteToBridgedCast(E, OBC_BridgeRetained);
356226633Sdim
357226633Sdim    if (family == OMF_autorelease || family == OMF_release) {
358226633Sdim      std::string err = "it is not safe to cast to '";
359226633Sdim      err += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
360226633Sdim      err += "' the result of '";
361226633Sdim      err += family == OMF_autorelease ? "autorelease" : "release";
362226633Sdim      err += "' message; a __bridge cast may result in a pointer to a "
363226633Sdim          "destroyed object and a __bridge_retained may leak the object";
364226633Sdim      Pass.TA.reportError(err, E->getLocStart(),
365226633Sdim                          E->getSubExpr()->getSourceRange());
366226633Sdim      Stmt *parent = E;
367226633Sdim      do {
368226633Sdim        parent = StmtMap->getParentIgnoreParenImpCasts(parent);
369226633Sdim      } while (parent && isa<ExprWithCleanups>(parent));
370226633Sdim
371226633Sdim      if (ReturnStmt *retS = dyn_cast_or_null<ReturnStmt>(parent)) {
372226633Sdim        std::string note = "remove the cast and change return type of function "
373226633Sdim            "to '";
374226633Sdim        note += E->getSubExpr()->getType().getAsString(Pass.Ctx.getPrintingPolicy());
375226633Sdim        note += "' to have the object automatically autoreleased";
376226633Sdim        Pass.TA.reportNote(note, retS->getLocStart());
377226633Sdim      }
378226633Sdim    }
379226633Sdim
380234353Sdim    Expr *subExpr = E->getSubExpr();
381234353Sdim
382234353Sdim    // Look through pseudo-object expressions.
383234353Sdim    if (PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(subExpr)) {
384234353Sdim      subExpr = pseudo->getResultExpr();
385234353Sdim      assert(subExpr && "no result for pseudo-object of non-void type?");
386234353Sdim    }
387234353Sdim
388234353Sdim    if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(subExpr)) {
389226633Sdim      if (implCE->getCastKind() == CK_ARCConsumeObject)
390226633Sdim        return rewriteToBridgedCast(E, OBC_BridgeRetained);
391226633Sdim      if (implCE->getCastKind() == CK_ARCReclaimReturnedObject)
392226633Sdim        return rewriteToBridgedCast(E, OBC_Bridge);
393226633Sdim    }
394226633Sdim
395226633Sdim    bool isConsumed = false;
396226633Sdim    if (isPassedToCParamWithKnownOwnership(E, isConsumed))
397226633Sdim      return rewriteToBridgedCast(E, isConsumed ? OBC_BridgeRetained
398226633Sdim                                                : OBC_Bridge);
399224135Sdim  }
400224135Sdim
401226633Sdim  static ObjCMethodFamily getFamilyOfMessage(Expr *E) {
402226633Sdim    E = E->IgnoreParenCasts();
403226633Sdim    if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
404226633Sdim      return ME->getMethodFamily();
405226633Sdim
406226633Sdim    return OMF_None;
407226633Sdim  }
408226633Sdim
409226633Sdim  bool isPassedToCFRetain(Expr *E, CallExpr *&callE) const {
410226633Sdim    if ((callE = dyn_cast_or_null<CallExpr>(
411226633Sdim                                     StmtMap->getParentIgnoreParenImpCasts(E))))
412226633Sdim      if (FunctionDecl *
413226633Sdim            FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl()))
414226633Sdim        if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 &&
415226633Sdim            FD->getParent()->isTranslationUnit() &&
416249423Sdim            FD->hasExternalLinkage())
417226633Sdim          return true;
418226633Sdim
419226633Sdim    return false;
420226633Sdim  }
421226633Sdim
422226633Sdim  bool isPassedToCParamWithKnownOwnership(Expr *E, bool &isConsumed) const {
423226633Sdim    if (CallExpr *callE = dyn_cast_or_null<CallExpr>(
424226633Sdim                                     StmtMap->getParentIgnoreParenImpCasts(E)))
425226633Sdim      if (FunctionDecl *
426226633Sdim            FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) {
427226633Sdim        unsigned i = 0;
428226633Sdim        for (unsigned e = callE->getNumArgs(); i != e; ++i) {
429226633Sdim          Expr *arg = callE->getArg(i);
430226633Sdim          if (arg == E || arg->IgnoreParenImpCasts() == E)
431226633Sdim            break;
432226633Sdim        }
433249423Sdim        if (i < callE->getNumArgs() && i < FD->getNumParams()) {
434226633Sdim          ParmVarDecl *PD = FD->getParamDecl(i);
435226633Sdim          if (PD->getAttr<CFConsumedAttr>()) {
436226633Sdim            isConsumed = true;
437226633Sdim            return true;
438226633Sdim          }
439226633Sdim        }
440226633Sdim      }
441226633Sdim
442226633Sdim    return false;
443226633Sdim  }
444226633Sdim
445226633Sdim  bool isSelf(Expr *E) const {
446224135Sdim    E = E->IgnoreParenLValueCasts();
447224135Sdim    if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
448226633Sdim      if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
449226633Sdim        if (IPD->getIdentifier() == SelfII)
450226633Sdim          return true;
451226633Sdim
452224135Sdim    return false;
453224135Sdim  }
454224135Sdim};
455224135Sdim
456224135Sdim} // end anonymous namespace
457224135Sdim
458224135Sdimvoid trans::rewriteUnbridgedCasts(MigrationPass &pass) {
459226633Sdim  BodyTransform<UnbridgedCastRewriter> trans(pass);
460224135Sdim  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
461224135Sdim}
462