aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaDeclObjC.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaDeclObjC.cpp')
-rw-r--r--lib/Sema/SemaDeclObjC.cpp167
1 files changed, 107 insertions, 60 deletions
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 66fdc67e41..f33e7bcb16 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -151,7 +151,8 @@ void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
if (ObjCMethodFamily Family = Overridden->getMethodFamily())
Diag(Overridden->getLocation(),
- diag::note_related_result_type_overridden_family)
+ diag::note_related_result_type_family)
+ << /*overridden method*/ 0
<< Family;
else
Diag(Overridden->getLocation(),
@@ -192,7 +193,7 @@ void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
/// \brief Check a method declaration for compatibility with the Objective-C
/// ARC conventions.
-static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) {
+bool Sema::CheckARCMethodDecl(ObjCMethodDecl *method) {
ObjCMethodFamily family = method->getMethodFamily();
switch (family) {
case OMF_None:
@@ -206,17 +207,17 @@ static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) {
return false;
case OMF_dealloc:
- if (!S.Context.hasSameType(method->getResultType(), S.Context.VoidTy)) {
+ if (!Context.hasSameType(method->getResultType(), Context.VoidTy)) {
SourceRange ResultTypeRange;
if (const TypeSourceInfo *ResultTypeInfo
= method->getResultTypeSourceInfo())
ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange();
if (ResultTypeRange.isInvalid())
- S.Diag(method->getLocation(), diag::error_dealloc_bad_result_type)
+ Diag(method->getLocation(), diag::error_dealloc_bad_result_type)
<< method->getResultType()
<< FixItHint::CreateInsertion(method->getSelectorLoc(0), "(void)");
else
- S.Diag(method->getLocation(), diag::error_dealloc_bad_result_type)
+ Diag(method->getLocation(), diag::error_dealloc_bad_result_type)
<< method->getResultType()
<< FixItHint::CreateReplacement(ResultTypeRange, "void");
return true;
@@ -225,11 +226,11 @@ static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) {
case OMF_init:
// If the method doesn't obey the init rules, don't bother annotating it.
- if (S.checkInitMethod(method, QualType()))
+ if (checkInitMethod(method, QualType()))
return true;
- method->addAttr(new (S.Context) NSConsumesSelfAttr(SourceLocation(),
- S.Context));
+ method->addAttr(new (Context) NSConsumesSelfAttr(SourceLocation(),
+ Context));
// Don't add a second copy of this attribute, but otherwise don't
// let it be suppressed.
@@ -248,8 +249,8 @@ static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) {
break;
}
- method->addAttr(new (S.Context) NSReturnsRetainedAttr(SourceLocation(),
- S.Context));
+ method->addAttr(new (Context) NSReturnsRetainedAttr(SourceLocation(),
+ Context));
return false;
}
@@ -520,8 +521,14 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) {
QualType T = TDecl->getUnderlyingType();
if (T->isObjCObjectType()) {
- if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface())
+ if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) {
SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl);
+ // This handles the following case:
+ // @interface NewI @end
+ // typedef NewI DeprI __attribute__((deprecated("blah")))
+ // @interface SI : DeprI /* warn here */ @end
+ (void)DiagnoseUseOfDecl(const_cast<TypedefNameDecl*>(TDecl), SuperLoc);
+ }
}
}
@@ -738,7 +745,10 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
<< ProtocolId[i].first;
continue;
}
-
+ // If this is a forward protocol declaration, get its definition.
+ if (!PDecl->isThisDeclarationADefinition() && PDecl->getDefinition())
+ PDecl = PDecl->getDefinition();
+
(void)DiagnoseUseOfDecl(PDecl, ProtocolId[i].second);
// If this is a forward declaration and we are supposed to warn in this
@@ -1035,7 +1045,7 @@ Decl *Sema::ActOnStartClassImplementation(
ObjCImplementationDecl* IMPDecl =
ObjCImplementationDecl::Create(Context, CurContext, IDecl, SDecl,
- ClassLoc, AtClassImplLoc);
+ ClassLoc, AtClassImplLoc, SuperClassLoc);
if (CheckObjCDeclScope(IMPDecl))
return ActOnObjCContainerStartDefinition(IMPDecl);
@@ -1176,14 +1186,18 @@ void Sema::WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method,
return;
}
- if (!IncompleteImpl) {
- Diag(ImpLoc, diag::warn_incomplete_impl);
- IncompleteImpl = true;
- }
- if (DiagID == diag::warn_unimplemented_protocol_method)
- Diag(ImpLoc, DiagID) << method->getDeclName();
- else
- Diag(method->getLocation(), DiagID) << method->getDeclName();
+ // FIXME: For now ignore 'IncompleteImpl'.
+ // Previously we grouped all unimplemented methods under a single
+ // 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();
+
+ // Issue a note to the original declaration.
+ SourceLocation MethodLoc = method->getLocStart();
+ if (MethodLoc.isValid())
+ Diag(MethodLoc, diag::note_method_declared_at) << method;
}
/// Determines if type B can be substituted for type A. Returns true if we can
@@ -1627,8 +1641,6 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
if (Diags.getDiagnosticLevel(DIAG, ImpLoc)
!= DiagnosticsEngine::Ignored) {
WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG);
- Diag(method->getLocation(), diag::note_method_declared_at)
- << method->getDeclName();
Diag(CDecl->getLocation(), diag::note_required_for_protocol_at)
<< PDecl->getDeclName();
}
@@ -1650,8 +1662,6 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
if (Diags.getDiagnosticLevel(DIAG, ImpLoc) !=
DiagnosticsEngine::Ignored) {
WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG);
- Diag(method->getLocation(), diag::note_method_declared_at)
- << method->getDeclName();
Diag(IDecl->getLocation(), diag::note_required_for_protocol_at) <<
PDecl->getDeclName();
}
@@ -1686,7 +1696,7 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
!InsMap.count((*I)->getSelector())) {
if (ImmediateClass)
WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl,
- diag::note_undef_method_impl);
+ diag::warn_undef_method_impl);
continue;
} else {
ObjCMethodDecl *ImpMethodDecl =
@@ -1716,7 +1726,7 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
if (!ClsMap.count((*I)->getSelector())) {
if (ImmediateClass)
WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl,
- diag::note_undef_method_impl);
+ diag::warn_undef_method_impl);
} else {
ObjCMethodDecl *ImpMethodDecl =
IMPDecl->getClassMethod((*I)->getSelector());
@@ -1826,7 +1836,7 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
if (!(LangOpts.ObjCDefaultSynthProperties &&
LangOpts.ObjCRuntime.isNonFragile()) ||
IDecl->isObjCRequiresPropertyDefs())
- DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap);
+ DiagnoseUnimplementedProperties(S, IMPDecl, CDecl);
SelectorSet ClsMap;
for (ObjCImplementationDecl::classmeth_iterator
@@ -1873,17 +1883,7 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
E = C->protocol_end(); PI != E; ++PI)
CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl,
InsMap, ClsMap, CDecl);
- // Report unimplemented properties in the category as well.
- // When reporting on missing setter/getters, do not report when
- // setter/getter is implemented in category's primary class
- // implementation.
- if (ObjCInterfaceDecl *ID = C->getClassInterface())
- if (ObjCImplDecl *IMP = ID->getImplementation()) {
- for (ObjCImplementationDecl::instmeth_iterator
- I = IMP->instmeth_begin(), E = IMP->instmeth_end(); I!=E; ++I)
- InsMap.insert((*I)->getSelector());
- }
- DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap);
+ DiagnoseUnimplementedProperties(S, IMPDecl, CDecl);
}
} else
llvm_unreachable("invalid ObjCContainerDecl type.");
@@ -2075,17 +2075,24 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left,
}
void Sema::addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method) {
+ // Record at the head of the list whether there were 0, 1, or >= 2 methods
+ // inside categories.
+ if (ObjCCategoryDecl *
+ CD = dyn_cast<ObjCCategoryDecl>(Method->getDeclContext()))
+ if (!CD->IsClassExtension() && List->getBits() < 2)
+ List->setBits(List->getBits()+1);
+
// If the list is empty, make it a singleton list.
if (List->Method == 0) {
List->Method = Method;
- List->Next = 0;
+ List->setNext(0);
return;
}
// We've seen a method with this name, see if we have already seen this type
// signature.
ObjCMethodList *Previous = List;
- for (; List; Previous = List, List = List->Next) {
+ for (; List; Previous = List, List = List->getNext()) {
if (!MatchTwoMethodDeclarations(Method, List->Method))
continue;
@@ -2114,7 +2121,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->Next = new (Mem) ObjCMethodList(Method, 0);
+ Previous->setNext(new (Mem) ObjCMethodList(Method, 0));
}
/// \brief Read the contents of the method pool for a given selector from
@@ -2176,7 +2183,7 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
// Gather the non-hidden methods.
ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;
llvm::SmallVector<ObjCMethodDecl *, 4> Methods;
- for (ObjCMethodList *M = &MethList; M; M = M->Next) {
+ for (ObjCMethodList *M = &MethList; M; M = M->getNext()) {
if (M->Method && !M->Method->isHidden()) {
// If we're not supposed to warn about mismatches, we're done.
if (!warn)
@@ -2726,9 +2733,9 @@ private:
return;
// - categories,
- for (ObjCInterfaceDecl::visible_categories_iterator
- cat = iface->visible_categories_begin(),
- catEnd = iface->visible_categories_end();
+ for (ObjCInterfaceDecl::known_categories_iterator
+ cat = iface->known_categories_begin(),
+ catEnd = iface->known_categories_end();
cat != catEnd; ++cat) {
search(*cat);
}
@@ -2758,7 +2765,8 @@ private:
void search(ObjCContainerDecl *container) {
// Check for a method in this container which matches this selector.
ObjCMethodDecl *meth = container->getMethod(Method->getSelector(),
- Method->isInstanceMethod());
+ Method->isInstanceMethod(),
+ /*AllowHidden=*/true);
// If we find one, record it and bail out.
if (meth) {
@@ -2792,10 +2800,47 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,
i = overrides.begin(), e = overrides.end(); i != e; ++i) {
ObjCMethodDecl *overridden = *i;
- if (isa<ObjCProtocolDecl>(overridden->getDeclContext()) ||
- CurrentClass != overridden->getClassInterface() ||
- overridden->isOverriding())
- hasOverriddenMethodsInBaseOrProtocol = true;
+ if (!hasOverriddenMethodsInBaseOrProtocol) {
+ if (isa<ObjCProtocolDecl>(overridden->getDeclContext()) ||
+ CurrentClass != overridden->getClassInterface() ||
+ overridden->isOverriding()) {
+ hasOverriddenMethodsInBaseOrProtocol = true;
+
+ } else if (isa<ObjCImplDecl>(ObjCMethod->getDeclContext())) {
+ // OverrideSearch will return as "overridden" the same method in the
+ // interface. For hasOverriddenMethodsInBaseOrProtocol, we need to
+ // check whether a category of a base class introduced a method with the
+ // same selector, after the interface method declaration.
+ // To avoid unnecessary lookups in the majority of cases, we use the
+ // extra info bits in GlobalMethodPool to check whether there were any
+ // category methods with this selector.
+ GlobalMethodPool::iterator It =
+ MethodPool.find(ObjCMethod->getSelector());
+ if (It != MethodPool.end()) {
+ ObjCMethodList &List =
+ ObjCMethod->isInstanceMethod()? It->second.first: It->second.second;
+ unsigned CategCount = List.getBits();
+ if (CategCount > 0) {
+ // If the method is in a category we'll do lookup if there were at
+ // least 2 category methods recorded, otherwise only one will do.
+ if (CategCount > 1 ||
+ !isa<ObjCCategoryImplDecl>(overridden->getDeclContext())) {
+ OverrideSearch overrides(*this, overridden);
+ for (OverrideSearch::iterator
+ OI= overrides.begin(), OE= overrides.end(); OI!=OE; ++OI) {
+ ObjCMethodDecl *SuperOverridden = *OI;
+ if (isa<ObjCProtocolDecl>(SuperOverridden->getDeclContext()) ||
+ CurrentClass != SuperOverridden->getClassInterface()) {
+ hasOverriddenMethodsInBaseOrProtocol = true;
+ overridden->setOverriding(true);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
// Propagate down the 'related result type' bit from overridden methods.
if (RTC != Sema::RTC_Incompatible && overridden->hasRelatedResultType())
@@ -2928,7 +2973,7 @@ Decl *Sema::ActOnMethodDeclaration(
ParmVarDecl* Param = CheckParameter(ObjCMethod, StartLoc,
ArgInfo[i].NameLoc, ArgInfo[i].Name,
- ArgType, DI, SC_None, SC_None);
+ ArgType, DI, SC_None);
Param->setObjCMethodScopeInfo(i);
@@ -3030,7 +3075,7 @@ Decl *Sema::ActOnMethodDeclaration(
bool ARCError = false;
if (getLangOpts().ObjCAutoRefCount)
- ARCError = CheckARCMethodDecl(*this, ObjCMethod);
+ ARCError = CheckARCMethodDecl(ObjCMethod);
// Infer the related result type when possible.
if (!ARCError && RTC == Sema::RTC_Compatible &&
@@ -3159,7 +3204,7 @@ VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType T,
}
VarDecl *New = VarDecl::Create(Context, CurContext, StartLoc, IdLoc, Id,
- T, TInfo, SC_None, SC_None);
+ T, TInfo, SC_None);
New->setExceptionVariable(true);
// In ARC, infer 'retaining' for variables of retainable type.
@@ -3179,15 +3224,17 @@ Decl *Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) {
if (DS.getStorageClassSpec() == DeclSpec::SCS_register) {
Diag(DS.getStorageClassSpecLoc(), diag::warn_register_objc_catch_parm)
<< FixItHint::CreateRemoval(SourceRange(DS.getStorageClassSpecLoc()));
- } else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) {
+ } else if (DeclSpec::SCS SCS = DS.getStorageClassSpec()) {
Diag(DS.getStorageClassSpecLoc(), diag::err_storage_spec_on_catch_parm)
- << DS.getStorageClassSpec();
- }
- if (D.getDeclSpec().isThreadSpecified())
- Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
+ << DeclSpec::getSpecifierName(SCS);
+ }
+ if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec())
+ Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
+ diag::err_invalid_thread)
+ << DeclSpec::getSpecifierName(TSCS);
D.getMutableDeclSpec().ClearStorageClassSpecs();
- DiagnoseFunctionSpecifiers(D);
+ DiagnoseFunctionSpecifiers(D.getDeclSpec());
// Check that there are no default arguments inside the type of this
// exception object (C++ only).