diff options
| -rw-r--r-- | clang/include/clang/AST/DeclObjC.h | 13 | ||||
| -rw-r--r-- | clang/include/clang/Basic/Attr.td | 6 | ||||
| -rw-r--r-- | clang/lib/AST/DeclObjC.cpp | 26 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 29 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclObjC.cpp | 13 | ||||
| -rw-r--r-- | clang/test/SemaObjC/protocols-suppress-conformance.m | 27 |
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 |

