diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp | 127 |
1 files changed, 118 insertions, 9 deletions
diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp index 1cacd6d..69fb2e8 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp @@ -36,25 +36,32 @@ #include "Internals.h" #include "clang/Analysis/DomainSpecific/CocoaConventions.h" #include "clang/Sema/SemaDiagnostic.h" +#include "clang/AST/ParentMap.h" #include "clang/Basic/SourceManager.h" using namespace clang; using namespace arcmt; using namespace trans; -using llvm::StringRef; namespace { class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{ MigrationPass &Pass; IdentifierInfo *SelfII; + llvm::OwningPtr<ParentMap> StmtMap; + public: UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass) { SelfII = &Pass.Ctx.Idents.get("self"); } + void transformBody(Stmt *body) { + StmtMap.reset(new ParentMap(body)); + TraverseStmt(body); + } + bool VisitCastExpr(CastExpr *E) { - if (E->getCastKind() != CK_AnyPointerToObjCPointerCast + if (E->getCastKind() != CK_CPointerToObjCPointerCast && E->getCastKind() != CK_BitCast) return true; @@ -139,13 +146,21 @@ private: } 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->getLocStart())) + E->getLocStart())) { + Trans.abort(); return; + } StringRef bridge; switch(Kind) { @@ -157,7 +172,6 @@ private: bridge = "__bridge_retained "; break; } - Transaction Trans(TA); TA.clearDiagnostic(diag::err_arc_mismatched_cast, diag::err_arc_cast_requires_bridge, E->getLocStart()); @@ -168,7 +182,7 @@ private: llvm::SmallString<128> newCast; newCast += '('; newCast += bridge; - newCast += E->getType().getAsString(Pass.Ctx.PrintingPolicy); + newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy()); newCast += ')'; if (isa<ParenExpr>(E->getSubExpr())) { @@ -181,16 +195,111 @@ private: } } + 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 transformObjCToNonObjCCast(CastExpr *E) { 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->getLocStart(), + E->getSubExpr()->getSourceRange()); + Stmt *parent = E; + do { + parent = StmtMap->getParentIgnoreParenImpCasts(parent); + } while (parent && isa<ExprWithCleanups>(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->getLocStart()); + } + } + + if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getSubExpr())){ + 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); } - bool isSelf(Expr *E) { + 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->getLinkage() == ExternalLinkage) + 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()) { + ParmVarDecl *PD = FD->getParamDecl(i); + if (PD->getAttr<CFConsumedAttr>()) { + isConsumed = true; + return true; + } + } + } + + return false; + } + + bool isSelf(Expr *E) const { E = E->IgnoreParenLValueCasts(); if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) - if (DRE->getDecl()->getIdentifier() == SelfII) - return true; + if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(DRE->getDecl())) + if (IPD->getIdentifier() == SelfII) + return true; + return false; } }; @@ -198,6 +307,6 @@ private: } // end anonymous namespace void trans::rewriteUnbridgedCasts(MigrationPass &pass) { - UnbridgedCastRewriter trans(pass); + BodyTransform<UnbridgedCastRewriter> trans(pass); trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); } |