summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp')
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp287
1 files changed, 274 insertions, 13 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp
index 7b235ba..de9097e 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp
@@ -24,6 +24,141 @@
using namespace clang;
+bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
+ const ObjCMethodDecl *Overridden,
+ bool IsImplementation) {
+ if (Overridden->hasRelatedResultType() &&
+ !NewMethod->hasRelatedResultType()) {
+ // This can only happen when the method follows a naming convention that
+ // 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();
+ SourceRange ResultTypeRange;
+ if (const TypeSourceInfo *ResultTypeInfo
+ = NewMethod->getResultTypeSourceInfo())
+ ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange();
+
+ // Figure out which class this method is part of, if any.
+ ObjCInterfaceDecl *CurrentClass
+ = dyn_cast<ObjCInterfaceDecl>(NewMethod->getDeclContext());
+ if (!CurrentClass) {
+ DeclContext *DC = NewMethod->getDeclContext();
+ if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(DC))
+ CurrentClass = Cat->getClassInterface();
+ else if (ObjCImplDecl *Impl = dyn_cast<ObjCImplDecl>(DC))
+ CurrentClass = Impl->getClassInterface();
+ else if (ObjCCategoryImplDecl *CatImpl
+ = dyn_cast<ObjCCategoryImplDecl>(DC))
+ CurrentClass = CatImpl->getClassInterface();
+ }
+
+ if (CurrentClass) {
+ Diag(NewMethod->getLocation(),
+ diag::warn_related_result_type_compatibility_class)
+ << Context.getObjCInterfaceType(CurrentClass)
+ << ResultType
+ << ResultTypeRange;
+ } else {
+ Diag(NewMethod->getLocation(),
+ diag::warn_related_result_type_compatibility_protocol)
+ << ResultType
+ << ResultTypeRange;
+ }
+
+ Diag(Overridden->getLocation(), diag::note_related_result_type_overridden)
+ << Overridden->getMethodFamily();
+ }
+
+ return false;
+}
+
+
+static bool CheckObjCMethodOverrides(Sema &S, ObjCMethodDecl *NewMethod,
+ DeclContext *DC,
+ bool SkipCurrent = true) {
+ if (!DC)
+ return false;
+
+ if (!SkipCurrent) {
+ // Look for this method. If we find it, we're done.
+ Selector Sel = NewMethod->getSelector();
+ bool IsInstance = NewMethod->isInstanceMethod();
+ DeclContext::lookup_const_iterator Meth, MethEnd;
+ for (llvm::tie(Meth, MethEnd) = DC->lookup(Sel); Meth != MethEnd; ++Meth) {
+ ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth);
+ if (MD && MD->isInstanceMethod() == IsInstance)
+ return S.CheckObjCMethodOverride(NewMethod, MD, false);
+ }
+ }
+
+ if (ObjCInterfaceDecl *Class = llvm::dyn_cast<ObjCInterfaceDecl>(DC)) {
+ // Look through categories.
+ for (ObjCCategoryDecl *Category = Class->getCategoryList();
+ Category; Category = Category->getNextClassCategory()) {
+ if (CheckObjCMethodOverrides(S, NewMethod, Category, false))
+ return true;
+ }
+
+ // Look through protocols.
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Class->protocol_begin(),
+ IEnd = Class->protocol_end();
+ I != IEnd; ++I)
+ if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
+ return true;
+
+ // Look in our superclass.
+ return CheckObjCMethodOverrides(S, NewMethod, Class->getSuperClass(),
+ false);
+ }
+
+ if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC)) {
+ // Look through protocols.
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Category->protocol_begin(),
+ IEnd = Category->protocol_end();
+ I != IEnd; ++I)
+ if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
+ return true;
+
+ return false;
+ }
+
+ if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC)) {
+ // Look through protocols.
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocol->protocol_begin(),
+ IEnd = Protocol->protocol_end();
+ I != IEnd; ++I)
+ if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
+ return true;
+
+ return false;
+ }
+
+ return false;
+}
+
+bool Sema::CheckObjCMethodOverrides(ObjCMethodDecl *NewMethod,
+ DeclContext *DC) {
+ if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(DC))
+ return ::CheckObjCMethodOverrides(*this, NewMethod, Class);
+
+ if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC))
+ return ::CheckObjCMethodOverrides(*this, NewMethod, Category);
+
+ if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC))
+ return ::CheckObjCMethodOverrides(*this, NewMethod, Protocol);
+
+ if (ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(DC))
+ return ::CheckObjCMethodOverrides(*this, NewMethod,
+ Impl->getClassInterface());
+
+ if (ObjCCategoryImplDecl *CatImpl = dyn_cast<ObjCCategoryImplDecl>(DC))
+ return ::CheckObjCMethodOverrides(*this, NewMethod,
+ CatImpl->getClassInterface());
+
+ return ::CheckObjCMethodOverrides(*this, NewMethod, CurContext);
+}
+
static void DiagnoseObjCImplementedDeprecations(Sema &S,
NamedDecl *ND,
SourceLocation ImplLoc,
@@ -272,23 +407,27 @@ Decl *Sema::ActOnCompatiblityAlias(SourceLocation AtLoc,
return AliasDecl;
}
-void Sema::CheckForwardProtocolDeclarationForCircularDependency(
+bool Sema::CheckForwardProtocolDeclarationForCircularDependency(
IdentifierInfo *PName,
SourceLocation &Ploc, SourceLocation PrevLoc,
const ObjCList<ObjCProtocolDecl> &PList) {
+
+ bool res = false;
for (ObjCList<ObjCProtocolDecl>::iterator I = PList.begin(),
E = PList.end(); I != E; ++I) {
-
if (ObjCProtocolDecl *PDecl = LookupProtocol((*I)->getIdentifier(),
Ploc)) {
if (PDecl->getIdentifier() == PName) {
Diag(Ploc, diag::err_protocol_has_circular_dependency);
Diag(PrevLoc, diag::note_previous_definition);
+ res = true;
}
- CheckForwardProtocolDeclarationForCircularDependency(PName, Ploc,
- PDecl->getLocation(), PDecl->getReferencedProtocols());
+ if (CheckForwardProtocolDeclarationForCircularDependency(PName, Ploc,
+ PDecl->getLocation(), PDecl->getReferencedProtocols()))
+ res = true;
}
}
+ return res;
}
Decl *
@@ -300,6 +439,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
const SourceLocation *ProtoLocs,
SourceLocation EndProtoLoc,
AttributeList *AttrList) {
+ bool err = false;
// FIXME: Deal with AttrList.
assert(ProtocolName && "Missing protocol identifier");
ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolName, ProtocolLoc);
@@ -314,8 +454,8 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
}
ObjCList<ObjCProtocolDecl> PList;
PList.set((ObjCProtocolDecl *const*)ProtoRefs, NumProtoRefs, Context);
- CheckForwardProtocolDeclarationForCircularDependency(
- ProtocolName, ProtocolLoc, PDecl->getLocation(), PList);
+ err = CheckForwardProtocolDeclarationForCircularDependency(
+ ProtocolName, ProtocolLoc, PDecl->getLocation(), PList);
// Make sure the cached decl gets a valid start location.
PDecl->setLocation(AtProtoInterfaceLoc);
@@ -331,7 +471,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
}
if (AttrList)
ProcessDeclAttributeList(TUScope, PDecl, AttrList);
- if (NumProtoRefs) {
+ if (!err && NumProtoRefs ) {
/// Check then save referenced protocols.
PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
ProtoLocs, Context);
@@ -1712,11 +1852,71 @@ bool containsInvalidMethodImplAttribute(const AttrVec &A) {
return false;
}
+/// \brief Check whether the declared result type of the given Objective-C
+/// method declaration is compatible with the method's class.
+///
+static bool
+CheckRelatedResultTypeCompatibility(Sema &S, ObjCMethodDecl *Method,
+ ObjCInterfaceDecl *CurrentClass) {
+ QualType ResultType = Method->getResultType();
+ SourceRange ResultTypeRange;
+ if (const TypeSourceInfo *ResultTypeInfo = Method->getResultTypeSourceInfo())
+ ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange();
+
+ // 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:
+ if (const ObjCObjectPointerType *ResultObjectType
+ = ResultType->getAs<ObjCObjectPointerType>()) {
+ // - it is id or qualified id, or
+ if (ResultObjectType->isObjCIdType() ||
+ ResultObjectType->isObjCQualifiedIdType())
+ return false;
+
+ if (CurrentClass) {
+ if (ObjCInterfaceDecl *ResultClass
+ = ResultObjectType->getInterfaceDecl()) {
+ // - it is the same as the method's class type, or
+ if (CurrentClass == ResultClass)
+ return false;
+
+ // - it is a superclass of the method's class type
+ if (ResultClass->isSuperClassOf(CurrentClass))
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+/// \brief Determine if any method in the global method pool has an inferred
+/// result type.
+static bool
+anyMethodInfersRelatedResultType(Sema &S, Selector Sel, bool IsInstance) {
+ Sema::GlobalMethodPool::iterator Pos = S.MethodPool.find(Sel);
+ if (Pos == S.MethodPool.end()) {
+ if (S.ExternalSource)
+ Pos = S.ReadMethodPool(Sel);
+ else
+ return 0;
+ }
+
+ ObjCMethodList &List = IsInstance ? Pos->second.first : Pos->second.second;
+ for (ObjCMethodList *M = &List; M; M = M->Next) {
+ if (M->Method && M->Method->hasRelatedResultType())
+ return true;
+ }
+
+ return false;
+}
+
Decl *Sema::ActOnMethodDeclaration(
Scope *S,
SourceLocation MethodLoc, SourceLocation EndLoc,
tok::TokenKind MethodType, Decl *ClassDecl,
ObjCDeclSpec &ReturnQT, ParsedType ReturnType,
+ SourceLocation SelectorStartLoc,
Selector Sel,
// optional arguments. The number of types/arguments is obtained
// from the Sel.getNumArgs().
@@ -1741,7 +1941,7 @@ Decl *Sema::ActOnMethodDeclaration(
Diag(MethodLoc, diag::err_object_cannot_be_passed_returned_by_value)
<< 0 << resultDeclType;
return 0;
- }
+ }
} else // get the type for "id".
resultDeclType = Context.getObjCIdType();
@@ -1751,9 +1951,10 @@ Decl *Sema::ActOnMethodDeclaration(
cast<DeclContext>(ClassDecl),
MethodType == tok::minus, isVariadic,
false, false,
- MethodDeclKind == tok::objc_optional ?
- ObjCMethodDecl::Optional :
- ObjCMethodDecl::Required);
+ MethodDeclKind == tok::objc_optional
+ ? ObjCMethodDecl::Optional
+ : ObjCMethodDecl::Required,
+ false);
llvm::SmallVector<ParmVarDecl*, 16> Params;
@@ -1849,6 +2050,7 @@ Decl *Sema::ActOnMethodDeclaration(
}
InterfaceMD = ImpDecl->getClassInterface()->getMethod(Sel,
MethodType == tok::minus);
+
if (ObjCMethod->hasAttrs() &&
containsInvalidMethodImplAttribute(ObjCMethod->getAttrs()))
Diag(EndLoc, diag::warn_attribute_method_def);
@@ -1861,6 +2063,10 @@ Decl *Sema::ActOnMethodDeclaration(
PrevMethod = CatImpDecl->getClassMethod(Sel);
CatImpDecl->addClassMethod(ObjCMethod);
}
+
+ if (ObjCCategoryDecl *Cat = CatImpDecl->getCategoryDecl())
+ InterfaceMD = Cat->getMethod(Sel, MethodType == tok::minus);
+
if (ObjCMethod->hasAttrs() &&
containsInvalidMethodImplAttribute(ObjCMethod->getAttrs()))
Diag(EndLoc, diag::warn_attribute_method_def);
@@ -1874,10 +2080,65 @@ Decl *Sema::ActOnMethodDeclaration(
Diag(PrevMethod->getLocation(), diag::note_previous_declaration);
}
+ // If this Objective-C method does not have a related result type, but we
+ // are allowed to infer related result types, try to do so based on the
+ // method family.
+ ObjCInterfaceDecl *CurrentClass = dyn_cast<ObjCInterfaceDecl>(ClassDecl);
+ if (!CurrentClass) {
+ if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(ClassDecl))
+ CurrentClass = Cat->getClassInterface();
+ else if (ObjCImplDecl *Impl = dyn_cast<ObjCImplDecl>(ClassDecl))
+ CurrentClass = Impl->getClassInterface();
+ else if (ObjCCategoryImplDecl *CatImpl
+ = dyn_cast<ObjCCategoryImplDecl>(ClassDecl))
+ CurrentClass = CatImpl->getClassInterface();
+ }
+
// Merge information down from the interface declaration if we have one.
- if (InterfaceMD)
+ if (InterfaceMD) {
+ // Inherit the related result type, if we can.
+ if (InterfaceMD->hasRelatedResultType() &&
+ !CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass))
+ ObjCMethod->SetRelatedResultType();
+
mergeObjCMethodDecls(ObjCMethod, InterfaceMD);
-
+ }
+
+ if (!ObjCMethod->hasRelatedResultType() &&
+ getLangOptions().ObjCInferRelatedResultType) {
+ bool InferRelatedResultType = false;
+ switch (ObjCMethod->getMethodFamily()) {
+ case OMF_None:
+ case OMF_copy:
+ case OMF_dealloc:
+ case OMF_mutableCopy:
+ case OMF_release:
+ case OMF_retainCount:
+ break;
+
+ case OMF_alloc:
+ case OMF_new:
+ InferRelatedResultType = ObjCMethod->isClassMethod();
+ break;
+
+ case OMF_init:
+ case OMF_autorelease:
+ case OMF_retain:
+ case OMF_self:
+ InferRelatedResultType = ObjCMethod->isInstanceMethod();
+ break;
+ }
+
+ if (InferRelatedResultType &&
+ !CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass))
+ ObjCMethod->SetRelatedResultType();
+
+ if (!InterfaceMD &&
+ anyMethodInfersRelatedResultType(*this, ObjCMethod->getSelector(),
+ ObjCMethod->isInstanceMethod()))
+ CheckObjCMethodOverrides(ObjCMethod, cast<DeclContext>(ClassDecl));
+ }
+
return ObjCMethod;
}
OpenPOWER on IntegriCloud