diff options
author | Alex Lorenz <arphaman@gmail.com> | 2017-03-06 15:58:34 +0000 |
---|---|---|
committer | Alex Lorenz <arphaman@gmail.com> | 2017-03-06 15:58:34 +0000 |
commit | 0e23c61c87551d8d6e796d54f99b654a73c67cff (patch) | |
tree | 3b6ec4f86c4ad9e1811aa96c45d099f3532d1dda /clang/lib/Sema/SemaExprObjC.cpp | |
parent | 89e36cc04c692d9fdefbc828c9f50153c0a8c63f (diff) | |
download | bcm5719-llvm-0e23c61c87551d8d6e796d54f99b654a73c67cff.tar.gz bcm5719-llvm-0e23c61c87551d8d6e796d54f99b654a73c67cff.zip |
[Sema][ObjC] Warn about 'performSelector' calls with selectors
that return record or vector types
The performSelector family of methods from Foundation use objc_msgSend to
dispatch the selector invocations to objects. However, method calls to methods
that return record types might have to use the objc_msgSend_stret as the return
value won't find into the register. This is also supported by this sentence from
performSelector documentation: "The method should not have a significant return
value and should take a single argument of type id, or no arguments". This
commit adds a new warning that warns when a selector which corresponds to a
method that returns a record type is passed into performSelector.
rdar://12056271
Differential Revision: https://reviews.llvm.org/D30174
llvm-svn: 297019
Diffstat (limited to 'clang/lib/Sema/SemaExprObjC.cpp')
-rw-r--r-- | clang/lib/Sema/SemaExprObjC.cpp | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 3039e12585a..67876c261d0 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -2266,6 +2266,52 @@ static void checkCocoaAPI(Sema &S, const ObjCMessageExpr *Msg) { edit::rewriteObjCRedundantCallWithLiteral); } +static void checkFoundationAPI(Sema &S, SourceLocation Loc, + const ObjCMethodDecl *Method, + ArrayRef<Expr *> Args, QualType ReceiverType, + bool IsClassObjectCall) { + // Check if this is a performSelector method that uses a selector that returns + // a record or a vector type. + if (Method->getMethodFamily() != OMF_performSelector || Args.empty()) + return; + const auto *SE = dyn_cast<ObjCSelectorExpr>(Args[0]->IgnoreParens()); + if (!SE) + return; + ObjCMethodDecl *ImpliedMethod; + if (!IsClassObjectCall) { + const auto *OPT = ReceiverType->getAs<ObjCObjectPointerType>(); + if (!OPT || !OPT->getInterfaceDecl()) + return; + ImpliedMethod = + OPT->getInterfaceDecl()->lookupInstanceMethod(SE->getSelector()); + if (!ImpliedMethod) + ImpliedMethod = + OPT->getInterfaceDecl()->lookupPrivateMethod(SE->getSelector()); + } else { + const auto *IT = ReceiverType->getAs<ObjCInterfaceType>(); + if (!IT) + return; + ImpliedMethod = IT->getDecl()->lookupClassMethod(SE->getSelector()); + if (!ImpliedMethod) + ImpliedMethod = + IT->getDecl()->lookupPrivateClassMethod(SE->getSelector()); + } + if (!ImpliedMethod) + return; + QualType Ret = ImpliedMethod->getReturnType(); + if (Ret->isRecordType() || Ret->isVectorType() || Ret->isExtVectorType()) { + QualType Ret = ImpliedMethod->getReturnType(); + S.Diag(Loc, diag::warn_objc_unsafe_perform_selector) + << Method->getSelector() + << (!Ret->isRecordType() + ? /*Vector*/ 2 + : Ret->isUnionType() ? /*Union*/ 1 : /*Struct*/ 0); + S.Diag(ImpliedMethod->getLocStart(), + diag::note_objc_unsafe_perform_selector_method_declared_here) + << ImpliedMethod->getSelector() << Ret; + } +} + /// \brief Diagnose use of %s directive in an NSString which is being passed /// as formatting string to formatting method. static void @@ -2468,6 +2514,9 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, if (!isImplicit) checkCocoaAPI(*this, Result); } + if (Method) + checkFoundationAPI(*this, SelLoc, Method, makeArrayRef(Args, NumArgs), + ReceiverType, /*IsClassObjectCall=*/true); return MaybeBindToTemporary(Result); } @@ -2994,6 +3043,26 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (!isImplicit) checkCocoaAPI(*this, Result); } + if (Method) { + bool IsClassObjectCall = ClassMessage; + // 'self' message receivers in class methods should be treated as message + // sends to the class object in order for the semantic checks to be + // performed correctly. Messages to 'super' already count as class messages, + // so they don't need to be handled here. + if (Receiver && isSelfExpr(Receiver)) { + if (const auto *OPT = ReceiverType->getAs<ObjCObjectPointerType>()) { + if (OPT->getObjectType()->isObjCClass()) { + if (const auto *CurMeth = getCurMethodDecl()) { + IsClassObjectCall = true; + ReceiverType = + Context.getObjCInterfaceType(CurMeth->getClassInterface()); + } + } + } + } + checkFoundationAPI(*this, SelLoc, Method, makeArrayRef(Args, NumArgs), + ReceiverType, IsClassObjectCall); + } if (getLangOpts().ObjCAutoRefCount) { // In ARC, annotate delegate init calls. |