aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaDeclObjC.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2014-11-24 09:15:30 +0000
committerDimitry Andric <dim@FreeBSD.org>2014-11-24 09:15:30 +0000
commit9f4dbff6669c8037f3b036bcf580d14f1a4f12a5 (patch)
tree47df2c12b57214af6c31e47404b005675b8b7ffc /lib/Sema/SemaDeclObjC.cpp
parentf73d5f23a889b93d89ddef61ac0995df40286bb8 (diff)
downloadsrc-9f4dbff6669c8037f3b036bcf580d14f1a4f12a5.tar.gz
src-9f4dbff6669c8037f3b036bcf580d14f1a4f12a5.zip
Vendor import of clang RELEASE_350/final tag r216957 (effectively, 3.5.0 release):vendor/clang/clang-release_350-r216957
Notes
Notes: svn path=/vendor/clang/dist/; revision=274958 svn path=/vendor/clang/clang-release_350-r216957/; revision=274959; tag=vendor/clang/clang-release_350-r216957
Diffstat (limited to 'lib/Sema/SemaDeclObjC.cpp')
-rw-r--r--lib/Sema/SemaDeclObjC.cpp883
1 files changed, 445 insertions, 438 deletions
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index f44fb3251141..b5205b3e6238 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/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);
+ }
}
}