summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/AST/DeclObjC.h13
-rw-r--r--clang/include/clang/Basic/Attr.td6
-rw-r--r--clang/lib/AST/DeclObjC.cpp26
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp29
-rw-r--r--clang/lib/Sema/SemaDeclObjC.cpp13
-rw-r--r--clang/test/SemaObjC/protocols-suppress-conformance.m27
6 files changed, 100 insertions, 14 deletions
diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h
index 2e760d658e4..10e5dc11ee6 100644
--- a/clang/include/clang/AST/DeclObjC.h
+++ b/clang/include/clang/AST/DeclObjC.h
@@ -1142,14 +1142,17 @@ public:
// found, we search referenced protocols and class categories.
ObjCMethodDecl *lookupMethod(Selector Sel, bool isInstance,
bool shallowCategoryLookup= false,
- const ObjCCategoryDecl *C= 0) const;
+ const ObjCCategoryDecl *C = 0,
+ const ObjCProtocolDecl *P = 0) const;
ObjCMethodDecl *lookupInstanceMethod(Selector Sel,
- bool shallowCategoryLookup = false) const {
- return lookupMethod(Sel, true/*isInstance*/, shallowCategoryLookup);
+ bool shallowCategoryLookup = false,
+ ObjCProtocolDecl *P = 0) const {
+ return lookupMethod(Sel, true/*isInstance*/, shallowCategoryLookup, 0, P);
}
ObjCMethodDecl *lookupClassMethod(Selector Sel,
- bool shallowCategoryLookup = false) const {
- return lookupMethod(Sel, false/*isInstance*/, shallowCategoryLookup);
+ bool shallowCategoryLookup = false,
+ ObjCProtocolDecl *P = 0) const {
+ return lookupMethod(Sel, false/*isInstance*/, shallowCategoryLookup, 0, P);
}
ObjCInterfaceDecl *lookupInheritedClass(const IdentifierInfo *ICName);
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index bcca1d25ef7..a6be491c5a2 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -613,6 +613,12 @@ def ObjCRootClass : InheritableAttr {
let Subjects = [ObjCInterface];
}
+def ObjCSuppressProtocol : InheritableAttr {
+ let Spellings = [GNU<"objc_suppress_protocol">];
+ let Subjects = [ObjCInterface];
+ let Args = [IdentifierArgument<"Protocol", 1>];
+}
+
def Overloadable : Attr {
let Spellings = [GNU<"overloadable">];
}
diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp
index b2b5b70197b..d759c0795b8 100644
--- a/clang/lib/AST/DeclObjC.cpp
+++ b/clang/lib/AST/DeclObjC.cpp
@@ -457,9 +457,11 @@ ObjCInterfaceDecl::lookupNestedProtocol(IdentifierInfo *Name) {
/// When argument category "C" is specified, any implicit method found
/// in this category is ignored.
ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel,
- bool isInstance,
- bool shallowCategoryLookup,
- const ObjCCategoryDecl *C) const {
+ bool isInstance,
+ bool shallowCategoryLookup,
+ const ObjCCategoryDecl *C,
+ const ObjCProtocolDecl *P) const
+{
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return 0;
@@ -470,7 +472,23 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel,
if (data().ExternallyCompleted)
LoadExternalDefinition();
- while (ClassDecl != NULL) {
+ while (ClassDecl) {
+ // If we are looking for a method that is part of protocol conformance,
+ // check if the class has been marked to suppress conformance
+ // of that protocol.
+ if (P && ClassDecl->hasAttrs()) {
+ const AttrVec &V = ClassDecl->getAttrs();
+ const IdentifierInfo *PI = P->getIdentifier();
+ for (AttrVec::const_iterator I = V.begin(), E = V.end(); I != E; ++I) {
+ if (const ObjCSuppressProtocolAttr *A =
+ dyn_cast<ObjCSuppressProtocolAttr>(*I)){
+ if (A->getProtocol() == PI) {
+ return 0;
+ }
+ }
+ }
+ }
+
if ((MethodDecl = ClassDecl->getMethod(Sel, isInstance)))
return MethodDecl;
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 38bffa2f99e..0c025b78497 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -2134,6 +2134,30 @@ static void handleObjCRootClassAttr(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
+static void handleObjCSuppresProtocolAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (!isa<ObjCInterfaceDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedObjectiveCInterface;
+ return;
+ }
+
+ IdentifierLoc *Parm = NULL;
+ if (Attr.getNumArgs() == 1) {
+ Parm = Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : 0;
+ }
+
+ if (!Parm) {
+ S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << Attr.getName() << 1;
+ return;
+ }
+
+ D->addAttr(::new (S.Context)
+ ObjCSuppressProtocolAttr(Attr.getRange(), S.Context, Parm->Ident,
+ Attr.getAttributeSpellingListIndex()));
+}
+
+
static void handleObjCRequiresPropertyDefsAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
if (!isa<ObjCInterfaceDecl>(D)) {
@@ -4690,7 +4714,10 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_ObjCRootClass:
handleObjCRootClassAttr(S, D, Attr);
break;
- case AttributeList::AT_ObjCRequiresPropertyDefs:
+ case AttributeList::AT_ObjCSuppressProtocol:
+ handleObjCSuppresProtocolAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_ObjCRequiresPropertyDefs:
handleObjCRequiresPropertyDefsAttr (S, D, Attr);
break;
case AttributeList::AT_Unused: handleUnusedAttr (S, D, Attr); break;
diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp
index f44fb325114..2a781b5bd7d 100644
--- a/clang/lib/Sema/SemaDeclObjC.cpp
+++ b/clang/lib/Sema/SemaDeclObjC.cpp
@@ -1664,7 +1664,8 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
if (method->getImplementationControl() != ObjCMethodDecl::Optional &&
!method->isPropertyAccessor() &&
!InsMap.count(method->getSelector()) &&
- (!Super || !Super->lookupInstanceMethod(method->getSelector()))) {
+ (!Super || !Super->lookupInstanceMethod(method->getSelector(),
+ false, PDecl))) {
// If a method is not implemented in the category implementation but
// has been declared in its primary class, superclass,
// or in one of their protocols, no need to issue the warning.
@@ -1676,7 +1677,8 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
// uses the protocol.
if (ObjCMethodDecl *MethodInClass =
IDecl->lookupInstanceMethod(method->getSelector(),
- true /*shallowCategoryLookup*/))
+ true /*shallowCategoryLookup*/,
+ PDecl))
if (C || MethodInClass->isPropertyAccessor())
continue;
unsigned DIAG = diag::warn_unimplemented_protocol_method;
@@ -1695,10 +1697,13 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
ObjCMethodDecl *method = *I;
if (method->getImplementationControl() != ObjCMethodDecl::Optional &&
!ClsMap.count(method->getSelector()) &&
- (!Super || !Super->lookupClassMethod(method->getSelector()))) {
+ (!Super || !Super->lookupClassMethod(method->getSelector(),
+ /* shallowCategoryLookup */ false,
+ PDecl))) {
// See above comment for instance method lookups.
if (C && IDecl->lookupClassMethod(method->getSelector(),
- true /*shallowCategoryLookup*/))
+ true /*shallowCategoryLookup*/,
+ PDecl))
continue;
unsigned DIAG = diag::warn_unimplemented_protocol_method;
if (Diags.getDiagnosticLevel(DIAG, ImpLoc) !=
diff --git a/clang/test/SemaObjC/protocols-suppress-conformance.m b/clang/test/SemaObjC/protocols-suppress-conformance.m
new file mode 100644
index 00000000000..77c7e254c27
--- /dev/null
+++ b/clang/test/SemaObjC/protocols-suppress-conformance.m
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -Wno-objc-root-class
+
+@protocol FooProto
+- (void) theBestOfTimes; // expected-note {{method 'theBestOfTimes' declared here}}
+@end
+
+__attribute__((objc_suppress_protocol(FooProto)))
+@interface Bar
+- (void) theBestOfTimes;
+@end
+
+@interface Bar2 : Bar
+@end
+
+@interface Baz : Bar2 <FooProto> // expected-note {{required for direct or indirect protocol 'FooProto'}}
+@end
+
+@interface Baz2 : Bar2 <FooProto>
+- (void) theBestOfTimes;
+@end
+
+@implementation Baz // expected-warning {{method 'theBestOfTimes' in protocol not implemented}}
+@end
+
+@implementation Baz2 // no-warning
+- (void) theBestOfTimes {}
+@end \ No newline at end of file
OpenPOWER on IntegriCloud