123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 |
- //===--- TransUnbridgedCasts.cpp - Transformations to ARC mode ------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // rewriteUnbridgedCasts:
- //
- // A cast of non-objc pointer to an objc one is checked. If the non-objc pointer
- // is from a file-level variable, __bridge cast is used to convert it.
- // For the result of a function call that we know is +1/+0,
- // __bridge/CFBridgingRelease is used.
- //
- // NSString *str = (NSString *)kUTTypePlainText;
- // str = b ? kUTTypeRTF : kUTTypePlainText;
- // NSString *_uuidString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault,
- // _uuid);
- // ---->
- // NSString *str = (__bridge NSString *)kUTTypePlainText;
- // str = (__bridge NSString *)(b ? kUTTypeRTF : kUTTypePlainText);
- // NSString *_uuidString = (NSString *)
- // CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, _uuid));
- //
- // For a C pointer to ObjC, for casting 'self', __bridge is used.
- //
- // CFStringRef str = (CFStringRef)self;
- // ---->
- // CFStringRef str = (__bridge CFStringRef)self;
- //
- // Uses of Block_copy/Block_release macros are rewritten:
- //
- // c = Block_copy(b);
- // Block_release(c);
- // ---->
- // c = [b copy];
- // <removed>
- //
- //===----------------------------------------------------------------------===//
- #include "Transforms.h"
- #include "Internals.h"
- #include "clang/AST/ASTContext.h"
- #include "clang/AST/Attr.h"
- #include "clang/AST/ParentMap.h"
- #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
- #include "clang/Basic/SourceManager.h"
- #include "clang/Lex/Lexer.h"
- #include "clang/Sema/SemaDiagnostic.h"
- #include "llvm/ADT/SmallString.h"
- using namespace clang;
- using namespace arcmt;
- using namespace trans;
- namespace {
- class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
- MigrationPass &Pass;
- IdentifierInfo *SelfII;
- std::unique_ptr<ParentMap> StmtMap;
- Decl *ParentD;
- Stmt *Body;
- mutable std::unique_ptr<ExprSet> Removables;
- public:
- UnbridgedCastRewriter(MigrationPass &pass)
- : Pass(pass), ParentD(nullptr), Body(nullptr) {
- SelfII = &Pass.Ctx.Idents.get("self");
- }
- void transformBody(Stmt *body, Decl *ParentD) {
- this->ParentD = ParentD;
- Body = body;
- StmtMap.reset(new ParentMap(body));
- TraverseStmt(body);
- }
- bool TraverseBlockDecl(BlockDecl *D) {
- // ParentMap does not enter into a BlockDecl to record its stmts, so use a
- // new UnbridgedCastRewriter to handle the block.
- UnbridgedCastRewriter(Pass).transformBody(D->getBody(), D);
- return true;
- }
- bool VisitCastExpr(CastExpr *E) {
- if (E->getCastKind() != CK_CPointerToObjCPointerCast &&
- E->getCastKind() != CK_BitCast &&
- E->getCastKind() != CK_AnyPointerToBlockPointerCast)
- return true;
- QualType castType = E->getType();
- Expr *castExpr = E->getSubExpr();
- QualType castExprType = castExpr->getType();
- if (castType->isObjCRetainableType() == castExprType->isObjCRetainableType())
- return true;
- bool exprRetainable = castExprType->isObjCIndirectLifetimeType();
- bool castRetainable = castType->isObjCIndirectLifetimeType();
- if (exprRetainable == castRetainable) return true;
- if (castExpr->isNullPointerConstant(Pass.Ctx,
- Expr::NPC_ValueDependentIsNull))
- return true;
- SourceLocation loc = castExpr->getExprLoc();
- if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc))
- return true;
- if (castType->isObjCRetainableType())
- transformNonObjCToObjCCast(E);
- else
- transformObjCToNonObjCCast(E);
- return true;
- }
- private:
- void transformNonObjCToObjCCast(CastExpr *E) {
- if (!E) return;
- // Global vars are assumed that are cast as unretained.
- if (isGlobalVar(E))
- if (E->getSubExpr()->getType()->isPointerType()) {
- castToObjCObject(E, /*retained=*/false);
- return;
- }
- // If the cast is directly over the result of a Core Foundation function
- // try to figure out whether it should be cast as retained or unretained.
- Expr *inner = E->IgnoreParenCasts();
- if (CallExpr *callE = dyn_cast<CallExpr>(inner)) {
- if (FunctionDecl *FD = callE->getDirectCallee()) {
- if (FD->hasAttr<CFReturnsRetainedAttr>()) {
- castToObjCObject(E, /*retained=*/true);
- return;
- }
- if (FD->hasAttr<CFReturnsNotRetainedAttr>()) {
- castToObjCObject(E, /*retained=*/false);
- return;
- }
- if (FD->isGlobal() &&
- FD->getIdentifier() &&
- ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF",
- FD->getIdentifier()->getName())) {
- StringRef fname = FD->getIdentifier()->getName();
- if (fname.endswith("Retain") || fname.contains("Create") ||
- fname.contains("Copy")) {
- // Do not migrate to couple of bridge transfer casts which
- // cancel each other out. Leave it unchanged so error gets user
- // attention instead.
- if (FD->getName() == "CFRetain" &&
- FD->getNumParams() == 1 &&
- FD->getParent()->isTranslationUnit() &&
- FD->isExternallyVisible()) {
- Expr *Arg = callE->getArg(0);
- if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
- const Expr *sub = ICE->getSubExpr();
- QualType T = sub->getType();
- if (T->isObjCObjectPointerType())
- return;
- }
- }
- castToObjCObject(E, /*retained=*/true);
- return;
- }
- if (fname.contains("Get")) {
- castToObjCObject(E, /*retained=*/false);
- return;
- }
- }
- }
- }
- // If returning an ivar or a member of an ivar from a +0 method, use
- // a __bridge cast.
- Expr *base = inner->IgnoreParenImpCasts();
- while (isa<MemberExpr>(base))
- base = cast<MemberExpr>(base)->getBase()->IgnoreParenImpCasts();
- if (isa<ObjCIvarRefExpr>(base) &&
- isa<ReturnStmt>(StmtMap->getParentIgnoreParenCasts(E))) {
- if (ObjCMethodDecl *method = dyn_cast_or_null<ObjCMethodDecl>(ParentD)) {
- if (!method->hasAttr<NSReturnsRetainedAttr>()) {
- castToObjCObject(E, /*retained=*/false);
- return;
- }
- }
- }
- }
- void castToObjCObject(CastExpr *E, bool retained) {
- rewriteToBridgedCast(E, retained ? OBC_BridgeTransfer : OBC_Bridge);
- }
- void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) {
- Transaction Trans(Pass.TA);
- rewriteToBridgedCast(E, Kind, Trans);
- }
- void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind,
- Transaction &Trans) {
- TransformActions &TA = Pass.TA;
- // We will remove the compiler diagnostic.
- if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast,
- diag::err_arc_cast_requires_bridge,
- E->getBeginLoc())) {
- Trans.abort();
- return;
- }
- StringRef bridge;
- switch(Kind) {
- case OBC_Bridge:
- bridge = "__bridge "; break;
- case OBC_BridgeTransfer:
- bridge = "__bridge_transfer "; break;
- case OBC_BridgeRetained:
- bridge = "__bridge_retained "; break;
- }
- TA.clearDiagnostic(diag::err_arc_mismatched_cast,
- diag::err_arc_cast_requires_bridge, E->getBeginLoc());
- if (Kind == OBC_Bridge || !Pass.CFBridgingFunctionsDefined()) {
- if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(E)) {
- TA.insertAfterToken(CCE->getLParenLoc(), bridge);
- } else {
- SourceLocation insertLoc = E->getSubExpr()->getBeginLoc();
- SmallString<128> newCast;
- newCast += '(';
- newCast += bridge;
- newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
- newCast += ')';
- if (isa<ParenExpr>(E->getSubExpr())) {
- TA.insert(insertLoc, newCast.str());
- } else {
- newCast += '(';
- TA.insert(insertLoc, newCast.str());
- TA.insertAfterToken(E->getEndLoc(), ")");
- }
- }
- } else {
- assert(Kind == OBC_BridgeTransfer || Kind == OBC_BridgeRetained);
- SmallString<32> BridgeCall;
- Expr *WrapE = E->getSubExpr();
- SourceLocation InsertLoc = WrapE->getBeginLoc();
- SourceManager &SM = Pass.Ctx.getSourceManager();
- char PrevChar = *SM.getCharacterData(InsertLoc.getLocWithOffset(-1));
- if (Lexer::isAsciiIdentifierContinueChar(PrevChar,
- Pass.Ctx.getLangOpts()))
- BridgeCall += ' ';
- if (Kind == OBC_BridgeTransfer)
- BridgeCall += "CFBridgingRelease";
- else
- BridgeCall += "CFBridgingRetain";
- if (isa<ParenExpr>(WrapE)) {
- TA.insert(InsertLoc, BridgeCall);
- } else {
- BridgeCall += '(';
- TA.insert(InsertLoc, BridgeCall);
- TA.insertAfterToken(WrapE->getEndLoc(), ")");
- }
- }
- }
- void rewriteCastForCFRetain(CastExpr *castE, CallExpr *callE) {
- Transaction Trans(Pass.TA);
- Pass.TA.replace(callE->getSourceRange(), callE->getArg(0)->getSourceRange());
- rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans);
- }
- void getBlockMacroRanges(CastExpr *E, SourceRange &Outer, SourceRange &Inner) {
- SourceManager &SM = Pass.Ctx.getSourceManager();
- SourceLocation Loc = E->getExprLoc();
- assert(Loc.isMacroID());
- CharSourceRange MacroRange = SM.getImmediateExpansionRange(Loc);
- SourceRange SubRange = E->getSubExpr()->IgnoreParenImpCasts()->getSourceRange();
- SourceLocation InnerBegin = SM.getImmediateMacroCallerLoc(SubRange.getBegin());
- SourceLocation InnerEnd = SM.getImmediateMacroCallerLoc(SubRange.getEnd());
- Outer = MacroRange.getAsRange();
- Inner = SourceRange(InnerBegin, InnerEnd);
- }
- void rewriteBlockCopyMacro(CastExpr *E) {
- SourceRange OuterRange, InnerRange;
- getBlockMacroRanges(E, OuterRange, InnerRange);
- Transaction Trans(Pass.TA);
- Pass.TA.replace(OuterRange, InnerRange);
- Pass.TA.insert(InnerRange.getBegin(), "[");
- Pass.TA.insertAfterToken(InnerRange.getEnd(), " copy]");
- Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast,
- diag::err_arc_cast_requires_bridge,
- OuterRange);
- }
- void removeBlockReleaseMacro(CastExpr *E) {
- SourceRange OuterRange, InnerRange;
- getBlockMacroRanges(E, OuterRange, InnerRange);
- Transaction Trans(Pass.TA);
- Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast,
- diag::err_arc_cast_requires_bridge,
- OuterRange);
- if (!hasSideEffects(E, Pass.Ctx)) {
- if (tryRemoving(cast<Expr>(StmtMap->getParentIgnoreParenCasts(E))))
- return;
- }
- Pass.TA.replace(OuterRange, InnerRange);
- }
- bool tryRemoving(Expr *E) const {
- if (!Removables) {
- Removables.reset(new ExprSet);
- collectRemovables(Body, *Removables);
- }
- if (Removables->count(E)) {
- Pass.TA.removeStmt(E);
- return true;
- }
- return false;
- }
- void transformObjCToNonObjCCast(CastExpr *E) {
- SourceLocation CastLoc = E->getExprLoc();
- if (CastLoc.isMacroID()) {
- StringRef MacroName = Lexer::getImmediateMacroName(CastLoc,
- Pass.Ctx.getSourceManager(),
- Pass.Ctx.getLangOpts());
- if (MacroName == "Block_copy") {
- rewriteBlockCopyMacro(E);
- return;
- }
- if (MacroName == "Block_release") {
- removeBlockReleaseMacro(E);
- return;
- }
- }
- if (isSelf(E->getSubExpr()))
- return rewriteToBridgedCast(E, OBC_Bridge);
- CallExpr *callE;
- if (isPassedToCFRetain(E, callE))
- return rewriteCastForCFRetain(E, callE);
- ObjCMethodFamily family = getFamilyOfMessage(E->getSubExpr());
- if (family == OMF_retain)
- return rewriteToBridgedCast(E, OBC_BridgeRetained);
- if (family == OMF_autorelease || family == OMF_release) {
- std::string err = "it is not safe to cast to '";
- err += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
- err += "' the result of '";
- err += family == OMF_autorelease ? "autorelease" : "release";
- err += "' message; a __bridge cast may result in a pointer to a "
- "destroyed object and a __bridge_retained may leak the object";
- Pass.TA.reportError(err, E->getBeginLoc(),
- E->getSubExpr()->getSourceRange());
- Stmt *parent = E;
- do {
- parent = StmtMap->getParentIgnoreParenImpCasts(parent);
- } while (parent && isa<FullExpr>(parent));
- if (ReturnStmt *retS = dyn_cast_or_null<ReturnStmt>(parent)) {
- std::string note = "remove the cast and change return type of function "
- "to '";
- note += E->getSubExpr()->getType().getAsString(Pass.Ctx.getPrintingPolicy());
- note += "' to have the object automatically autoreleased";
- Pass.TA.reportNote(note, retS->getBeginLoc());
- }
- }
- Expr *subExpr = E->getSubExpr();
- // Look through pseudo-object expressions.
- if (PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(subExpr)) {
- subExpr = pseudo->getResultExpr();
- assert(subExpr && "no result for pseudo-object of non-void type?");
- }
- if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(subExpr)) {
- if (implCE->getCastKind() == CK_ARCConsumeObject)
- return rewriteToBridgedCast(E, OBC_BridgeRetained);
- if (implCE->getCastKind() == CK_ARCReclaimReturnedObject)
- return rewriteToBridgedCast(E, OBC_Bridge);
- }
- bool isConsumed = false;
- if (isPassedToCParamWithKnownOwnership(E, isConsumed))
- return rewriteToBridgedCast(E, isConsumed ? OBC_BridgeRetained
- : OBC_Bridge);
- }
- static ObjCMethodFamily getFamilyOfMessage(Expr *E) {
- E = E->IgnoreParenCasts();
- if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
- return ME->getMethodFamily();
- return OMF_None;
- }
- bool isPassedToCFRetain(Expr *E, CallExpr *&callE) const {
- if ((callE = dyn_cast_or_null<CallExpr>(
- StmtMap->getParentIgnoreParenImpCasts(E))))
- if (FunctionDecl *
- FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl()))
- if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 &&
- FD->getParent()->isTranslationUnit() &&
- FD->isExternallyVisible())
- return true;
- return false;
- }
- bool isPassedToCParamWithKnownOwnership(Expr *E, bool &isConsumed) const {
- if (CallExpr *callE = dyn_cast_or_null<CallExpr>(
- StmtMap->getParentIgnoreParenImpCasts(E)))
- if (FunctionDecl *
- FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) {
- unsigned i = 0;
- for (unsigned e = callE->getNumArgs(); i != e; ++i) {
- Expr *arg = callE->getArg(i);
- if (arg == E || arg->IgnoreParenImpCasts() == E)
- break;
- }
- if (i < callE->getNumArgs() && i < FD->getNumParams()) {
- ParmVarDecl *PD = FD->getParamDecl(i);
- if (PD->hasAttr<CFConsumedAttr>()) {
- isConsumed = true;
- return true;
- }
- }
- }
- return false;
- }
- bool isSelf(Expr *E) const {
- E = E->IgnoreParenLValueCasts();
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
- if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
- if (IPD->getIdentifier() == SelfII)
- return true;
- return false;
- }
- };
- } // end anonymous namespace
- void trans::rewriteUnbridgedCasts(MigrationPass &pass) {
- BodyTransform<UnbridgedCastRewriter> trans(pass);
- trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
- }
|