1249423Sdim//===--- TransUnbridgedCasts.cpp - Transformations to ARC mode ------------===// 2224135Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6224135Sdim// 7224135Sdim//===----------------------------------------------------------------------===// 8224135Sdim// 9224135Sdim// rewriteUnbridgedCasts: 10224135Sdim// 11224135Sdim// A cast of non-objc pointer to an objc one is checked. If the non-objc pointer 12224135Sdim// is from a file-level variable, __bridge cast is used to convert it. 13224135Sdim// For the result of a function call that we know is +1/+0, 14239462Sdim// __bridge/CFBridgingRelease is used. 15224135Sdim// 16224135Sdim// NSString *str = (NSString *)kUTTypePlainText; 17224135Sdim// str = b ? kUTTypeRTF : kUTTypePlainText; 18224135Sdim// NSString *_uuidString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault, 19224135Sdim// _uuid); 20224135Sdim// ----> 21224135Sdim// NSString *str = (__bridge NSString *)kUTTypePlainText; 22224135Sdim// str = (__bridge NSString *)(b ? kUTTypeRTF : kUTTypePlainText); 23239462Sdim// NSString *_uuidString = (NSString *) 24239462Sdim// CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, _uuid)); 25224135Sdim// 26224135Sdim// For a C pointer to ObjC, for casting 'self', __bridge is used. 27224135Sdim// 28224135Sdim// CFStringRef str = (CFStringRef)self; 29224135Sdim// ----> 30224135Sdim// CFStringRef str = (__bridge CFStringRef)self; 31224135Sdim// 32249423Sdim// Uses of Block_copy/Block_release macros are rewritten: 33249423Sdim// 34249423Sdim// c = Block_copy(b); 35249423Sdim// Block_release(c); 36249423Sdim// ----> 37249423Sdim// c = [b copy]; 38249423Sdim// <removed> 39249423Sdim// 40224135Sdim//===----------------------------------------------------------------------===// 41224135Sdim 42224135Sdim#include "Transforms.h" 43224135Sdim#include "Internals.h" 44239462Sdim#include "clang/AST/ASTContext.h" 45249423Sdim#include "clang/AST/Attr.h" 46226633Sdim#include "clang/AST/ParentMap.h" 47249423Sdim#include "clang/Analysis/DomainSpecific/CocoaConventions.h" 48224135Sdim#include "clang/Basic/SourceManager.h" 49239462Sdim#include "clang/Lex/Lexer.h" 50239462Sdim#include "clang/Sema/SemaDiagnostic.h" 51234353Sdim#include "llvm/ADT/SmallString.h" 52224135Sdim 53224135Sdimusing namespace clang; 54224135Sdimusing namespace arcmt; 55224135Sdimusing namespace trans; 56224135Sdim 57224135Sdimnamespace { 58224135Sdim 59224135Sdimclass UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{ 60224135Sdim MigrationPass &Pass; 61224135Sdim IdentifierInfo *SelfII; 62276479Sdim std::unique_ptr<ParentMap> StmtMap; 63239462Sdim Decl *ParentD; 64249423Sdim Stmt *Body; 65276479Sdim mutable std::unique_ptr<ExprSet> Removables; 66226633Sdim 67224135Sdimpublic: 68276479Sdim UnbridgedCastRewriter(MigrationPass &pass) 69276479Sdim : Pass(pass), ParentD(nullptr), Body(nullptr) { 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 80261991Sdim bool TraverseBlockDecl(BlockDecl *D) { 81261991Sdim // ParentMap does not enter into a BlockDecl to record its stmts, so use a 82261991Sdim // new UnbridgedCastRewriter to handle the block. 83261991Sdim UnbridgedCastRewriter(Pass).transformBody(D->getBody(), D); 84261991Sdim return true; 85261991Sdim } 86261991Sdim 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; 99341825Sdim 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()) { 136276479Sdim if (FD->hasAttr<CFReturnsRetainedAttr>()) { 137224135Sdim castToObjCObject(E, /*retained=*/true); 138224135Sdim return; 139224135Sdim } 140276479Sdim if (FD->hasAttr<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. 155341825Sdim if (FD->getName() == "CFRetain" && 156234353Sdim FD->getNumParams() == 1 && 157234353Sdim FD->getParent()->isTranslationUnit() && 158261991Sdim 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, 211344779Sdim E->getBeginLoc())) { 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, 227344779Sdim diag::err_arc_cast_requires_bridge, E->getBeginLoc()); 228239462Sdim if (Kind == OBC_Bridge || !Pass.CFBridgingFunctionsDefined()) { 229239462Sdim if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(E)) { 230239462Sdim TA.insertAfterToken(CCE->getLParenLoc(), bridge); 231239462Sdim } else { 232344779Sdim SourceLocation insertLoc = E->getSubExpr()->getBeginLoc(); 233239462Sdim SmallString<128> newCast; 234239462Sdim newCast += '('; 235239462Sdim newCast += bridge; 236239462Sdim newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy()); 237239462Sdim newCast += ')'; 238239462Sdim 239239462Sdim if (isa<ParenExpr>(E->getSubExpr())) { 240239462Sdim TA.insert(insertLoc, newCast.str()); 241239462Sdim } else { 242239462Sdim newCast += '('; 243239462Sdim TA.insert(insertLoc, newCast.str()); 244344779Sdim TA.insertAfterToken(E->getEndLoc(), ")"); 245239462Sdim } 246239462Sdim } 247224135Sdim } else { 248239462Sdim assert(Kind == OBC_BridgeTransfer || Kind == OBC_BridgeRetained); 249239462Sdim SmallString<32> BridgeCall; 250224135Sdim 251239462Sdim Expr *WrapE = E->getSubExpr(); 252344779Sdim SourceLocation InsertLoc = WrapE->getBeginLoc(); 253239462Sdim 254239462Sdim SourceManager &SM = Pass.Ctx.getSourceManager(); 255239462Sdim char PrevChar = *SM.getCharacterData(InsertLoc.getLocWithOffset(-1)); 256239462Sdim if (Lexer::isIdentifierBodyChar(PrevChar, Pass.Ctx.getLangOpts())) 257239462Sdim BridgeCall += ' '; 258239462Sdim 259239462Sdim if (Kind == OBC_BridgeTransfer) 260239462Sdim BridgeCall += "CFBridgingRelease"; 261239462Sdim else 262239462Sdim BridgeCall += "CFBridgingRetain"; 263239462Sdim 264239462Sdim if (isa<ParenExpr>(WrapE)) { 265239462Sdim TA.insert(InsertLoc, BridgeCall); 266224135Sdim } else { 267239462Sdim BridgeCall += '('; 268239462Sdim TA.insert(InsertLoc, BridgeCall); 269344779Sdim TA.insertAfterToken(WrapE->getEndLoc(), ")"); 270224135Sdim } 271224135Sdim } 272224135Sdim } 273224135Sdim 274226633Sdim void rewriteCastForCFRetain(CastExpr *castE, CallExpr *callE) { 275226633Sdim Transaction Trans(Pass.TA); 276226633Sdim Pass.TA.replace(callE->getSourceRange(), callE->getArg(0)->getSourceRange()); 277226633Sdim rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans); 278226633Sdim } 279226633Sdim 280249423Sdim void getBlockMacroRanges(CastExpr *E, SourceRange &Outer, SourceRange &Inner) { 281249423Sdim SourceManager &SM = Pass.Ctx.getSourceManager(); 282249423Sdim SourceLocation Loc = E->getExprLoc(); 283249423Sdim assert(Loc.isMacroID()); 284341825Sdim CharSourceRange MacroRange = SM.getImmediateExpansionRange(Loc); 285249423Sdim SourceRange SubRange = E->getSubExpr()->IgnoreParenImpCasts()->getSourceRange(); 286249423Sdim SourceLocation InnerBegin = SM.getImmediateMacroCallerLoc(SubRange.getBegin()); 287249423Sdim SourceLocation InnerEnd = SM.getImmediateMacroCallerLoc(SubRange.getEnd()); 288249423Sdim 289341825Sdim Outer = MacroRange.getAsRange(); 290249423Sdim Inner = SourceRange(InnerBegin, InnerEnd); 291249423Sdim } 292249423Sdim 293249423Sdim void rewriteBlockCopyMacro(CastExpr *E) { 294249423Sdim SourceRange OuterRange, InnerRange; 295249423Sdim getBlockMacroRanges(E, OuterRange, InnerRange); 296249423Sdim 297249423Sdim Transaction Trans(Pass.TA); 298249423Sdim Pass.TA.replace(OuterRange, InnerRange); 299249423Sdim Pass.TA.insert(InnerRange.getBegin(), "["); 300249423Sdim Pass.TA.insertAfterToken(InnerRange.getEnd(), " copy]"); 301249423Sdim Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast, 302249423Sdim diag::err_arc_cast_requires_bridge, 303249423Sdim OuterRange); 304249423Sdim } 305249423Sdim 306249423Sdim void removeBlockReleaseMacro(CastExpr *E) { 307249423Sdim SourceRange OuterRange, InnerRange; 308249423Sdim getBlockMacroRanges(E, OuterRange, InnerRange); 309249423Sdim 310249423Sdim Transaction Trans(Pass.TA); 311249423Sdim Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast, 312249423Sdim diag::err_arc_cast_requires_bridge, 313249423Sdim OuterRange); 314249423Sdim if (!hasSideEffects(E, Pass.Ctx)) { 315249423Sdim if (tryRemoving(cast<Expr>(StmtMap->getParentIgnoreParenCasts(E)))) 316249423Sdim return; 317249423Sdim } 318249423Sdim Pass.TA.replace(OuterRange, InnerRange); 319249423Sdim } 320249423Sdim 321249423Sdim bool tryRemoving(Expr *E) const { 322249423Sdim if (!Removables) { 323249423Sdim Removables.reset(new ExprSet); 324249423Sdim collectRemovables(Body, *Removables); 325249423Sdim } 326249423Sdim 327249423Sdim if (Removables->count(E)) { 328249423Sdim Pass.TA.removeStmt(E); 329249423Sdim return true; 330249423Sdim } 331249423Sdim 332249423Sdim return false; 333249423Sdim } 334249423Sdim 335224135Sdim void transformObjCToNonObjCCast(CastExpr *E) { 336249423Sdim SourceLocation CastLoc = E->getExprLoc(); 337249423Sdim if (CastLoc.isMacroID()) { 338249423Sdim StringRef MacroName = Lexer::getImmediateMacroName(CastLoc, 339249423Sdim Pass.Ctx.getSourceManager(), 340249423Sdim Pass.Ctx.getLangOpts()); 341249423Sdim if (MacroName == "Block_copy") { 342249423Sdim rewriteBlockCopyMacro(E); 343249423Sdim return; 344249423Sdim } 345249423Sdim if (MacroName == "Block_release") { 346249423Sdim removeBlockReleaseMacro(E); 347249423Sdim return; 348249423Sdim } 349249423Sdim } 350249423Sdim 351224135Sdim if (isSelf(E->getSubExpr())) 352224135Sdim return rewriteToBridgedCast(E, OBC_Bridge); 353226633Sdim 354226633Sdim CallExpr *callE; 355226633Sdim if (isPassedToCFRetain(E, callE)) 356226633Sdim return rewriteCastForCFRetain(E, callE); 357226633Sdim 358226633Sdim ObjCMethodFamily family = getFamilyOfMessage(E->getSubExpr()); 359226633Sdim if (family == OMF_retain) 360226633Sdim return rewriteToBridgedCast(E, OBC_BridgeRetained); 361226633Sdim 362226633Sdim if (family == OMF_autorelease || family == OMF_release) { 363226633Sdim std::string err = "it is not safe to cast to '"; 364226633Sdim err += E->getType().getAsString(Pass.Ctx.getPrintingPolicy()); 365226633Sdim err += "' the result of '"; 366226633Sdim err += family == OMF_autorelease ? "autorelease" : "release"; 367226633Sdim err += "' message; a __bridge cast may result in a pointer to a " 368226633Sdim "destroyed object and a __bridge_retained may leak the object"; 369344779Sdim Pass.TA.reportError(err, E->getBeginLoc(), 370226633Sdim E->getSubExpr()->getSourceRange()); 371226633Sdim Stmt *parent = E; 372226633Sdim do { 373226633Sdim parent = StmtMap->getParentIgnoreParenImpCasts(parent); 374344779Sdim } while (parent && isa<FullExpr>(parent)); 375226633Sdim 376226633Sdim if (ReturnStmt *retS = dyn_cast_or_null<ReturnStmt>(parent)) { 377226633Sdim std::string note = "remove the cast and change return type of function " 378226633Sdim "to '"; 379226633Sdim note += E->getSubExpr()->getType().getAsString(Pass.Ctx.getPrintingPolicy()); 380226633Sdim note += "' to have the object automatically autoreleased"; 381344779Sdim Pass.TA.reportNote(note, retS->getBeginLoc()); 382226633Sdim } 383226633Sdim } 384226633Sdim 385234353Sdim Expr *subExpr = E->getSubExpr(); 386234353Sdim 387234353Sdim // Look through pseudo-object expressions. 388234353Sdim if (PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(subExpr)) { 389234353Sdim subExpr = pseudo->getResultExpr(); 390234353Sdim assert(subExpr && "no result for pseudo-object of non-void type?"); 391234353Sdim } 392234353Sdim 393234353Sdim if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(subExpr)) { 394226633Sdim if (implCE->getCastKind() == CK_ARCConsumeObject) 395226633Sdim return rewriteToBridgedCast(E, OBC_BridgeRetained); 396226633Sdim if (implCE->getCastKind() == CK_ARCReclaimReturnedObject) 397226633Sdim return rewriteToBridgedCast(E, OBC_Bridge); 398226633Sdim } 399226633Sdim 400226633Sdim bool isConsumed = false; 401226633Sdim if (isPassedToCParamWithKnownOwnership(E, isConsumed)) 402226633Sdim return rewriteToBridgedCast(E, isConsumed ? OBC_BridgeRetained 403226633Sdim : OBC_Bridge); 404224135Sdim } 405224135Sdim 406226633Sdim static ObjCMethodFamily getFamilyOfMessage(Expr *E) { 407226633Sdim E = E->IgnoreParenCasts(); 408226633Sdim if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) 409226633Sdim return ME->getMethodFamily(); 410226633Sdim 411226633Sdim return OMF_None; 412226633Sdim } 413226633Sdim 414226633Sdim bool isPassedToCFRetain(Expr *E, CallExpr *&callE) const { 415226633Sdim if ((callE = dyn_cast_or_null<CallExpr>( 416226633Sdim StmtMap->getParentIgnoreParenImpCasts(E)))) 417226633Sdim if (FunctionDecl * 418226633Sdim FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) 419226633Sdim if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 && 420226633Sdim FD->getParent()->isTranslationUnit() && 421261991Sdim FD->isExternallyVisible()) 422226633Sdim return true; 423226633Sdim 424226633Sdim return false; 425226633Sdim } 426226633Sdim 427226633Sdim bool isPassedToCParamWithKnownOwnership(Expr *E, bool &isConsumed) const { 428226633Sdim if (CallExpr *callE = dyn_cast_or_null<CallExpr>( 429226633Sdim StmtMap->getParentIgnoreParenImpCasts(E))) 430226633Sdim if (FunctionDecl * 431226633Sdim FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) { 432226633Sdim unsigned i = 0; 433226633Sdim for (unsigned e = callE->getNumArgs(); i != e; ++i) { 434226633Sdim Expr *arg = callE->getArg(i); 435226633Sdim if (arg == E || arg->IgnoreParenImpCasts() == E) 436226633Sdim break; 437226633Sdim } 438249423Sdim if (i < callE->getNumArgs() && i < FD->getNumParams()) { 439226633Sdim ParmVarDecl *PD = FD->getParamDecl(i); 440276479Sdim if (PD->hasAttr<CFConsumedAttr>()) { 441226633Sdim isConsumed = true; 442226633Sdim return true; 443226633Sdim } 444226633Sdim } 445226633Sdim } 446226633Sdim 447226633Sdim return false; 448226633Sdim } 449226633Sdim 450226633Sdim bool isSelf(Expr *E) const { 451224135Sdim E = E->IgnoreParenLValueCasts(); 452224135Sdim if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) 453226633Sdim if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(DRE->getDecl())) 454226633Sdim if (IPD->getIdentifier() == SelfII) 455226633Sdim return true; 456226633Sdim 457224135Sdim return false; 458224135Sdim } 459224135Sdim}; 460224135Sdim 461224135Sdim} // end anonymous namespace 462224135Sdim 463224135Sdimvoid trans::rewriteUnbridgedCasts(MigrationPass &pass) { 464226633Sdim BodyTransform<UnbridgedCastRewriter> trans(pass); 465224135Sdim trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 466224135Sdim} 467