diff options
author | Ted Kremenek <kremenek@apple.com> | 2014-03-05 08:13:08 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2014-03-05 08:13:08 +0000 |
commit | 4b3c66e6e816ad87e1c81fadf35810243426d903 (patch) | |
tree | cdc576a9836b56ad8b5a009b846e7ef000de49d2 /clang/lib/Sema/SemaDeclObjC.cpp | |
parent | 19126f9075902a7c3b6b966290bbf742ce8b86b7 (diff) | |
download | bcm5719-llvm-4b3c66e6e816ad87e1c81fadf35810243426d903.tar.gz bcm5719-llvm-4b3c66e6e816ad87e1c81fadf35810243426d903.zip |
Adjust logic for 'objc_protocol_requires_explicit_implementation' for inherited protocols and protocols already conformed in the class hierarchy.
Per more discussion, 'objc_protocol_requires_explicit_implementation' is
refinement that it mainly adds that requirement that a protocol must be
explicitly satisfied at the moment the first class in the class hierarchy
conforms to it. Any subclasses that also conform to that protocol,
either directly or via conforming to a protocol that inherits that protocol,
do not need to re-implement that protocol.
Doing this requires first doing a pass on the super class hierarchy,
gathering the set of protocols conformed to by the super classes,
and then culling those out when determining conformance. This
two-pass algorithm could be generalized for all protocol checking,
and could possibly be a performance win in some cases. For now
we restrict this change to protocols with this attribute to isolate
the change in logic (especially as the design continues to evolve).
This change needs to be adjusted for properties as well; this
only impacts methods right now.
llvm-svn: 202948
Diffstat (limited to 'clang/lib/Sema/SemaDeclObjC.cpp')
-rw-r--r-- | clang/lib/Sema/SemaDeclObjC.cpp | 60 |
1 files changed, 54 insertions, 6 deletions
diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 86e16212a3a..57f40aaca54 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -1632,6 +1632,26 @@ void Sema::WarnExactTypedMethods(ObjCMethodDecl *ImpMethodDecl, /// we used an immutable set to keep the table then it wouldn't add significant /// memory cost and it would be handy for lookups. +typedef llvm::DenseSet<IdentifierInfo*> ProtocolNameSet; +typedef llvm::OwningPtr<ProtocolNameSet> LazyProtocolNameSet; + +/// Recursively populates a set with all conformed protocols in a class +/// hierarchy that have the 'objc_protocol_requires_explicit_implementation' +/// attribute. +static void findProtocolsWithExplicitImpls(const ObjCInterfaceDecl *Super, + ProtocolNameSet &PNS) { + if (!Super) + return; + + for (ObjCInterfaceDecl::all_protocol_iterator + I = Super->all_referenced_protocol_begin(), + E = Super->all_referenced_protocol_end(); I != E; ++I) { + const ObjCProtocolDecl *PDecl = *I; + if (PDecl->hasAttr<ObjCExplicitProtocolImplAttr>()) + PNS.insert(PDecl->getIdentifier()); + } +} + /// CheckProtocolMethodDefs - This routine checks unimplemented methods /// Declared in protocol, and those referenced by it. static void CheckProtocolMethodDefs(Sema &S, @@ -1641,7 +1661,7 @@ static void CheckProtocolMethodDefs(Sema &S, const Sema::SelectorSet &InsMap, const Sema::SelectorSet &ClsMap, ObjCContainerDecl *CDecl, - bool isExplicitProtocol = true) { + LazyProtocolNameSet &ProtocolsExplictImpl) { ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl); ObjCInterfaceDecl *IDecl = C ? C->getClassInterface() : dyn_cast<ObjCInterfaceDecl>(CDecl); @@ -1649,6 +1669,32 @@ static void CheckProtocolMethodDefs(Sema &S, ObjCInterfaceDecl *Super = IDecl->getSuperClass(); ObjCInterfaceDecl *NSIDecl = 0; + + // If this protocol is marked 'objc_protocol_requires_explicit_implementation' + // then we should check if any class in the super class hierarchy also + // conforms to this protocol, either directly or via protocol inheritance. + // If so, we can skip checking this protocol completely because we + // know that a parent class already satisfies this protocol. + // + // Note: we could generalize this logic for all protocols, and merely + // add the limit on looking at the super class chain for just + // specially marked protocols. This may be a good optimization. This + // change is restricted to 'objc_protocol_requires_explicit_implementation' + // protocols for now for controlled evaluation. + if (PDecl->hasAttr<ObjCExplicitProtocolImplAttr>()) { + if (!ProtocolsExplictImpl.isValid()) { + ProtocolsExplictImpl.reset(new ProtocolNameSet); + findProtocolsWithExplicitImpls(Super, *ProtocolsExplictImpl); + } + if (ProtocolsExplictImpl->find(PDecl->getIdentifier()) != + ProtocolsExplictImpl->end()) + return; + + // If no super class conforms to the protocol, we should not search + // for methods in the super class to implicitly satisfy the protocol. + Super = NULL; + } + if (S.getLangOpts().ObjCRuntime.isNeXTFamily()) { // check to see if class implements forwardInvocation method and objects // of this class are derived from 'NSProxy' so that to forward requests @@ -1674,8 +1720,6 @@ static void CheckProtocolMethodDefs(Sema &S, // the method was implemented by a base class or an inherited // protocol. This lookup is slow, but occurs rarely in correct code // and otherwise would terminate in a warning. - if (isExplicitProtocol && PDecl->hasAttr<ObjCExplicitProtocolImplAttr>()) - Super = NULL; // check unimplemented instance methods. if (!NSIDecl) @@ -1744,7 +1788,7 @@ static void CheckProtocolMethodDefs(Sema &S, for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), E = PDecl->protocol_end(); PI != E; ++PI) CheckProtocolMethodDefs(S, ImpLoc, *PI, IncompleteImpl, InsMap, ClsMap, - CDecl, /* isExplicitProtocl */ false); + CDecl, ProtocolsExplictImpl); } /// MatchAllMethodDeclarations - Check methods declared in interface @@ -1958,12 +2002,15 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, // Check and see if class methods in class interface have been // implemented in the implementation class. + LazyProtocolNameSet ExplicitImplProtocols; + if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl> (CDecl)) { for (ObjCInterfaceDecl::all_protocol_iterator PI = I->all_referenced_protocol_begin(), E = I->all_referenced_protocol_end(); PI != E; ++PI) CheckProtocolMethodDefs(*this, IMPDecl->getLocation(), *PI, - IncompleteImpl, InsMap, ClsMap, I); + IncompleteImpl, InsMap, ClsMap, I, + ExplicitImplProtocols); // Check class extensions (unnamed categories) for (ObjCInterfaceDecl::visible_extensions_iterator Ext = I->visible_extensions_begin(), @@ -1978,7 +2025,8 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, for (ObjCCategoryDecl::protocol_iterator PI = C->protocol_begin(), E = C->protocol_end(); PI != E; ++PI) CheckProtocolMethodDefs(*this, IMPDecl->getLocation(), *PI, - IncompleteImpl, InsMap, ClsMap, CDecl); + IncompleteImpl, InsMap, ClsMap, CDecl, + ExplicitImplProtocols); DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, /* SynthesizeProperties */ false); } |