diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:44:14 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:44:14 +0000 |
commit | 2b6b257f4e5503a7a2675bdb8735693db769f75c (patch) | |
tree | e85e046ae7003fe3bcc8b5454cd0fa3f7407b470 /lib/Sema/SemaDeclObjC.cpp | |
parent | b4348ed0b7e90c0831b925fbee00b5f179a99796 (diff) |
Notes
Diffstat (limited to 'lib/Sema/SemaDeclObjC.cpp')
-rw-r--r-- | lib/Sema/SemaDeclObjC.cpp | 228 |
1 files changed, 190 insertions, 38 deletions
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index a2f41a7cc30a7..738de77cecb7b 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -21,7 +21,6 @@ #include "clang/AST/ExprObjC.h" #include "clang/Basic/SourceManager.h" #include "clang/Sema/DeclSpec.h" -#include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" @@ -320,11 +319,11 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { PushOnScopeChains(MDecl->getCmdDecl(), FnBodyScope); // The ObjC parser requires parameter names so there's no need to check. - CheckParmsForFunctionDef(MDecl->param_begin(), MDecl->param_end(), + CheckParmsForFunctionDef(MDecl->parameters(), /*CheckParameterNames=*/false); // Introduce all of the other parameters into this scope. - for (auto *Param : MDecl->params()) { + for (auto *Param : MDecl->parameters()) { if (!Param->isInvalidDecl() && getLangOpts().ObjCAutoRefCount && !HasExplicitOwnershipAttr(*this, Param)) @@ -1303,6 +1302,16 @@ class ObjCTypeArgOrProtocolValidatorCCC : public CorrectionCandidateCallback { }; } // end anonymous namespace +void Sema::DiagnoseTypeArgsAndProtocols(IdentifierInfo *ProtocolId, + SourceLocation ProtocolLoc, + IdentifierInfo *TypeArgId, + SourceLocation TypeArgLoc, + bool SelectProtocolFirst) { + Diag(TypeArgLoc, diag::err_objc_type_args_and_protocols) + << SelectProtocolFirst << TypeArgId << ProtocolId + << SourceRange(ProtocolLoc); +} + void Sema::actOnObjCTypeArgsOrProtocolQualifiers( Scope *S, ParsedType baseType, @@ -1493,6 +1502,7 @@ void Sema::actOnObjCTypeArgsOrProtocolQualifiers( SourceLocation(), SourceLocation(), SourceLocation(), + SourceLocation(), SourceLocation()), parsedAttrs, starLoc); @@ -1570,11 +1580,9 @@ void Sema::actOnObjCTypeArgsOrProtocolQualifiers( // We have a conflict: some names refer to protocols and others // refer to types. - Diag(identifierLocs[i], diag::err_objc_type_args_and_protocols) - << (protocols[i] != nullptr) - << identifiers[i] - << identifiers[0] - << SourceRange(identifierLocs[0]); + DiagnoseTypeArgsAndProtocols(identifiers[0], identifierLocs[0], + identifiers[i], identifierLocs[i], + protocols[i] != nullptr); protocols.clear(); typeArgs.clear(); @@ -1831,6 +1839,13 @@ Decl *Sema::ActOnStartCategoryImplementation( if (IDecl) DiagnoseUseOfDecl(IDecl, ClassLoc); + // If the interface has the objc_runtime_visible attribute, we + // cannot implement a category for it. + if (IDecl && IDecl->hasAttr<ObjCRuntimeVisibleAttr>()) { + Diag(ClassLoc, diag::err_objc_runtime_visible_category) + << IDecl->getDeclName(); + } + /// Check that CatName, category name, is not used in another implementation. if (CatIDecl) { if (CatIDecl->getImplementation()) { @@ -1968,6 +1983,16 @@ Decl *Sema::ActOnStartClassImplementation( dyn_cast<NamedDecl>(IDecl), IMPDecl->getLocation(), 1); } + + // If the superclass has the objc_runtime_visible attribute, we + // cannot implement a subclass of it. + if (IDecl->getSuperClass() && + IDecl->getSuperClass()->hasAttr<ObjCRuntimeVisibleAttr>()) { + Diag(ClassLoc, diag::err_objc_runtime_visible_subclass) + << IDecl->getDeclName() + << IDecl->getSuperClass()->getDeclName(); + } + return ActOnObjCContainerStartDefinition(IMPDecl); } @@ -2734,7 +2759,8 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap, for (auto *I : CDecl->class_methods()) { if (!ClsMapSeen.insert(I->getSelector()).second) continue; - if (!ClsMap.count(I->getSelector())) { + if (!I->isPropertyAccessor() && + !ClsMap.count(I->getSelector())) { if (ImmediateClass) WarnUndefinedMethod(*this, IMPDecl->getLocation(), I, IncompleteImpl, diag::warn_undef_method_impl); @@ -2743,12 +2769,14 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap, IMPDecl->getClassMethod(I->getSelector()); assert(CDecl->getClassMethod(I->getSelector()) && "Expected to find the method through lookup as well"); - if (!WarnCategoryMethodImpl) - WarnConflictingTypedMethods(ImpMethodDecl, I, - isa<ObjCProtocolDecl>(CDecl)); - else - WarnExactTypedMethods(ImpMethodDecl, I, - isa<ObjCProtocolDecl>(CDecl)); + // ImpMethodDecl may be null as in a @dynamic property. + if (ImpMethodDecl) { + if (!WarnCategoryMethodImpl) + WarnConflictingTypedMethods(ImpMethodDecl, I, + isa<ObjCProtocolDecl>(CDecl)); + else if (!I->isPropertyAccessor()) + WarnExactTypedMethods(ImpMethodDecl, I, isa<ObjCProtocolDecl>(CDecl)); + } } } @@ -3147,6 +3175,26 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left, return true; } +static bool isMethodContextSameForKindofLookup(ObjCMethodDecl *Method, + ObjCMethodDecl *MethodInList) { + auto *MethodProtocol = dyn_cast<ObjCProtocolDecl>(Method->getDeclContext()); + auto *MethodInListProtocol = + dyn_cast<ObjCProtocolDecl>(MethodInList->getDeclContext()); + // If this method belongs to a protocol but the method in list does not, or + // vice versa, we say the context is not the same. + if ((MethodProtocol && !MethodInListProtocol) || + (!MethodProtocol && MethodInListProtocol)) + return false; + + if (MethodProtocol && MethodInListProtocol) + return true; + + ObjCInterfaceDecl *MethodInterface = Method->getClassInterface(); + ObjCInterfaceDecl *MethodInListInterface = + MethodInList->getClassInterface(); + return MethodInterface == MethodInListInterface; +} + void Sema::addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method) { // Record at the head of the list whether there were 0, 1, or >= 2 methods @@ -3166,17 +3214,42 @@ void Sema::addMethodToGlobalList(ObjCMethodList *List, // We've seen a method with this name, see if we have already seen this type // signature. ObjCMethodList *Previous = List; + ObjCMethodList *ListWithSameDeclaration = nullptr; for (; List; Previous = List, List = List->getNext()) { // If we are building a module, keep all of the methods. - if (getLangOpts().Modules && !getLangOpts().CurrentModule.empty()) + if (getLangOpts().CompilingModule) continue; - if (!MatchTwoMethodDeclarations(Method, List->getMethod())) { + bool SameDeclaration = MatchTwoMethodDeclarations(Method, + List->getMethod()); + // Looking for method with a type bound requires the correct context exists. + // We need to insert a method into the list if the context is different. + // If the method's declaration matches the list + // a> the method belongs to a different context: we need to insert it, in + // order to emit the availability message, we need to prioritize over + // availability among the methods with the same declaration. + // b> the method belongs to the same context: there is no need to insert a + // new entry. + // If the method's declaration does not match the list, we insert it to the + // end. + if (!SameDeclaration || + !isMethodContextSameForKindofLookup(Method, List->getMethod())) { // Even if two method types do not match, we would like to say // there is more than one declaration so unavailability/deprecated // warning is not too noisy. if (!Method->isDefined()) List->setHasMoreThanOneDecl(true); + + // For methods with the same declaration, the one that is deprecated + // should be put in the front for better diagnostics. + if (Method->isDeprecated() && SameDeclaration && + !ListWithSameDeclaration && !List->getMethod()->isDeprecated()) + ListWithSameDeclaration = List; + + if (Method->isUnavailable() && SameDeclaration && + !ListWithSameDeclaration && + List->getMethod()->getAvailability() < AR_Deprecated) + ListWithSameDeclaration = List; continue; } @@ -3212,6 +3285,16 @@ void Sema::addMethodToGlobalList(ObjCMethodList *List, // We have a new signature for an existing method - add it. // This is extremely rare. Only 1% of Cocoa selectors are "overloaded". ObjCMethodList *Mem = BumpAlloc.Allocate<ObjCMethodList>(); + + // We insert it right before ListWithSameDeclaration. + if (ListWithSameDeclaration) { + auto *List = new (Mem) ObjCMethodList(*ListWithSameDeclaration); + // FIXME: should we clear the other bits in ListWithSameDeclaration? + ListWithSameDeclaration->setMethod(Method); + ListWithSameDeclaration->setNext(List); + return; + } + Previous->setNext(new (Mem) ObjCMethodList(Method)); } @@ -3222,6 +3305,12 @@ void Sema::ReadMethodPool(Selector Sel) { ExternalSource->ReadMethodPool(Sel); } +void Sema::updateOutOfDateSelector(Selector Sel) { + if (!ExternalSource) + return; + ExternalSource->updateOutOfDateSelector(Sel); +} + void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, bool instance) { // Ignore methods of invalid containers. @@ -3261,25 +3350,95 @@ static bool isAcceptableMethodMismatch(ObjCMethodDecl *chosen, return (chosen->getReturnType()->isIntegerType()); } +/// Return true if the given method is wthin the type bound. +static bool FilterMethodsByTypeBound(ObjCMethodDecl *Method, + const ObjCObjectType *TypeBound) { + if (!TypeBound) + return true; + + if (TypeBound->isObjCId()) + // FIXME: should we handle the case of bounding to id<A, B> differently? + return true; + + auto *BoundInterface = TypeBound->getInterface(); + assert(BoundInterface && "unexpected object type!"); + + // Check if the Method belongs to a protocol. We should allow any method + // defined in any protocol, because any subclass could adopt the protocol. + auto *MethodProtocol = dyn_cast<ObjCProtocolDecl>(Method->getDeclContext()); + if (MethodProtocol) { + return true; + } + + // If the Method belongs to a class, check if it belongs to the class + // hierarchy of the class bound. + if (ObjCInterfaceDecl *MethodInterface = Method->getClassInterface()) { + // We allow methods declared within classes that are part of the hierarchy + // of the class bound (superclass of, subclass of, or the same as the class + // bound). + return MethodInterface == BoundInterface || + MethodInterface->isSuperClassOf(BoundInterface) || + BoundInterface->isSuperClassOf(MethodInterface); + } + llvm_unreachable("unknow method context"); +} + +/// We first select the type of the method: Instance or Factory, then collect +/// all methods with that type. bool Sema::CollectMultipleMethodsInGlobalPool( - Selector Sel, SmallVectorImpl<ObjCMethodDecl *> &Methods, bool instance) { + Selector Sel, SmallVectorImpl<ObjCMethodDecl *> &Methods, + bool InstanceFirst, bool CheckTheOther, + const ObjCObjectType *TypeBound) { if (ExternalSource) ReadMethodPool(Sel); GlobalMethodPool::iterator Pos = MethodPool.find(Sel); if (Pos == MethodPool.end()) return false; + // Gather the non-hidden methods. - ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second; + ObjCMethodList &MethList = InstanceFirst ? Pos->second.first : + Pos->second.second; for (ObjCMethodList *M = &MethList; M; M = M->getNext()) - if (M->getMethod() && !M->getMethod()->isHidden()) - Methods.push_back(M->getMethod()); + if (M->getMethod() && !M->getMethod()->isHidden()) { + if (FilterMethodsByTypeBound(M->getMethod(), TypeBound)) + Methods.push_back(M->getMethod()); + } + + // Return if we find any method with the desired kind. + if (!Methods.empty()) + return Methods.size() > 1; + + if (!CheckTheOther) + return false; + + // Gather the other kind. + ObjCMethodList &MethList2 = InstanceFirst ? Pos->second.second : + Pos->second.first; + for (ObjCMethodList *M = &MethList2; M; M = M->getNext()) + if (M->getMethod() && !M->getMethod()->isHidden()) { + if (FilterMethodsByTypeBound(M->getMethod(), TypeBound)) + Methods.push_back(M->getMethod()); + } + return Methods.size() > 1; } -bool Sema::AreMultipleMethodsInGlobalPool(Selector Sel, ObjCMethodDecl *BestMethod, - SourceRange R, - bool receiverIdOrClass) { +bool Sema::AreMultipleMethodsInGlobalPool( + Selector Sel, ObjCMethodDecl *BestMethod, SourceRange R, + bool receiverIdOrClass, SmallVectorImpl<ObjCMethodDecl *> &Methods) { + // Diagnose finding more than one method in global pool. + SmallVector<ObjCMethodDecl *, 4> FilteredMethods; + FilteredMethods.push_back(BestMethod); + + for (auto *M : Methods) + if (M != BestMethod && !M->hasAttr<UnavailableAttr>()) + FilteredMethods.push_back(M); + + if (FilteredMethods.size() > 1) + DiagnoseMultipleMethodInGlobalPool(FilteredMethods, Sel, R, + receiverIdOrClass); + GlobalMethodPool::iterator Pos = MethodPool.find(Sel); // Test for no method in the pool which should not trigger any warning by // caller. @@ -3287,17 +3446,6 @@ bool Sema::AreMultipleMethodsInGlobalPool(Selector Sel, ObjCMethodDecl *BestMeth return true; ObjCMethodList &MethList = BestMethod->isInstanceMethod() ? Pos->second.first : Pos->second.second; - - // Diagnose finding more than one method in global pool - SmallVector<ObjCMethodDecl *, 4> Methods; - Methods.push_back(BestMethod); - for (ObjCMethodList *ML = &MethList; ML; ML = ML->getNext()) - if (ObjCMethodDecl *M = ML->getMethod()) - if (!M->isHidden() && M != BestMethod && !M->hasAttr<UnavailableAttr>()) - Methods.push_back(M); - if (Methods.size() > 1) - DiagnoseMultipleMethodInGlobalPool(Methods, Sel, R, receiverIdOrClass); - return MethList.hasMoreThanOneDecl(); } @@ -3650,10 +3798,11 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods, // property will be synthesized when property with same name is // seen in the @implementation. for (const auto *Ext : IDecl->visible_extensions()) { - for (const auto *Property : Ext->properties()) { + for (const auto *Property : Ext->instance_properties()) { // Skip over properties declared @dynamic if (const ObjCPropertyImplDecl *PIDecl - = IC->FindPropertyImplDecl(Property->getIdentifier())) + = IC->FindPropertyImplDecl(Property->getIdentifier(), + Property->getQueryKind())) if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) continue; @@ -3839,7 +3988,7 @@ public: } } - typedef llvm::SmallPtrSet<ObjCMethodDecl*, 128>::iterator iterator; + typedef llvm::SmallPtrSetImpl<ObjCMethodDecl*>::iterator iterator; iterator begin() const { return Overridden.begin(); } iterator end() const { return Overridden.end(); } @@ -4463,6 +4612,9 @@ Decl *Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) { Diag(DS.getStorageClassSpecLoc(), diag::err_storage_spec_on_catch_parm) << DeclSpec::getSpecifierName(SCS); } + if (DS.isInlineSpecified()) + Diag(DS.getInlineSpecLoc(), diag::err_inline_non_function) + << getLangOpts().CPlusPlus1z; if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), diag::err_invalid_thread) |