diff options
author | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2011-07-18 07:44:45 +0000 |
---|---|---|
committer | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2011-07-18 07:44:45 +0000 |
commit | fd10398c10ffdcbdeb1e3e299c74d70e689f503c (patch) | |
tree | c52a8f508e0a075addc538f529bf289bdd61bb09 /lib/ARCMigrate/TransAPIUses.cpp | |
parent | f57ef0516c011237a1b6a5b2585b99caf0396bd7 (diff) |
[arcmt] NSInvocation's [get/set]ReturnValue and [get/set]Argument are only safe
with __unsafe_unretained parameters. Emit error for strong/weak ones. rdar://9206226
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@135381 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/ARCMigrate/TransAPIUses.cpp')
-rw-r--r-- | lib/ARCMigrate/TransAPIUses.cpp | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/lib/ARCMigrate/TransAPIUses.cpp b/lib/ARCMigrate/TransAPIUses.cpp new file mode 100644 index 0000000000..58fd3d07d0 --- /dev/null +++ b/lib/ARCMigrate/TransAPIUses.cpp @@ -0,0 +1,89 @@ +//===--- TransAPIUses.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. +// +//===----------------------------------------------------------------------===// +// +// checkAPIUses: +// +// Emits error with some API uses that are not safe in ARC mode: +// +// - NSInvocation's [get/set]ReturnValue and [get/set]Argument are only safe +// with __unsafe_unretained objects. +// +//===----------------------------------------------------------------------===// + +#include "Transforms.h" +#include "Internals.h" + +using namespace clang; +using namespace arcmt; +using namespace trans; +using llvm::StringRef; + +namespace { + +class APIChecker : public RecursiveASTVisitor<APIChecker> { + MigrationPass &Pass; + Selector getReturnValueSel, setReturnValueSel; + Selector getArgumentSel, setArgumentSel; + +public: + APIChecker(MigrationPass &pass) : Pass(pass) { + SelectorTable &sels = Pass.Ctx.Selectors; + IdentifierTable &ids = Pass.Ctx.Idents; + getReturnValueSel = sels.getUnarySelector(&ids.get("getReturnValue")); + setReturnValueSel = sels.getUnarySelector(&ids.get("setReturnValue")); + + IdentifierInfo *selIds[2]; + selIds[0] = &ids.get("getArgument"); + selIds[1] = &ids.get("atIndex"); + getArgumentSel = sels.getSelector(2, selIds); + selIds[0] = &ids.get("setArgument"); + setArgumentSel = sels.getSelector(2, selIds); + } + + bool VisitObjCMessageExpr(ObjCMessageExpr *E) { + if (E->isInstanceMessage() && + E->getReceiverInterface() && + E->getReceiverInterface()->getName() == "NSInvocation") { + StringRef selName; + if (E->getSelector() == getReturnValueSel) + selName = "getReturnValue"; + else if (E->getSelector() == setReturnValueSel) + selName = "setReturnValue"; + else if (E->getSelector() == getArgumentSel) + selName = "getArgument"; + else if (E->getSelector() == setArgumentSel) + selName = "setArgument"; + + if (selName.empty()) + return true; + + Expr *parm = E->getArg(0)->IgnoreParenCasts(); + QualType pointee = parm->getType()->getPointeeType(); + if (pointee.isNull()) + return true; + + if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone) { + std::string err = "NSInvocation's "; + err += selName; + err += " is not safe to be used with an object with ownership other " + "than __unsafe_unretained"; + Pass.TA.reportError(err, parm->getLocStart(), parm->getSourceRange()); + } + return true; + } + + return true; + } +}; + +} // anonymous namespace + +void trans::checkAPIUses(MigrationPass &pass) { + APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl()); +} |