diff options
author | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2011-06-21 20:20:39 +0000 |
---|---|---|
committer | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2011-06-21 20:20:39 +0000 |
commit | e5b475c6881ff8ce6de1f4bc42e452c1d8059d83 (patch) | |
tree | aacf2978c9e15c890120372eff7abfe5578d4079 /clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp | |
parent | e1ba3123c1a8f1e9cc36df7282b44887bab5bdde (diff) | |
download | bcm5719-llvm-e5b475c6881ff8ce6de1f4bc42e452c1d8059d83.tar.gz bcm5719-llvm-e5b475c6881ff8ce6de1f4bc42e452c1d8059d83.zip |
[arcmt] Break apart Transforms.cpp.
llvm-svn: 133539
Diffstat (limited to 'clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp')
-rw-r--r-- | clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp b/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp new file mode 100644 index 00000000000..f03ab5a6f4b --- /dev/null +++ b/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp @@ -0,0 +1,142 @@ +//===--- TransRetainReleaseDealloc.cpp - Tranformations to ARC mode -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// removeRetainReleaseDealloc: +// +// Removes retain/release/autorelease/dealloc messages. +// +// return [[foo retain] autorelease]; +// ----> +// return foo; +// +//===----------------------------------------------------------------------===// + +#include "Transforms.h" +#include "Internals.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "clang/AST/ParentMap.h" + +using namespace clang; +using namespace arcmt; +using namespace trans; +using llvm::StringRef; + +namespace { + +class RetainReleaseDeallocRemover : + public RecursiveASTVisitor<RetainReleaseDeallocRemover> { + Decl *Dcl; + Stmt *Body; + MigrationPass &Pass; + + ExprSet Removables; + llvm::OwningPtr<ParentMap> StmtMap; + +public: + RetainReleaseDeallocRemover(Decl *D, MigrationPass &pass) + : Dcl(D), Body(0), Pass(pass) { } + + void transformBody(Stmt *body) { + Body = body; + collectRemovables(body, Removables); + StmtMap.reset(new ParentMap(body)); + TraverseStmt(body); + } + + bool VisitObjCMessageExpr(ObjCMessageExpr *E) { + switch (E->getMethodFamily()) { + default: + return true; + case OMF_retain: + case OMF_release: + case OMF_autorelease: + if (E->getReceiverKind() == ObjCMessageExpr::Instance) + if (Expr *rec = E->getInstanceReceiver()) { + rec = rec->IgnoreParenImpCasts(); + if (rec->getType().getObjCLifetime() == Qualifiers::OCL_ExplicitNone){ + std::string err = "It is not safe to remove '"; + err += E->getSelector().getAsString() + "' message on " + "an __unsafe_unretained type"; + Pass.TA.reportError(err, rec->getLocStart()); + return true; + } + } + case OMF_dealloc: + break; + } + + switch (E->getReceiverKind()) { + default: + return true; + case ObjCMessageExpr::SuperInstance: { + Transaction Trans(Pass.TA); + Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message, + diag::err_unavailable, + diag::err_unavailable_message, + E->getSuperLoc()); + if (tryRemoving(E)) + return true; + Pass.TA.replace(E->getSourceRange(), "self"); + return true; + } + case ObjCMessageExpr::Instance: + break; + } + + Expr *rec = E->getInstanceReceiver(); + if (!rec) return true; + + Transaction Trans(Pass.TA); + Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message, + diag::err_unavailable, + diag::err_unavailable_message, + rec->getExprLoc()); + if (!hasSideEffects(E, Pass.Ctx)) { + if (tryRemoving(E)) + return true; + } + Pass.TA.replace(E->getSourceRange(), rec->getSourceRange()); + + return true; + } + +private: + bool isRemovable(Expr *E) const { + return Removables.count(E); + } + + bool tryRemoving(Expr *E) const { + if (isRemovable(E)) { + Pass.TA.removeStmt(E); + return true; + } + + if (ParenExpr *parenE = dyn_cast_or_null<ParenExpr>(StmtMap->getParent(E))) + return tryRemoving(parenE); + + if (BinaryOperator * + bopE = dyn_cast_or_null<BinaryOperator>(StmtMap->getParent(E))) { + if (bopE->getOpcode() == BO_Comma && bopE->getLHS() == E && + isRemovable(bopE)) { + Pass.TA.replace(bopE->getSourceRange(), bopE->getRHS()->getSourceRange()); + return true; + } + } + + return false; + } + +}; + +} // anonymous namespace + +void trans::removeRetainReleaseDealloc(MigrationPass &pass) { + BodyTransform<RetainReleaseDeallocRemover> trans(pass); + trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); +} |