diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp | 883 |
1 files changed, 445 insertions, 438 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp index f44fb32..b5205b3 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp @@ -15,11 +15,11 @@ #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" +#include "clang/AST/DataRecursiveASTVisitor.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprObjC.h" #include "clang/Basic/SourceManager.h" -#include "clang/Lex/Preprocessor.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/Lookup.h" @@ -48,8 +48,8 @@ bool Sema::checkInitMethod(ObjCMethodDecl *method, // We ignore protocols here. Should we? What about Class? - const ObjCObjectType *result = method->getResultType() - ->castAs<ObjCObjectPointerType>()->getObjectType(); + const ObjCObjectType *result = + method->getReturnType()->castAs<ObjCObjectPointerType>()->getObjectType(); if (result->isObjCId()) { return false; @@ -70,7 +70,7 @@ bool Sema::checkInitMethod(ObjCMethodDecl *method, } else { // If this method was declared in a protocol, we can't check // anything unless we have a receiver type that's an interface. - const ObjCInterfaceDecl *receiverClass = 0; + const ObjCInterfaceDecl *receiverClass = nullptr; if (isa<ObjCProtocolDecl>(method->getDeclContext())) { if (receiverTypeIfCall.isNull()) return false; @@ -97,8 +97,9 @@ bool Sema::checkInitMethod(ObjCMethodDecl *method, // If we're in a system header, and this is not a call, just make // the method unusable. if (receiverTypeIfCall.isNull() && getSourceManager().isInSystemHeader(loc)) { - method->addAttr(new (Context) UnavailableAttr(loc, Context, - "init method returns a type unrelated to its receiver type")); + method->addAttr(UnavailableAttr::CreateImplicit(Context, + "init method returns a type unrelated to its receiver type", + loc)); return true; } @@ -116,10 +117,10 @@ void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, // implies a related result type, and the original (overridden) method has // a suitable return type, but the new (overriding) method does not have // a suitable return type. - QualType ResultType = NewMethod->getResultType(); + QualType ResultType = NewMethod->getReturnType(); SourceRange ResultTypeRange; - if (const TypeSourceInfo *ResultTypeInfo - = NewMethod->getResultTypeSourceInfo()) + if (const TypeSourceInfo *ResultTypeInfo = + NewMethod->getReturnTypeSourceInfo()) ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange(); // Figure out which class this method is part of, if any. @@ -207,19 +208,19 @@ bool Sema::CheckARCMethodDecl(ObjCMethodDecl *method) { return false; case OMF_dealloc: - if (!Context.hasSameType(method->getResultType(), Context.VoidTy)) { + if (!Context.hasSameType(method->getReturnType(), Context.VoidTy)) { SourceRange ResultTypeRange; - if (const TypeSourceInfo *ResultTypeInfo - = method->getResultTypeSourceInfo()) + if (const TypeSourceInfo *ResultTypeInfo = + method->getReturnTypeSourceInfo()) ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange(); if (ResultTypeRange.isInvalid()) - Diag(method->getLocation(), diag::error_dealloc_bad_result_type) - << method->getResultType() - << FixItHint::CreateInsertion(method->getSelectorLoc(0), "(void)"); + Diag(method->getLocation(), diag::error_dealloc_bad_result_type) + << method->getReturnType() + << FixItHint::CreateInsertion(method->getSelectorLoc(0), "(void)"); else - Diag(method->getLocation(), diag::error_dealloc_bad_result_type) - << method->getResultType() - << FixItHint::CreateReplacement(ResultTypeRange, "void"); + Diag(method->getLocation(), diag::error_dealloc_bad_result_type) + << method->getReturnType() + << FixItHint::CreateReplacement(ResultTypeRange, "void"); return true; } return false; @@ -229,8 +230,7 @@ bool Sema::CheckARCMethodDecl(ObjCMethodDecl *method) { if (checkInitMethod(method, QualType())) return true; - method->addAttr(new (Context) NSConsumesSelfAttr(SourceLocation(), - Context)); + method->addAttr(NSConsumesSelfAttr::CreateImplicit(Context)); // Don't add a second copy of this attribute, but otherwise don't // let it be suppressed. @@ -249,8 +249,7 @@ bool Sema::CheckARCMethodDecl(ObjCMethodDecl *method) { break; } - method->addAttr(new (Context) NSReturnsRetainedAttr(SourceLocation(), - Context)); + method->addAttr(NSReturnsRetainedAttr::CreateImplicit(Context)); return false; } @@ -304,7 +303,7 @@ HasExplicitOwnershipAttr(Sema &S, ParmVarDecl *Param) { /// ActOnStartOfObjCMethodDef - This routine sets up parameters; invisible /// and user declared, in the method definition's AST. void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { - assert((getCurMethodDecl() == 0) && "Methodparsing confused"); + assert((getCurMethodDecl() == nullptr) && "Methodparsing confused"); ObjCMethodDecl *MDecl = dyn_cast_or_null<ObjCMethodDecl>(D); // If we don't have a valid method decl, simply return. @@ -329,17 +328,15 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { /*CheckParameterNames=*/false); // Introduce all of the other parameters into this scope. - for (ObjCMethodDecl::param_iterator PI = MDecl->param_begin(), - E = MDecl->param_end(); PI != E; ++PI) { - ParmVarDecl *Param = (*PI); + for (auto *Param : MDecl->params()) { if (!Param->isInvalidDecl() && getLangOpts().ObjCAutoRefCount && !HasExplicitOwnershipAttr(*this, Param)) Diag(Param->getLocation(), diag::warn_arc_strong_pointer_objc_pointer) << Param->getType(); - if ((*PI)->getIdentifier()) - PushOnScopeChains(*PI, FnBodyScope); + if (Param->getIdentifier()) + PushOnScopeChains(Param, FnBodyScope); } // In ARC, disallow definition of retain/release/autorelease/retainCount @@ -378,11 +375,16 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { dyn_cast<ObjCImplDecl>(MDecl->getDeclContext()); ObjCContainerDecl *ContDeclOfMethodDecl = dyn_cast<ObjCContainerDecl>(IMD->getDeclContext()); - ObjCImplDecl *ImplDeclOfMethodDecl = 0; + ObjCImplDecl *ImplDeclOfMethodDecl = nullptr; if (ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ContDeclOfMethodDecl)) ImplDeclOfMethodDecl = OID->getImplementation(); - else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContDeclOfMethodDecl)) - ImplDeclOfMethodDecl = CD->getImplementation(); + else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContDeclOfMethodDecl)) { + if (CD->IsClassExtension()) { + if (ObjCInterfaceDecl *OID = CD->getClassInterface()) + ImplDeclOfMethodDecl = OID->getImplementation(); + } else + ImplDeclOfMethodDecl = CD->getImplementation(); + } // No need to issue deprecated warning if deprecated mehod in class/category // is being implemented in its own implementation (no overriding is involved). if (!ImplDeclOfMethodDecl || ImplDeclOfMethodDecl != ImplDeclOfMethodDef) @@ -391,6 +393,17 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { MDecl->getLocation(), 0); } + if (MDecl->getMethodFamily() == OMF_init) { + if (MDecl->isDesignatedInitializerForTheInterface()) { + getCurFunction()->ObjCIsDesignatedInit = true; + getCurFunction()->ObjCWarnForNoDesignatedInitChain = + IC->getSuperClass() != nullptr; + } else if (IC->hasDesignatedInitializers()) { + getCurFunction()->ObjCIsSecondaryInit = true; + getCurFunction()->ObjCWarnForNoInitDelegation = true; + } + } + // If this is "dealloc" or "finalize", set some bit here. // Then in ActOnSuperMessage() (SemaExprObjC), set it back to false. // Finally, in ActOnFinishFunctionBody() (SemaDecl), warn if flag is set. @@ -424,11 +437,11 @@ namespace { // function will reject corrections to that class. class ObjCInterfaceValidatorCCC : public CorrectionCandidateCallback { public: - ObjCInterfaceValidatorCCC() : CurrentIDecl(0) {} + ObjCInterfaceValidatorCCC() : CurrentIDecl(nullptr) {} explicit ObjCInterfaceValidatorCCC(ObjCInterfaceDecl *IDecl) : CurrentIDecl(IDecl) {} - virtual bool ValidateCandidate(const TypoCorrection &candidate) { + bool ValidateCandidate(const TypoCorrection &candidate) override { ObjCInterfaceDecl *ID = candidate.getCorrectionDeclAs<ObjCInterfaceDecl>(); return ID && !declaresSameEntity(ID, CurrentIDecl); } @@ -510,7 +523,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, ObjCInterfaceValidatorCCC Validator(IDecl); if (TypoCorrection Corrected = CorrectTypo( DeclarationNameInfo(SuperName, SuperLoc), LookupOrdinaryName, TUScope, - NULL, Validator)) { + nullptr, Validator, CTK_ErrorRecovery)) { diagnoseTypo(Corrected, PDiag(diag::err_undef_superclass_suggest) << SuperName << ClassName); PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>(); @@ -529,7 +542,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, if (SuperClassDecl) (void)DiagnoseUseOfDecl(SuperClassDecl, SuperLoc); - if (PrevDecl && SuperClassDecl == 0) { + if (PrevDecl && !SuperClassDecl) { // The previous declaration was not a class decl. Check if we have a // typedef. If we do, get the underlying class type. if (const TypedefNameDecl *TDecl = @@ -568,7 +581,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, SuperClassDecl->getDeclName(), ClassName, SourceRange(AtInterfaceLoc, ClassLoc))) { - SuperClassDecl = 0; + SuperClassDecl = nullptr; } } IDecl->setSuperClass(SuperClassDecl); @@ -607,9 +620,8 @@ void Sema::ActOnTypedefedProtocols(SmallVectorImpl<Decl *> &ProtocolRefs, QualType T = TDecl->getUnderlyingType(); if (T->isObjCObjectType()) if (const ObjCObjectType *OPT = T->getAs<ObjCObjectType>()) - for (ObjCObjectType::qual_iterator I = OPT->qual_begin(), - E = OPT->qual_end(); I != E; ++I) - ProtocolRefs.push_back(*I); + for (auto *I : OPT->quals()) + ProtocolRefs.push_back(I); } } @@ -626,7 +638,7 @@ Decl *Sema::ActOnCompatibilityAlias(SourceLocation AtLoc, if (ADecl) { Diag(AliasLocation, diag::err_conflicting_aliasing_type) << AliasName; Diag(ADecl->getLocation(), diag::note_previous_declaration); - return 0; + return nullptr; } // Check for class declaration NamedDecl *CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation, @@ -643,11 +655,11 @@ Decl *Sema::ActOnCompatibilityAlias(SourceLocation AtLoc, } } ObjCInterfaceDecl *CDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDeclU); - if (CDecl == 0) { + if (!CDecl) { Diag(ClassLocation, diag::warn_undef_interface) << ClassName; if (CDeclU) Diag(CDeclU->getLocation(), diag::note_previous_declaration); - return 0; + return nullptr; } // Everything checked out, instantiate a new alias declaration AST. @@ -701,8 +713,8 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, assert(ProtocolName && "Missing protocol identifier"); ObjCProtocolDecl *PrevDecl = LookupProtocol(ProtocolName, ProtocolLoc, ForRedeclaration); - ObjCProtocolDecl *PDecl = 0; - if (ObjCProtocolDecl *Def = PrevDecl? PrevDecl->getDefinition() : 0) { + ObjCProtocolDecl *PDecl = nullptr; + if (ObjCProtocolDecl *Def = PrevDecl? PrevDecl->getDefinition() : nullptr) { // If we already have a definition, complain. Diag(ProtocolLoc, diag::warn_duplicate_protocol_def) << ProtocolName; Diag(Def->getLocation(), diag::note_previous_definition); @@ -713,7 +725,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, // FIXME: Can we turn this into an error? PDecl = ObjCProtocolDecl::Create(Context, CurContext, ProtocolName, ProtocolLoc, AtProtoInterfaceLoc, - /*PrevDecl=*/0); + /*PrevDecl=*/nullptr); PDecl->startDefinition(); } else { if (PrevDecl) { @@ -751,6 +763,21 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, return ActOnObjCContainerStartDefinition(PDecl); } +static bool NestedProtocolHasNoDefinition(ObjCProtocolDecl *PDecl, + ObjCProtocolDecl *&UndefinedProtocol) { + if (!PDecl->hasDefinition() || PDecl->getDefinition()->isHidden()) { + UndefinedProtocol = PDecl; + return true; + } + + for (auto *PI : PDecl->protocols()) + if (NestedProtocolHasNoDefinition(PI, UndefinedProtocol)) { + UndefinedProtocol = PI; + return true; + } + return false; +} + /// FindProtocolDeclaration - This routine looks up protocols and /// issues an error if they are not declared. It returns list of /// protocol declarations in its 'Protocols' argument. @@ -766,7 +793,8 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations, DeclFilterCCC<ObjCProtocolDecl> Validator; TypoCorrection Corrected = CorrectTypo( DeclarationNameInfo(ProtocolId[i].first, ProtocolId[i].second), - LookupObjCProtocolName, TUScope, NULL, Validator); + LookupObjCProtocolName, TUScope, nullptr, Validator, + CTK_ErrorRecovery); if ((PDecl = Corrected.getCorrectionDeclAs<ObjCProtocolDecl>())) diagnoseTypo(Corrected, PDiag(diag::err_undeclared_protocol_suggest) << ProtocolId[i].first); @@ -786,10 +814,15 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations, // If this is a forward declaration and we are supposed to warn in this // case, do it. // FIXME: Recover nicely in the hidden case. + ObjCProtocolDecl *UndefinedProtocol; + if (WarnOnDeclarations && - (!PDecl->hasDefinition() || PDecl->getDefinition()->isHidden())) + NestedProtocolHasNoDefinition(PDecl, UndefinedProtocol)) { Diag(ProtocolId[i].second, diag::warn_undef_protocolref) << ProtocolId[i].first; + Diag(UndefinedProtocol->getLocation(), diag::note_protocol_decl_undefined) + << UndefinedProtocol; + } Protocols.push_back(PDecl); } } @@ -803,19 +836,16 @@ void Sema::DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT, return; // Possibly due to previous error llvm::DenseMap<Selector, const ObjCMethodDecl*> MethodMap; - for (ObjCInterfaceDecl::method_iterator i = ID->meth_begin(), - e = ID->meth_end(); i != e; ++i) { - ObjCMethodDecl *MD = *i; + for (auto *MD : ID->methods()) MethodMap[MD->getSelector()] = MD; - } if (MethodMap.empty()) return; - for (ObjCCategoryDecl::method_iterator i = CAT->meth_begin(), - e = CAT->meth_end(); i != e; ++i) { - ObjCMethodDecl *Method = *i; + for (const auto *Method : CAT->methods()) { const ObjCMethodDecl *&PrevMethod = MethodMap[Method->getSelector()]; - if (PrevMethod && !MatchTwoMethodDeclarations(Method, PrevMethod)) { + if (PrevMethod && + (PrevMethod->isInstanceMethod() == Method->isInstanceMethod()) && + !MatchTwoMethodDeclarations(Method, PrevMethod)) { Diag(Method->getLocation(), diag::err_duplicate_method_decl) << Method->getDeclName(); Diag(PrevMethod->getLocation(), diag::note_previous_declaration); @@ -871,7 +901,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, if (!IDecl || RequireCompleteType(ClassLoc, Context.getObjCInterfaceType(IDecl), diag::err_category_forward_interface, - CategoryName == 0)) { + CategoryName == nullptr)) { // Create an invalid ObjCCategoryDecl to serve as context for // the enclosing method declarations. We mark the decl invalid // to make it clear that this isn't a valid AST. @@ -928,7 +958,7 @@ Decl *Sema::ActOnStartCategoryImplementation( IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *CatName, SourceLocation CatLoc) { ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc, true); - ObjCCategoryDecl *CatIDecl = 0; + ObjCCategoryDecl *CatIDecl = nullptr; if (IDecl && IDecl->hasDefinition()) { CatIDecl = IDecl->FindCategoryDeclaration(CatName); if (!CatIDecl) { @@ -987,7 +1017,7 @@ Decl *Sema::ActOnStartClassImplementation( IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *SuperClassname, SourceLocation SuperClassLoc) { - ObjCInterfaceDecl *IDecl = 0; + ObjCInterfaceDecl *IDecl = nullptr; // Check for another declaration kind with the same name. NamedDecl *PrevDecl = LookupSingleName(TUScope, ClassName, ClassLoc, LookupOrdinaryName, @@ -1004,7 +1034,8 @@ Decl *Sema::ActOnStartClassImplementation( ObjCInterfaceValidatorCCC Validator; TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(ClassName, ClassLoc), - LookupOrdinaryName, TUScope, NULL, Validator); + LookupOrdinaryName, TUScope, nullptr, Validator, + CTK_NonError); if (Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) { // Suggest the (potentially) correct interface name. Don't provide a // code-modification hint or use the typo name for recovery, because @@ -1018,7 +1049,7 @@ Decl *Sema::ActOnStartClassImplementation( } // Check that super class name is valid class name - ObjCInterfaceDecl* SDecl = 0; + ObjCInterfaceDecl *SDecl = nullptr; if (SuperClassname) { // Check if a different kind of symbol declared in this scope. PrevDecl = LookupSingleName(TUScope, SuperClassname, SuperClassLoc, @@ -1030,7 +1061,7 @@ Decl *Sema::ActOnStartClassImplementation( } else { SDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); if (SDecl && !SDecl->hasDefinition()) - SDecl = 0; + SDecl = nullptr; if (!SDecl) Diag(SuperClassLoc, diag::err_undef_superclass) << SuperClassname << ClassName; @@ -1051,7 +1082,7 @@ Decl *Sema::ActOnStartClassImplementation( // FIXME: Do we support attributes on the @implementation? If so we should // copy them over. IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassImplLoc, - ClassName, /*PrevDecl=*/0, ClassLoc, + ClassName, /*PrevDecl=*/nullptr, ClassLoc, true); IDecl->startDefinition(); if (SDecl) { @@ -1154,11 +1185,7 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, continue; } // Check class extensions (unnamed categories) for duplicate ivars. - for (ObjCInterfaceDecl::visible_extensions_iterator - Ext = IDecl->visible_extensions_begin(), - ExtEnd = IDecl->visible_extensions_end(); - Ext != ExtEnd; ++Ext) { - ObjCCategoryDecl *CDecl = *Ext; + for (const auto *CDecl : IDecl->visible_extensions()) { if (const ObjCIvarDecl *ClsExtIvar = CDecl->getIvarDecl(ImplIvar->getIdentifier())) { Diag(ImplIvar->getLocation(), diag::err_duplicate_ivar_declaration); @@ -1209,13 +1236,16 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, } if (numIvars > 0) - Diag(ivars[j]->getLocation(), diag::err_inconsistant_ivar_count); + Diag(ivars[j]->getLocation(), diag::err_inconsistent_ivar_count); else if (IVI != IVE) - Diag(IVI->getLocation(), diag::err_inconsistant_ivar_count); + Diag(IVI->getLocation(), diag::err_inconsistent_ivar_count); } -void Sema::WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method, - bool &IncompleteImpl, unsigned DiagID) { +static void WarnUndefinedMethod(Sema &S, SourceLocation ImpLoc, + ObjCMethodDecl *method, + bool &IncompleteImpl, + unsigned DiagID, + NamedDecl *NeededFor = nullptr) { // No point warning no definition of method which is 'unavailable'. switch (method->getAvailability()) { case AR_Available: @@ -1233,13 +1263,17 @@ void Sema::WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method, // warning, but some users strongly voiced that they would prefer // separate warnings. We will give that approach a try, as that // matches what we do with protocols. - - Diag(ImpLoc, DiagID) << method->getDeclName(); + { + const Sema::SemaDiagnosticBuilder &B = S.Diag(ImpLoc, DiagID); + B << method; + if (NeededFor) + B << NeededFor; + } // Issue a note to the original declaration. SourceLocation MethodLoc = method->getLocStart(); if (MethodLoc.isValid()) - Diag(MethodLoc, diag::note_method_declared_at) << method; + S.Diag(MethodLoc, diag::note_method_declared_at) << method; } /// Determines if type B can be substituted for type A. Returns true if we can @@ -1323,21 +1357,21 @@ static bool CheckMethodOverrideReturn(Sema &S, (MethodDecl->getObjCDeclQualifier() != MethodImpl->getObjCDeclQualifier())) { if (Warn) { - S.Diag(MethodImpl->getLocation(), - (IsOverridingMode ? - diag::warn_conflicting_overriding_ret_type_modifiers - : diag::warn_conflicting_ret_type_modifiers)) + S.Diag(MethodImpl->getLocation(), + (IsOverridingMode + ? diag::warn_conflicting_overriding_ret_type_modifiers + : diag::warn_conflicting_ret_type_modifiers)) << MethodImpl->getDeclName() - << getTypeRange(MethodImpl->getResultTypeSourceInfo()); - S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration) - << getTypeRange(MethodDecl->getResultTypeSourceInfo()); + << getTypeRange(MethodImpl->getReturnTypeSourceInfo()); + S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration) + << getTypeRange(MethodDecl->getReturnTypeSourceInfo()); } else return false; } - - if (S.Context.hasSameUnqualifiedType(MethodImpl->getResultType(), - MethodDecl->getResultType())) + + if (S.Context.hasSameUnqualifiedType(MethodImpl->getReturnType(), + MethodDecl->getReturnType())) return true; if (!Warn) return false; @@ -1349,9 +1383,9 @@ static bool CheckMethodOverrideReturn(Sema &S, // Mismatches between ObjC pointers go into a different warning // category, and sometimes they're even completely whitelisted. if (const ObjCObjectPointerType *ImplPtrTy = - MethodImpl->getResultType()->getAs<ObjCObjectPointerType>()) { + MethodImpl->getReturnType()->getAs<ObjCObjectPointerType>()) { if (const ObjCObjectPointerType *IfacePtrTy = - MethodDecl->getResultType()->getAs<ObjCObjectPointerType>()) { + MethodDecl->getReturnType()->getAs<ObjCObjectPointerType>()) { // Allow non-matching return types as long as they don't violate // the principle of substitutability. Specifically, we permit // return types that are subclasses of the declared return type, @@ -1366,14 +1400,13 @@ static bool CheckMethodOverrideReturn(Sema &S, } S.Diag(MethodImpl->getLocation(), DiagID) - << MethodImpl->getDeclName() - << MethodDecl->getResultType() - << MethodImpl->getResultType() - << getTypeRange(MethodImpl->getResultTypeSourceInfo()); - S.Diag(MethodDecl->getLocation(), - IsOverridingMode ? diag::note_previous_declaration - : diag::note_previous_definition) - << getTypeRange(MethodDecl->getResultTypeSourceInfo()); + << MethodImpl->getDeclName() << MethodDecl->getReturnType() + << MethodImpl->getReturnType() + << getTypeRange(MethodImpl->getReturnTypeSourceInfo()); + S.Diag(MethodDecl->getLocation(), IsOverridingMode + ? diag::note_previous_declaration + : diag::note_previous_definition) + << getTypeRange(MethodDecl->getReturnTypeSourceInfo()); return false; } @@ -1505,7 +1538,7 @@ static bool checkMethodFamilyMismatch(Sema &S, ObjCMethodDecl *impl, // The only reason these methods don't fall within their families is // due to unusual result types. - if (unmatched->getResultType()->isObjCObjectPointerType()) { + if (unmatched->getReturnType()->isObjCObjectPointerType()) { reasonSelector = R_UnrelatedReturn; } else { reasonSelector = R_NonObjectReturn; @@ -1615,22 +1648,75 @@ 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 std::unique_ptr<ProtocolNameSet> LazyProtocolNameSet; + +static void findProtocolsWithExplicitImpls(const ObjCProtocolDecl *PDecl, + ProtocolNameSet &PNS) { + if (PDecl->hasAttr<ObjCExplicitProtocolImplAttr>()) + PNS.insert(PDecl->getIdentifier()); + for (const auto *PI : PDecl->protocols()) + findProtocolsWithExplicitImpls(PI, PNS); +} + +/// 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 (const auto *I : Super->all_referenced_protocols()) + findProtocolsWithExplicitImpls(I, PNS); + + findProtocolsWithExplicitImpls(Super->getSuperClass(), PNS); +} + /// CheckProtocolMethodDefs - This routine checks unimplemented methods /// Declared in protocol, and those referenced by it. -void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, - ObjCProtocolDecl *PDecl, - bool& IncompleteImpl, - const SelectorSet &InsMap, - const SelectorSet &ClsMap, - ObjCContainerDecl *CDecl) { +static void CheckProtocolMethodDefs(Sema &S, + SourceLocation ImpLoc, + ObjCProtocolDecl *PDecl, + bool& IncompleteImpl, + const Sema::SelectorSet &InsMap, + const Sema::SelectorSet &ClsMap, + ObjCContainerDecl *CDecl, + LazyProtocolNameSet &ProtocolsExplictImpl) { ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl); ObjCInterfaceDecl *IDecl = C ? C->getClassInterface() : dyn_cast<ObjCInterfaceDecl>(CDecl); assert (IDecl && "CheckProtocolMethodDefs - IDecl is null"); ObjCInterfaceDecl *Super = IDecl->getSuperClass(); - ObjCInterfaceDecl *NSIDecl = 0; - if (getLangOpts().ObjCRuntime.isNeXTFamily()) { + ObjCInterfaceDecl *NSIDecl = nullptr; + + // 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) { + 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 = nullptr; + } + + 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 // from one object to another. @@ -1638,12 +1724,12 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, // implemented in the class, we should not issue "Method definition not // found" warnings. // FIXME: Use a general GetUnarySelector method for this. - IdentifierInfo* II = &Context.Idents.get("forwardInvocation"); - Selector fISelector = Context.Selectors.getSelector(1, &II); + IdentifierInfo* II = &S.Context.Idents.get("forwardInvocation"); + Selector fISelector = S.Context.Selectors.getSelector(1, &II); if (InsMap.count(fISelector)) // Is IDecl derived from 'NSProxy'? If so, no instance methods // need be implemented in the implementation. - NSIDecl = IDecl->lookupInheritedClass(&Context.Idents.get("NSProxy")); + NSIDecl = IDecl->lookupInheritedClass(&S.Context.Idents.get("NSProxy")); } // If this is a forward protocol declaration, get its definition. @@ -1658,13 +1744,15 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, // check unimplemented instance methods. if (!NSIDecl) - for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(), - E = PDecl->instmeth_end(); I != E; ++I) { - ObjCMethodDecl *method = *I; + for (auto *method : PDecl->instance_methods()) { if (method->getImplementationControl() != ObjCMethodDecl::Optional && !method->isPropertyAccessor() && !InsMap.count(method->getSelector()) && - (!Super || !Super->lookupInstanceMethod(method->getSelector()))) { + (!Super || !Super->lookupMethod(method->getSelector(), + true /* instance */, + false /* shallowCategory */, + true /* followsSuper */, + nullptr /* category */))) { // 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. @@ -1675,44 +1763,45 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, // have been synthesized due to a property declared in the class which // uses the protocol. if (ObjCMethodDecl *MethodInClass = - IDecl->lookupInstanceMethod(method->getSelector(), - true /*shallowCategoryLookup*/)) + IDecl->lookupMethod(method->getSelector(), + true /* instance */, + true /* shallowCategoryLookup */, + false /* followSuper */)) if (C || MethodInClass->isPropertyAccessor()) continue; unsigned DIAG = diag::warn_unimplemented_protocol_method; - if (Diags.getDiagnosticLevel(DIAG, ImpLoc) - != DiagnosticsEngine::Ignored) { - WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG); - Diag(CDecl->getLocation(), diag::note_required_for_protocol_at) - << PDecl->getDeclName(); + if (!S.Diags.isIgnored(DIAG, ImpLoc)) { + WarnUndefinedMethod(S, ImpLoc, method, IncompleteImpl, DIAG, + PDecl); } } } // check unimplemented class methods - for (ObjCProtocolDecl::classmeth_iterator - I = PDecl->classmeth_begin(), E = PDecl->classmeth_end(); - I != E; ++I) { - ObjCMethodDecl *method = *I; + for (auto *method : PDecl->class_methods()) { if (method->getImplementationControl() != ObjCMethodDecl::Optional && !ClsMap.count(method->getSelector()) && - (!Super || !Super->lookupClassMethod(method->getSelector()))) { + (!Super || !Super->lookupMethod(method->getSelector(), + false /* class method */, + false /* shallowCategoryLookup */, + true /* followSuper */, + nullptr /* category */))) { // See above comment for instance method lookups. - if (C && IDecl->lookupClassMethod(method->getSelector(), - true /*shallowCategoryLookup*/)) + if (C && IDecl->lookupMethod(method->getSelector(), + false /* class */, + true /* shallowCategoryLookup */, + false /* followSuper */)) continue; + unsigned DIAG = diag::warn_unimplemented_protocol_method; - if (Diags.getDiagnosticLevel(DIAG, ImpLoc) != - DiagnosticsEngine::Ignored) { - WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG); - Diag(IDecl->getLocation(), diag::note_required_for_protocol_at) << - PDecl->getDeclName(); + if (!S.Diags.isIgnored(DIAG, ImpLoc)) { + WarnUndefinedMethod(S, ImpLoc, method, IncompleteImpl, DIAG, PDecl); } } } // Check on this protocols's referenced protocols, recursively. - for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), - E = PDecl->protocol_end(); PI != E; ++PI) - CheckProtocolMethodDefs(ImpLoc, *PI, IncompleteImpl, InsMap, ClsMap, CDecl); + for (auto *PI : PDecl->protocols()) + CheckProtocolMethodDefs(S, ImpLoc, PI, IncompleteImpl, InsMap, ClsMap, + CDecl, ProtocolsExplictImpl); } /// MatchAllMethodDeclarations - Check methods declared in interface @@ -1729,56 +1818,50 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap, bool WarnCategoryMethodImpl) { // Check and see if instance methods in class interface have been // implemented in the implementation class. If so, their types match. - for (ObjCInterfaceDecl::instmeth_iterator I = CDecl->instmeth_begin(), - E = CDecl->instmeth_end(); I != E; ++I) { - if (!InsMapSeen.insert((*I)->getSelector())) + for (auto *I : CDecl->instance_methods()) { + if (!InsMapSeen.insert(I->getSelector())) continue; - if (!(*I)->isPropertyAccessor() && - !InsMap.count((*I)->getSelector())) { + if (!I->isPropertyAccessor() && + !InsMap.count(I->getSelector())) { if (ImmediateClass) - WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl, + WarnUndefinedMethod(*this, IMPDecl->getLocation(), I, IncompleteImpl, diag::warn_undef_method_impl); continue; } else { ObjCMethodDecl *ImpMethodDecl = - IMPDecl->getInstanceMethod((*I)->getSelector()); - assert(CDecl->getInstanceMethod((*I)->getSelector()) && + IMPDecl->getInstanceMethod(I->getSelector()); + assert(CDecl->getInstanceMethod(I->getSelector()) && "Expected to find the method through lookup as well"); - ObjCMethodDecl *MethodDecl = *I; // ImpMethodDecl may be null as in a @dynamic property. if (ImpMethodDecl) { if (!WarnCategoryMethodImpl) - WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl, + WarnConflictingTypedMethods(ImpMethodDecl, I, isa<ObjCProtocolDecl>(CDecl)); - else if (!MethodDecl->isPropertyAccessor()) - WarnExactTypedMethods(ImpMethodDecl, MethodDecl, - isa<ObjCProtocolDecl>(CDecl)); + else if (!I->isPropertyAccessor()) + WarnExactTypedMethods(ImpMethodDecl, I, isa<ObjCProtocolDecl>(CDecl)); } } } // Check and see if class methods in class interface have been // implemented in the implementation class. If so, their types match. - for (ObjCInterfaceDecl::classmeth_iterator I = CDecl->classmeth_begin(), - E = CDecl->classmeth_end(); - I != E; ++I) { - if (!ClsMapSeen.insert((*I)->getSelector())) + for (auto *I : CDecl->class_methods()) { + if (!ClsMapSeen.insert(I->getSelector())) continue; - if (!ClsMap.count((*I)->getSelector())) { + if (!ClsMap.count(I->getSelector())) { if (ImmediateClass) - WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl, + WarnUndefinedMethod(*this, IMPDecl->getLocation(), I, IncompleteImpl, diag::warn_undef_method_impl); } else { ObjCMethodDecl *ImpMethodDecl = - IMPDecl->getClassMethod((*I)->getSelector()); - assert(CDecl->getClassMethod((*I)->getSelector()) && + IMPDecl->getClassMethod(I->getSelector()); + assert(CDecl->getClassMethod(I->getSelector()) && "Expected to find the method through lookup as well"); - ObjCMethodDecl *MethodDecl = *I; if (!WarnCategoryMethodImpl) - WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl, + WarnConflictingTypedMethods(ImpMethodDecl, I, isa<ObjCProtocolDecl>(CDecl)); else - WarnExactTypedMethods(ImpMethodDecl, MethodDecl, + WarnExactTypedMethods(ImpMethodDecl, I, isa<ObjCProtocolDecl>(CDecl)); } } @@ -1786,10 +1869,9 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap, if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl> (CDecl)) { // Also, check for methods declared in protocols inherited by // this protocol. - for (ObjCProtocolDecl::protocol_iterator - PI = PD->protocol_begin(), E = PD->protocol_end(); PI != E; ++PI) + for (auto *PI : PD->protocols()) MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, - IMPDecl, (*PI), IncompleteImpl, false, + IMPDecl, PI, IncompleteImpl, false, WarnCategoryMethodImpl); } @@ -1798,35 +1880,24 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap, // i.e. when WarnCategoryMethodImpl is false, check declarations in class // extension; as well as those in categories. if (!WarnCategoryMethodImpl) { - for (ObjCInterfaceDecl::visible_categories_iterator - Cat = I->visible_categories_begin(), - CatEnd = I->visible_categories_end(); - Cat != CatEnd; ++Cat) { + for (auto *Cat : I->visible_categories()) MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, - IMPDecl, *Cat, IncompleteImpl, false, + IMPDecl, Cat, IncompleteImpl, false, WarnCategoryMethodImpl); - } } else { // Also methods in class extensions need be looked at next. - for (ObjCInterfaceDecl::visible_extensions_iterator - Ext = I->visible_extensions_begin(), - ExtEnd = I->visible_extensions_end(); - Ext != ExtEnd; ++Ext) { + for (auto *Ext : I->visible_extensions()) MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, - IMPDecl, *Ext, IncompleteImpl, false, + IMPDecl, Ext, IncompleteImpl, false, WarnCategoryMethodImpl); - } } // Check for any implementation of a methods declared in protocol. - for (ObjCInterfaceDecl::all_protocol_iterator - PI = I->all_referenced_protocol_begin(), - E = I->all_referenced_protocol_end(); PI != E; ++PI) + for (auto *PI : I->all_referenced_protocols()) MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, - IMPDecl, - (*PI), IncompleteImpl, false, + IMPDecl, PI, IncompleteImpl, false, WarnCategoryMethodImpl); - + // FIXME. For now, we are not checking for extact match of methods // in category implementation and its primary class's super class. if (!WarnCategoryMethodImpl && I->getSuperClass()) @@ -1841,20 +1912,6 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap, /// warns each time an exact match is found. void Sema::CheckCategoryVsClassMethodMatches( ObjCCategoryImplDecl *CatIMPDecl) { - SelectorSet InsMap, ClsMap; - - for (ObjCImplementationDecl::instmeth_iterator - I = CatIMPDecl->instmeth_begin(), - E = CatIMPDecl->instmeth_end(); I!=E; ++I) - InsMap.insert((*I)->getSelector()); - - for (ObjCImplementationDecl::classmeth_iterator - I = CatIMPDecl->classmeth_begin(), - E = CatIMPDecl->classmeth_end(); I != E; ++I) - ClsMap.insert((*I)->getSelector()); - if (InsMap.empty() && ClsMap.empty()) - return; - // Get category's primary class. ObjCCategoryDecl *CatDecl = CatIMPDecl->getCategoryDecl(); if (!CatDecl) @@ -1862,6 +1919,28 @@ void Sema::CheckCategoryVsClassMethodMatches( ObjCInterfaceDecl *IDecl = CatDecl->getClassInterface(); if (!IDecl) return; + ObjCInterfaceDecl *SuperIDecl = IDecl->getSuperClass(); + SelectorSet InsMap, ClsMap; + + for (const auto *I : CatIMPDecl->instance_methods()) { + Selector Sel = I->getSelector(); + // When checking for methods implemented in the category, skip over + // those declared in category class's super class. This is because + // the super class must implement the method. + if (SuperIDecl && SuperIDecl->lookupMethod(Sel, true)) + continue; + InsMap.insert(Sel); + } + + for (const auto *I : CatIMPDecl->class_methods()) { + Selector Sel = I->getSelector(); + if (SuperIDecl && SuperIDecl->lookupMethod(Sel, false)) + continue; + ClsMap.insert(Sel); + } + if (InsMap.empty() && ClsMap.empty()) + return; + SelectorSet InsMapSeen, ClsMapSeen; bool IncompleteImpl = false; MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, @@ -1876,24 +1955,22 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, SelectorSet InsMap; // Check and see if instance methods in class interface have been // implemented in the implementation class. - for (ObjCImplementationDecl::instmeth_iterator - I = IMPDecl->instmeth_begin(), E = IMPDecl->instmeth_end(); I!=E; ++I) - InsMap.insert((*I)->getSelector()); + for (const auto *I : IMPDecl->instance_methods()) + InsMap.insert(I->getSelector()); // Check and see if properties declared in the interface have either 1) // an implementation or 2) there is a @synthesize/@dynamic implementation // of the property in the @implementation. - if (const ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) - if (!(LangOpts.ObjCDefaultSynthProperties && - LangOpts.ObjCRuntime.isNonFragile()) || - IDecl->isObjCRequiresPropertyDefs()) - DiagnoseUnimplementedProperties(S, IMPDecl, CDecl); - + if (const ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) { + bool SynthesizeProperties = LangOpts.ObjCDefaultSynthProperties && + LangOpts.ObjCRuntime.isNonFragile() && + !IDecl->isObjCRequiresPropertyDefs(); + DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, SynthesizeProperties); + } + SelectorSet ClsMap; - for (ObjCImplementationDecl::classmeth_iterator - I = IMPDecl->classmeth_begin(), - E = IMPDecl->classmeth_end(); I != E; ++I) - ClsMap.insert((*I)->getSelector()); + for (const auto *I : IMPDecl->class_methods()) + ClsMap.insert(I->getSelector()); // Check for type conflict of methods declared in a class/protocol and // its implementation; if any. @@ -1913,28 +1990,25 @@ 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(IMPDecl->getLocation(), *PI, IncompleteImpl, - InsMap, ClsMap, I); + for (auto *PI : I->all_referenced_protocols()) + CheckProtocolMethodDefs(*this, IMPDecl->getLocation(), PI, IncompleteImpl, + InsMap, ClsMap, I, ExplicitImplProtocols); // Check class extensions (unnamed categories) - for (ObjCInterfaceDecl::visible_extensions_iterator - Ext = I->visible_extensions_begin(), - ExtEnd = I->visible_extensions_end(); - Ext != ExtEnd; ++Ext) { - ImplMethodsVsClassMethods(S, IMPDecl, *Ext, IncompleteImpl); - } + for (auto *Ext : I->visible_extensions()) + ImplMethodsVsClassMethods(S, IMPDecl, Ext, IncompleteImpl); } else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) { // For extended class, unimplemented methods in its protocols will // be reported in the primary class. if (!C->IsClassExtension()) { - for (ObjCCategoryDecl::protocol_iterator PI = C->protocol_begin(), - E = C->protocol_end(); PI != E; ++PI) - CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl, - InsMap, ClsMap, CDecl); - DiagnoseUnimplementedProperties(S, IMPDecl, CDecl); + for (auto *P : C->protocols()) + CheckProtocolMethodDefs(*this, IMPDecl->getLocation(), P, + IncompleteImpl, InsMap, ClsMap, CDecl, + ExplicitImplProtocols); + DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, + /* SynthesizeProperties */ false); } } else llvm_unreachable("invalid ObjCContainerDecl type."); @@ -2103,8 +2177,8 @@ static bool tryMatchRecordTypes(ASTContext &Context, bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left, const ObjCMethodDecl *right, MethodMatchStrategy strategy) { - if (!matchTypes(Context, strategy, - left->getResultType(), right->getResultType())) + if (!matchTypes(Context, strategy, left->getReturnType(), + right->getReturnType())) return false; // If either is hidden, it is not considered to match. @@ -2145,9 +2219,9 @@ void Sema::addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method) { List->setBits(List->getBits()+1); // If the list is empty, make it a singleton list. - if (List->Method == 0) { + if (List->Method == nullptr) { List->Method = Method; - List->setNext(0); + List->setNext(nullptr); return; } @@ -2187,7 +2261,7 @@ void Sema::addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method) { // 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>(); - Previous->setNext(new (Mem) ObjCMethodList(Method, 0)); + Previous->setNext(new (Mem) ObjCMethodList(Method, nullptr)); } /// \brief Read the contents of the method pool for a given selector from @@ -2233,7 +2307,7 @@ static bool isAcceptableMethodMismatch(ObjCMethodDecl *chosen, // Don't complain about mismatches for -length if the method we // chose has an integral result type. - return (chosen->getResultType()->isIntegerType()); + return (chosen->getReturnType()->isIntegerType()); } ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R, @@ -2244,7 +2318,7 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R, GlobalMethodPool::iterator Pos = MethodPool.find(Sel); if (Pos == MethodPool.end()) - return 0; + return nullptr; // Gather the non-hidden methods. ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second; @@ -2262,7 +2336,7 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R, // If there aren't any visible methods, we're done. // FIXME: Recover if there are any known-but-hidden methods? if (Methods.empty()) - return 0; + return nullptr; if (Methods.size() == 1) return Methods[0]; @@ -2273,10 +2347,8 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R, // We support a warning which complains about *any* difference in // method signature. bool strictSelectorMatch = - (receiverIdOrClass && warn && - (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl, - R.getBegin()) - != DiagnosticsEngine::Ignored)); + receiverIdOrClass && warn && + !Diags.isIgnored(diag::warn_strict_multiple_method_decl, R.getBegin()); if (strictSelectorMatch) { for (unsigned I = 1, N = Methods.size(); I != N; ++I) { if (!MatchTwoMethodDeclarations(Methods[0], Methods[I], MMS_strict)) { @@ -2324,15 +2396,19 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R, ObjCMethodDecl *Sema::LookupImplementedMethodInGlobalPool(Selector Sel) { GlobalMethodPool::iterator Pos = MethodPool.find(Sel); if (Pos == MethodPool.end()) - return 0; + return nullptr; GlobalMethods &Methods = Pos->second; - - if (Methods.first.Method && Methods.first.Method->isDefined()) - return Methods.first.Method; - if (Methods.second.Method && Methods.second.Method->isDefined()) - return Methods.second.Method; - return 0; + for (const ObjCMethodList *Method = &Methods.first; Method; + Method = Method->getNext()) + if (Method->Method && Method->Method->isDefined()) + return Method->Method; + + for (const ObjCMethodList *Method = &Methods.second; Method; + Method = Method->getNext()) + if (Method->Method && Method->Method->isDefined()) + return Method->Method; + return nullptr; } static void @@ -2364,7 +2440,8 @@ static bool HelperIsMethodInObjCType(Sema &S, Selector Sel, return true; if (S.LookupMethodInObjectType(Sel, ObjectType, true/*Instance method*/)) return true; - return S.LookupMethodInObjectType(Sel, ObjectType, false/*Class method*/) != 0; + return S.LookupMethodInObjectType(Sel, ObjectType, false/*Class method*/) != + nullptr; } const ObjCMethodDecl * @@ -2376,7 +2453,7 @@ Sema::SelectorsForTypoCorrection(Selector Sel, if (ObjectType.isNull()) ObjectIsId = ObjectIsClass = false; else if (!ObjectType->isObjCObjectPointerType()) - return 0; + return nullptr; else if (const ObjCObjectPointerType *ObjCPtr = ObjectType->getAsObjCInterfacePointerType()) { ObjectType = QualType(ObjCPtr->getInterfaceType(), 0); @@ -2387,8 +2464,8 @@ Sema::SelectorsForTypoCorrection(Selector Sel, else if (ObjectType->isObjCClassType() || ObjectType->isObjCQualifiedClassType()) ObjectIsId = false; else - return 0; - + return nullptr; + for (GlobalMethodPool::iterator b = MethodPool.begin(), e = MethodPool.end(); b != e; b++) { // instance methods @@ -2420,52 +2497,7 @@ Sema::SelectorsForTypoCorrection(Selector Sel, HelperSelectorsForTypoCorrection(SelectedMethods, Sel.getAsString(), Methods[i]); } - return (SelectedMethods.size() == 1) ? SelectedMethods[0] : NULL; -} - -static void -HelperToDiagnoseMismatchedMethodsInGlobalPool(Sema &S, - ObjCMethodList &MethList) { - ObjCMethodList *M = &MethList; - ObjCMethodDecl *TargetMethod = M->Method; - while (TargetMethod && - isa<ObjCImplDecl>(TargetMethod->getDeclContext())) { - M = M->getNext(); - TargetMethod = M ? M->Method : 0; - } - if (!TargetMethod) - return; - bool FirstTime = true; - for (M = M->getNext(); M; M=M->getNext()) { - ObjCMethodDecl *MatchingMethodDecl = M->Method; - if (isa<ObjCImplDecl>(MatchingMethodDecl->getDeclContext())) - continue; - if (!S.MatchTwoMethodDeclarations(TargetMethod, - MatchingMethodDecl, Sema::MMS_loose)) { - if (FirstTime) { - FirstTime = false; - S.Diag(TargetMethod->getLocation(), diag::warning_multiple_selectors) - << TargetMethod->getSelector(); - } - S.Diag(MatchingMethodDecl->getLocation(), diag::note_also_found); - } - } -} - -void Sema::DiagnoseMismatchedMethodsInGlobalPool() { - unsigned DIAG = diag::warning_multiple_selectors; - if (Diags.getDiagnosticLevel(DIAG, SourceLocation()) - == DiagnosticsEngine::Ignored) - return; - for (GlobalMethodPool::iterator b = MethodPool.begin(), - e = MethodPool.end(); b != e; b++) { - // first, instance methods - ObjCMethodList &InstMethList = b->second.first; - HelperToDiagnoseMismatchedMethodsInGlobalPool(*this, InstMethList); - // second, class methods - ObjCMethodList &ClsMethList = b->second.second; - HelperToDiagnoseMismatchedMethodsInGlobalPool(*this, ClsMethList); - } + return (SelectedMethods.size() == 1) ? SelectedMethods[0] : nullptr; } /// DiagnoseDuplicateIvars - @@ -2475,9 +2507,7 @@ void Sema::DiagnoseMismatchedMethodsInGlobalPool() { /// class's \@implementation is seen. void Sema::DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID, ObjCInterfaceDecl *SID) { - for (ObjCInterfaceDecl::ivar_iterator IVI = ID->ivar_begin(), - IVE = ID->ivar_end(); IVI != IVE; ++IVI) { - ObjCIvarDecl* Ivar = *IVI; + for (auto *Ivar : ID->ivars()) { if (Ivar->isInvalidDecl()) continue; if (IdentifierInfo *II = Ivar->getIdentifier()) { @@ -2516,7 +2546,7 @@ Sema::ObjCContainerKind Sema::getObjCContainerKind() const { Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods, ArrayRef<DeclGroupPtrTy> allTUVars) { if (getObjCContainerKind() == Sema::OCK_None) - return 0; + return nullptr; assert(AtEnd.isValid() && "Invalid location for '@end'"); @@ -2603,10 +2633,8 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods, // ProcessPropertyDecl is responsible for diagnosing conflicts with any // user-defined setter/getter. It also synthesizes setter/getter methods // and adds them to the DeclContext and global method pools. - for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(), - E = CDecl->prop_end(); - I != E; ++I) - ProcessPropertyDecl(*I, CDecl); + for (auto *I : CDecl->properties()) + ProcessPropertyDecl(I, CDecl); CDecl->setAtEndRange(AtEnd); } if (ObjCImplementationDecl *IC=dyn_cast<ObjCImplementationDecl>(ClassDecl)) { @@ -2617,13 +2645,8 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods, // of the other class extensions. Mark them as synthesized as // property will be synthesized when property with same name is // seen in the @implementation. - for (ObjCInterfaceDecl::visible_extensions_iterator - Ext = IDecl->visible_extensions_begin(), - ExtEnd = IDecl->visible_extensions_end(); - Ext != ExtEnd; ++Ext) { - for (ObjCContainerDecl::prop_iterator I = Ext->prop_begin(), - E = Ext->prop_end(); I != E; ++I) { - ObjCPropertyDecl *Property = *I; + for (const auto *Ext : IDecl->visible_extensions()) { + for (const auto *Property : Ext->properties()) { // Skip over properties declared @dynamic if (const ObjCPropertyImplDecl *PIDecl = IC->FindPropertyImplDecl(Property->getIdentifier())) @@ -2631,10 +2654,7 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods, == ObjCPropertyImplDecl::Dynamic) continue; - for (ObjCInterfaceDecl::visible_extensions_iterator - Ext = IDecl->visible_extensions_begin(), - ExtEnd = IDecl->visible_extensions_end(); - Ext != ExtEnd; ++Ext) { + for (const auto *Ext : IDecl->visible_extensions()) { if (ObjCMethodDecl *GetterMethod = Ext->getInstanceMethod(Property->getGetterName())) GetterMethod->setPropertyAccessor(true); @@ -2648,14 +2668,17 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods, ImplMethodsVsClassMethods(S, IC, IDecl); AtomicPropertySetterGetterRules(IC, IDecl); DiagnoseOwningPropertyGetterSynthesis(IC); - + DiagnoseUnusedBackingIvarInAccessor(S, IC); + if (IDecl->hasDesignatedInitializers()) + DiagnoseMissingDesignatedInitOverrides(IC, IDecl); + bool HasRootClassAttr = IDecl->hasAttr<ObjCRootClassAttr>(); - if (IDecl->getSuperClass() == NULL) { + if (IDecl->getSuperClass() == nullptr) { // This class has no superclass, so check that it has been marked with // __attribute((objc_root_class)). if (!HasRootClassAttr) { SourceLocation DeclLoc(IDecl->getLocation()); - SourceLocation SuperClassLoc(PP.getLocForEndOfToken(DeclLoc)); + SourceLocation SuperClassLoc(getLocForEndOfToken(DeclLoc)); Diag(DeclLoc, diag::warn_objc_root_class_missing) << IDecl->getIdentifier(); // See if NSObject is in the current scope, and if it is, suggest @@ -2729,72 +2752,14 @@ CvtQTToAstBitMask(ObjCDeclSpec::ObjCDeclQualifier PQTVal) { return (Decl::ObjCDeclQualifier) (unsigned) PQTVal; } -static inline -unsigned countAlignAttr(const AttrVec &A) { - unsigned count=0; - for (AttrVec::const_iterator i = A.begin(), e = A.end(); i != e; ++i) - if ((*i)->getKind() == attr::Aligned) - ++count; - return count; -} - -static inline -bool containsInvalidMethodImplAttribute(ObjCMethodDecl *IMD, - const AttrVec &A) { - // If method is only declared in implementation (private method), - // No need to issue any diagnostics on method definition with attributes. - if (!IMD) - return false; - - // method declared in interface has no attribute. - // But implementation has attributes. This is invalid. - // Except when implementation has 'Align' attribute which is - // immaterial to method declared in interface. - if (!IMD->hasAttrs()) - return (A.size() > countAlignAttr(A)); - - const AttrVec &D = IMD->getAttrs(); - - unsigned countAlignOnImpl = countAlignAttr(A); - if (!countAlignOnImpl && (A.size() != D.size())) - return true; - else if (countAlignOnImpl) { - unsigned countAlignOnDecl = countAlignAttr(D); - if (countAlignOnDecl && (A.size() != D.size())) - return true; - else if (!countAlignOnDecl && - ((A.size()-countAlignOnImpl) != D.size())) - return true; - } - - // attributes on method declaration and definition must match exactly. - // Note that we have at most a couple of attributes on methods, so this - // n*n search is good enough. - for (AttrVec::const_iterator i = A.begin(), e = A.end(); i != e; ++i) { - if ((*i)->getKind() == attr::Aligned) - continue; - bool match = false; - for (AttrVec::const_iterator i1 = D.begin(), e1 = D.end(); i1 != e1; ++i1) { - if ((*i)->getKind() == (*i1)->getKind()) { - match = true; - break; - } - } - if (!match) - return true; - } - - return false; -} - /// \brief Check whether the declared result type of the given Objective-C /// method declaration is compatible with the method's class. /// static Sema::ResultTypeCompatibilityKind CheckRelatedResultTypeCompatibility(Sema &S, ObjCMethodDecl *Method, ObjCInterfaceDecl *CurrentClass) { - QualType ResultType = Method->getResultType(); - + QualType ResultType = Method->getReturnType(); + // If an Objective-C method inherits its related result type, then its // declared result type must be compatible with its own class type. The // declared result type is compatible if: @@ -2928,12 +2893,8 @@ private: return; // - categories, - for (ObjCInterfaceDecl::known_categories_iterator - cat = iface->known_categories_begin(), - catEnd = iface->known_categories_end(); - cat != catEnd; ++cat) { - search(*cat); - } + for (auto *Cat : iface->known_categories()) + search(Cat); // - the super class, and if (ObjCInterfaceDecl *super = iface->getSuperClass()) @@ -3095,19 +3056,19 @@ Decl *Sema::ActOnMethodDeclaration( // Make sure we can establish a context for the method. if (!CurContext->isObjCContainer()) { Diag(MethodLoc, diag::error_missing_method_context); - return 0; + return nullptr; } ObjCContainerDecl *OCD = dyn_cast<ObjCContainerDecl>(CurContext); Decl *ClassDecl = cast<Decl>(OCD); QualType resultDeclType; bool HasRelatedResultType = false; - TypeSourceInfo *ResultTInfo = 0; + TypeSourceInfo *ReturnTInfo = nullptr; if (ReturnType) { - resultDeclType = GetTypeFromParser(ReturnType, &ResultTInfo); + resultDeclType = GetTypeFromParser(ReturnType, &ReturnTInfo); if (CheckFunctionReturnType(resultDeclType, MethodLoc)) - return 0; + return nullptr; HasRelatedResultType = (resultDeclType == Context.getObjCInstanceType()); } else { // get the type for "id". @@ -3116,18 +3077,14 @@ Decl *Sema::ActOnMethodDeclaration( << FixItHint::CreateInsertion(SelectorLocs.front(), "(id)"); } - ObjCMethodDecl* ObjCMethod = - ObjCMethodDecl::Create(Context, MethodLoc, EndLoc, Sel, - resultDeclType, - ResultTInfo, - CurContext, - MethodType == tok::minus, isVariadic, - /*isPropertyAccessor=*/false, - /*isImplicitlyDeclared=*/false, /*isDefined=*/false, - MethodDeclKind == tok::objc_optional - ? ObjCMethodDecl::Optional - : ObjCMethodDecl::Required, - HasRelatedResultType); + ObjCMethodDecl *ObjCMethod = ObjCMethodDecl::Create( + Context, MethodLoc, EndLoc, Sel, resultDeclType, ReturnTInfo, CurContext, + MethodType == tok::minus, isVariadic, + /*isPropertyAccessor=*/false, + /*isImplicitlyDeclared=*/false, /*isDefined=*/false, + MethodDeclKind == tok::objc_optional ? ObjCMethodDecl::Optional + : ObjCMethodDecl::Required, + HasRelatedResultType); SmallVector<ParmVarDecl*, 16> Params; @@ -3137,7 +3094,7 @@ Decl *Sema::ActOnMethodDeclaration( if (!ArgInfo[i].Type) { ArgType = Context.getObjCIdType(); - DI = 0; + DI = nullptr; } else { ArgType = GetTypeFromParser(ArgInfo[i].Type, &DI); } @@ -3204,7 +3161,7 @@ Decl *Sema::ActOnMethodDeclaration( ProcessDeclAttributeList(TUScope, ObjCMethod, AttrList); // Add the method now. - const ObjCMethodDecl *PrevMethod = 0; + const ObjCMethodDecl *PrevMethod = nullptr; if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(ClassDecl)) { if (MethodType == tok::minus) { PrevMethod = ImpDecl->getInstanceMethod(Sel); @@ -3214,24 +3171,22 @@ Decl *Sema::ActOnMethodDeclaration( ImpDecl->addClassMethod(ObjCMethod); } - ObjCMethodDecl *IMD = 0; + ObjCMethodDecl *IMD = nullptr; if (ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface()) IMD = IDecl->lookupMethod(ObjCMethod->getSelector(), ObjCMethod->isInstanceMethod()); if (IMD && IMD->hasAttr<ObjCRequiresSuperAttr>() && !ObjCMethod->hasAttr<ObjCRequiresSuperAttr>()) { // merge the attribute into implementation. - ObjCMethod->addAttr( - new (Context) ObjCRequiresSuperAttr(ObjCMethod->getLocation(), Context)); - } - if (ObjCMethod->hasAttrs() && - containsInvalidMethodImplAttribute(IMD, ObjCMethod->getAttrs())) { - SourceLocation MethodLoc = IMD->getLocation(); - if (!getSourceManager().isInSystemHeader(MethodLoc)) { - Diag(EndLoc, diag::warn_attribute_method_def); - Diag(MethodLoc, diag::note_method_declared_at) + ObjCMethod->addAttr(ObjCRequiresSuperAttr::CreateImplicit(Context, + ObjCMethod->getLocation())); + } + if (isa<ObjCCategoryImplDecl>(ImpDecl)) { + ObjCMethodFamily family = + ObjCMethod->getSelector().getMethodFamily(); + if (family == OMF_dealloc && IMD && IMD->isOverriding()) + Diag(ObjCMethod->getLocation(), diag::warn_dealloc_in_category) << ObjCMethod->getDeclName(); - } } } else { cast<DeclContext>(ClassDecl)->addDecl(ObjCMethod); @@ -3482,8 +3437,6 @@ void Sema::DiagnoseUseOfUnimplementedSelectors() { ReferencedSelectors[Sels[I].first] = Sels[I].second; } - DiagnoseMismatchedMethodsInGlobalPool(); - // Warning will be issued only when selector table is // generated (which means there is at lease one implementation // in the TU). This is to match gcc's behavior. @@ -3503,39 +3456,93 @@ void Sema::DiagnoseUseOfUnimplementedSelectors() { ObjCIvarDecl * Sema::GetIvarBackingPropertyAccessor(const ObjCMethodDecl *Method, const ObjCPropertyDecl *&PDecl) const { - + if (Method->isClassMethod()) + return nullptr; const ObjCInterfaceDecl *IDecl = Method->getClassInterface(); if (!IDecl) - return 0; - Method = IDecl->lookupMethod(Method->getSelector(), true); + return nullptr; + Method = IDecl->lookupMethod(Method->getSelector(), /*isInstance=*/true, + /*shallowCategoryLookup=*/false, + /*followSuper=*/false); if (!Method || !Method->isPropertyAccessor()) - return 0; - if ((PDecl = Method->findPropertyDecl())) { - if (!PDecl->getDeclContext()) - return 0; - // Make sure property belongs to accessor's class and not to - // one of its super classes. - if (const ObjCInterfaceDecl *CID = - dyn_cast<ObjCInterfaceDecl>(PDecl->getDeclContext())) - if (CID != IDecl) - return 0; - return PDecl->getPropertyIvarDecl(); - } - return 0; -} - -void Sema::DiagnoseUnusedBackingIvarInAccessor(Scope *S) { - if (S->hasUnrecoverableErrorOccurred() || !S->isInObjcMethodScope()) - return; - - const ObjCMethodDecl *CurMethod = getCurMethodDecl(); - if (!CurMethod) + return nullptr; + if ((PDecl = Method->findPropertyDecl())) + if (ObjCIvarDecl *IV = PDecl->getPropertyIvarDecl()) { + // property backing ivar must belong to property's class + // or be a private ivar in class's implementation. + // FIXME. fix the const-ness issue. + IV = const_cast<ObjCInterfaceDecl *>(IDecl)->lookupInstanceVariable( + IV->getIdentifier()); + return IV; + } + return nullptr; +} + +namespace { + /// Used by Sema::DiagnoseUnusedBackingIvarInAccessor to check if a property + /// accessor references the backing ivar. + class UnusedBackingIvarChecker : + public DataRecursiveASTVisitor<UnusedBackingIvarChecker> { + public: + Sema &S; + const ObjCMethodDecl *Method; + const ObjCIvarDecl *IvarD; + bool AccessedIvar; + bool InvokedSelfMethod; + + UnusedBackingIvarChecker(Sema &S, const ObjCMethodDecl *Method, + const ObjCIvarDecl *IvarD) + : S(S), Method(Method), IvarD(IvarD), + AccessedIvar(false), InvokedSelfMethod(false) { + assert(IvarD); + } + + bool VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { + if (E->getDecl() == IvarD) { + AccessedIvar = true; + return false; + } + return true; + } + + bool VisitObjCMessageExpr(ObjCMessageExpr *E) { + if (E->getReceiverKind() == ObjCMessageExpr::Instance && + S.isSelfExpr(E->getInstanceReceiver(), Method)) { + InvokedSelfMethod = true; + } + return true; + } + }; +} + +void Sema::DiagnoseUnusedBackingIvarInAccessor(Scope *S, + const ObjCImplementationDecl *ImplD) { + if (S->hasUnrecoverableErrorOccurred()) return; - const ObjCPropertyDecl *PDecl; - const ObjCIvarDecl *IV = GetIvarBackingPropertyAccessor(CurMethod, PDecl); - if (IV && !IV->getBackingIvarReferencedInAccessor()) { - Diag(getCurMethodDecl()->getLocation(), diag::warn_unused_property_backing_ivar) - << IV->getDeclName(); - Diag(PDecl->getLocation(), diag::note_property_declare); + + for (const auto *CurMethod : ImplD->instance_methods()) { + unsigned DIAG = diag::warn_unused_property_backing_ivar; + SourceLocation Loc = CurMethod->getLocation(); + if (Diags.isIgnored(DIAG, Loc)) + continue; + + const ObjCPropertyDecl *PDecl; + const ObjCIvarDecl *IV = GetIvarBackingPropertyAccessor(CurMethod, PDecl); + if (!IV) + continue; + + UnusedBackingIvarChecker Checker(*this, CurMethod, IV); + Checker.TraverseStmt(CurMethod->getBody()); + if (Checker.AccessedIvar) + continue; + + // Do not issue this warning if backing ivar is used somewhere and accessor + // implementation makes a self call. This is to prevent false positive in + // cases where the ivar is accessed by another method that the accessor + // delegates to. + if (!IV->isReferenced() || !Checker.InvokedSelfMethod) { + Diag(Loc, DIAG) << IV; + Diag(PDecl->getLocation(), diag::note_property_declare); + } } } |