r195323 - Add new attribute 'objc_suppress_protocol' to suppress protocol conformance for a class.
Jean-Daniel Dupas
devlists at shadowlab.org
Thu Nov 21 00:48:53 PST 2013
Le 21 nov. 2013 à 08:20, Ted Kremenek <kremenek at apple.com> a écrit :
> Author: kremenek
> Date: Thu Nov 21 01:20:42 2013
> New Revision: 195323
>
> URL: http://llvm.org/viewvc/llvm-project?rev=195323&view=rev
> Log:
> Add new attribute 'objc_suppress_protocol' to suppress protocol conformance for a class.
>
> The idea is to allow a class to stipulate that its methods (and those
> of its parents) cannot be used for protocol conformance in a subclass.
> A subclass is then explicitly required to re-implement those methods
> of they are present in the class marked with this attribute.
>
> Currently the attribute can only be applied to an @interface, and
> not a category or class extension. This is by design.
If this is by design, maybe the test case should check that it is not supported.
> Unlike
> protocol conformance, where a category can add explicit conformance
> of a protocol to class, this anti-conformance really needs to be
> observed uniformly by all clients of the class. That's because
> the absence of the attribute implies more permissive checking of
> protocol conformance.
>
> This unfortunately required changing method lookup in ObjCInterfaceDecl
> to take an optional protocol parameter. This should not slow down
> method lookup in most cases, and is just used for protocol conformance.
>
> Added:
> cfe/trunk/test/SemaObjC/protocols-suppress-conformance.m
> Modified:
> cfe/trunk/include/clang/AST/DeclObjC.h
> cfe/trunk/include/clang/Basic/Attr.td
> cfe/trunk/lib/AST/DeclObjC.cpp
> cfe/trunk/lib/Sema/SemaDeclAttr.cpp
> cfe/trunk/lib/Sema/SemaDeclObjC.cpp
>
> Modified: cfe/trunk/include/clang/AST/DeclObjC.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclObjC.h?rev=195323&r1=195322&r2=195323&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/DeclObjC.h (original)
> +++ cfe/trunk/include/clang/AST/DeclObjC.h Thu Nov 21 01:20:42 2013
> @@ -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);
>
>
> Modified: cfe/trunk/include/clang/Basic/Attr.td
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=195323&r1=195322&r2=195323&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/Attr.td (original)
> +++ cfe/trunk/include/clang/Basic/Attr.td Thu Nov 21 01:20:42 2013
> @@ -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">];
> }
>
> Modified: cfe/trunk/lib/AST/DeclObjC.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclObjC.cpp?rev=195323&r1=195322&r2=195323&view=diff
> ==============================================================================
> --- cfe/trunk/lib/AST/DeclObjC.cpp (original)
> +++ cfe/trunk/lib/AST/DeclObjC.cpp Thu Nov 21 01:20:42 2013
> @@ -457,9 +457,11 @@ ObjCInterfaceDecl::lookupNestedProtocol(
> /// 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::looku
> 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;
>
>
> Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=195323&r1=195322&r2=195323&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Thu Nov 21 01:20:42 2013
> @@ -2134,6 +2134,30 @@ static void handleObjCRootClassAttr(Sema
> 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
> 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;
>
> Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=195323&r1=195322&r2=195323&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Thu Nov 21 01:20:42 2013
> @@ -1664,7 +1664,8 @@ void Sema::CheckProtocolMethodDefs(Sourc
> 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(Sourc
> // 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(Sourc
> 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) !=
>
> Added: cfe/trunk/test/SemaObjC/protocols-suppress-conformance.m
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/protocols-suppress-conformance.m?rev=195323&view=auto
> ==============================================================================
> --- cfe/trunk/test/SemaObjC/protocols-suppress-conformance.m (added)
> +++ cfe/trunk/test/SemaObjC/protocols-suppress-conformance.m Thu Nov 21 01:20:42 2013
> @@ -0,0 +1,27 @@
> +// RUN: %clang_cc1 -fsyntax-only -verify %s -Wno-objc-root-class
> +
> + at protocol FooProto
> +- (void) theBestOfTimes; // expected-note {{method 'theBestOfTimes' declared here}}
> + at end
> +
> +__attribute__((objc_suppress_protocol(FooProto)))
> + at interface Bar
> +- (void) theBestOfTimes;
> + at end
> +
> + at interface Bar2 : Bar
> + at end
> +
> + at interface Baz : Bar2 <FooProto> // expected-note {{required for direct or indirect protocol 'FooProto'}}
> + at end
> +
> + at interface Baz2 : Bar2 <FooProto>
> +- (void) theBestOfTimes;
> + at end
> +
> + at implementation Baz // expected-warning {{method 'theBestOfTimes' in protocol not implemented}}
> + at end
> +
> + at implementation Baz2 // no-warning
> +- (void) theBestOfTimes {}
> + at end
> \ No newline at end of file
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
-- Jean-Daniel
More information about the cfe-commits
mailing list