diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/DeclObjC.cpp | 28 | ||||
-rw-r--r-- | lib/Basic/IdentifierTable.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaDeclObjC.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 48 |
4 files changed, 86 insertions, 0 deletions
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 67f6531d79..557b681d2f 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -452,6 +452,34 @@ ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const { if (!isInstanceMethod()) family = OMF_None; break; + + case OMF_performSelector: + if (!isInstanceMethod() || + !getResultType()->isObjCIdType()) + family = OMF_None; + else { + unsigned noParams = param_size(); + if (noParams < 1 || noParams > 3) + family = OMF_None; + else { + ObjCMethodDecl::arg_type_iterator it = arg_type_begin(); + QualType ArgT = (*it); + if (!ArgT->isObjCSelType()) { + family = OMF_None; + break; + } + while (--noParams) { + it++; + ArgT = (*it); + if (!ArgT->isObjCIdType()) { + family = OMF_None; + break; + } + } + } + } + break; + } // Cache the result. diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index 109761c9dc..188e2d46f5 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -397,6 +397,8 @@ ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) { if (name == "retainCount") return OMF_retainCount; if (name == "self") return OMF_self; } + + if (name == "performSelector") return OMF_performSelector; // The other method families may begin with a prefix of underscores. while (!name.empty() && name.front() == '_') diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index a9f4f95c20..127bb3cdcc 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -286,6 +286,11 @@ static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) { method->hasAttr<NSReturnsAutoreleasedAttr>()) return false; break; + + case OMF_performSelector: + // we don't annotate performSelector's + return true; + } method->addAttr(new (S.Context) NSReturnsRetainedAttr(SourceLocation(), @@ -366,6 +371,7 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { case OMF_copy: case OMF_new: case OMF_self: + case OMF_performSelector: break; } } @@ -1298,6 +1304,7 @@ static bool checkMethodFamilyMismatch(Sema &S, ObjCMethodDecl *impl, case OMF_dealloc: case OMF_retainCount: case OMF_self: + case OMF_performSelector: // Mismatches for these methods don't change ownership // conventions, so we don't care. return false; @@ -2467,6 +2474,7 @@ Decl *Sema::ActOnMethodDeclaration( case OMF_mutableCopy: case OMF_release: case OMF_retainCount: + case OMF_performSelector: break; case OMF_alloc: diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index c02b634547..17a7401d65 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -204,6 +204,7 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, case OMF_mutableCopy: case OMF_new: case OMF_self: + case OMF_performSelector: break; } } @@ -1417,6 +1418,53 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, Diag(Loc, diag::err_arc_illegal_explicit_message) << Sel << SelectorLoc; break; + + case OMF_performSelector: + if (Method && NumArgs >= 1) { + if (ObjCSelectorExpr *SelExp = dyn_cast<ObjCSelectorExpr>(Args[0])) { + Selector ArgSel = SelExp->getSelector(); + ObjCMethodDecl *SelMethod = + LookupInstanceMethodInGlobalPool(ArgSel, + SelExp->getSourceRange()); + if (!SelMethod) + SelMethod = + LookupFactoryMethodInGlobalPool(ArgSel, + SelExp->getSourceRange()); + if (SelMethod) { + ObjCMethodFamily SelFamily = SelMethod->getMethodFamily(); + switch (SelFamily) { + case OMF_alloc: + case OMF_copy: + case OMF_mutableCopy: + case OMF_new: + case OMF_self: + case OMF_init: + // Issue error, unless ns_returns_not_retained. + if (!SelMethod->hasAttr<NSReturnsNotRetainedAttr>()) { + // selector names a +1 method + Diag(SelectorLoc, + diag::err_arc_perform_selector_retains); + Diag(SelMethod->getLocation(), diag::note_method_declared_at); + } + break; + default: + // +0 call. OK. unless ns_returns_retained. + if (SelMethod->hasAttr<NSReturnsRetainedAttr>()) { + // selector names a +1 method + Diag(SelectorLoc, + diag::err_arc_perform_selector_retains); + Diag(SelMethod->getLocation(), diag::note_method_declared_at); + } + break; + } + } + } else { + // error (may leak). + Diag(SelectorLoc, diag::warn_arc_perform_selector_leaks); + Diag(Args[0]->getExprLoc(), diag::note_used_here); + } + } + break; } } |