aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/DeclObjC.cpp28
-rw-r--r--lib/Basic/IdentifierTable.cpp2
-rw-r--r--lib/Sema/SemaDeclObjC.cpp8
-rw-r--r--lib/Sema/SemaExprObjC.cpp48
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;
}
}