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