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