aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/DeclObjC.h9
-rw-r--r--include/clang/Basic/DiagnosticGroups.td1
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--include/clang/Parse/Action.h2
-rw-r--r--include/clang/Parse/Parser.h2
-rw-r--r--lib/AST/ASTImporter.cpp1
-rw-r--r--lib/AST/DeclObjC.cpp4
-rw-r--r--lib/CodeGen/CodeGenModule.cpp4
-rw-r--r--lib/Frontend/PCHReaderDecl.cpp1
-rw-r--r--lib/Frontend/PCHWriterDecl.cpp1
-rw-r--r--lib/Parse/ParseObjc.cpp3
-rw-r--r--lib/Sema/ParseAST.cpp2
-rw-r--r--lib/Sema/Sema.h18
-rw-r--r--lib/Sema/SemaDeclObjC.cpp85
-rw-r--r--lib/Sema/SemaExprObjC.cpp5
-rw-r--r--lib/Sema/SemaObjCProperty.cpp4
16 files changed, 104 insertions, 40 deletions
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index 2a175513cb..d4735bfb84 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -128,6 +128,9 @@ private:
// Synthesized declaration method for a property setter/getter
bool IsSynthesized : 1;
+
+ // Method has a definition.
+ bool IsDefined : 1;
// NOTE: VC++ treats enums as signed, avoid using ImplementationControl enum
/// @required/@optional
@@ -171,12 +174,14 @@ private:
bool isInstance = true,
bool isVariadic = false,
bool isSynthesized = false,
+ bool isDefined = false,
ImplementationControl impControl = None,
unsigned numSelectorArgs = 0)
: NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo),
DeclContext(ObjCMethod),
IsInstance(isInstance), IsVariadic(isVariadic),
IsSynthesized(isSynthesized),
+ IsDefined(isDefined),
DeclImplementation(impControl), objcDeclQualifier(OBJC_TQ_None),
NumSelectorArgs(numSelectorArgs), MethodDeclType(T),
ResultTInfo(ResultTInfo),
@@ -203,6 +208,7 @@ public:
bool isInstance = true,
bool isVariadic = false,
bool isSynthesized = false,
+ bool isDefined = false,
ImplementationControl impControl = None,
unsigned numSelectorArgs = 0);
@@ -296,6 +302,9 @@ public:
bool isSynthesized() const { return IsSynthesized; }
void setSynthesized(bool isSynth) { IsSynthesized = isSynth; }
+
+ bool isDefined() const { return IsDefined; }
+ void setDefined(bool isDefined) { IsDefined = isDefined; }
// Related to protocols declared in @protocol
void setDeclImplementation(ImplementationControl ic) {
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 1416d7195a..033b6c4214 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -134,6 +134,7 @@ def UnusedVariable : DiagGroup<"unused-variable">;
def ReadOnlySetterAttrs : DiagGroup<"readonly-setter-attrs">;
def Reorder : DiagGroup<"reorder">;
def UndeclaredSelector : DiagGroup<"undeclared-selector">;
+def Selector : DiagGroup<"selector">;
def Protocol : DiagGroup<"protocol">;
def SuperSubClassMismatch : DiagGroup<"super-class-method-mismatch">;
def : DiagGroup<"variadic-macros">;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 59bd8f8e38..6fb53189cd 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -400,6 +400,8 @@ def warn_objc_property_attr_mutually_exclusive : Warning<
InGroup<ReadOnlySetterAttrs>, DefaultIgnore;
def warn_undeclared_selector : Warning<
"undeclared selector %0">, InGroup<UndeclaredSelector>, DefaultIgnore;
+def warn_unimplemented_selector: Warning<
+ "unimplemented selector %0">, InGroup<Selector>, DefaultIgnore;
def warn_unimplemented_protocol_method : Warning<
"method in protocol not implemented">, InGroup<Protocol>;
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index 9cb47aa8da..2ca49ad675 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -202,6 +202,8 @@ public:
return DeclGroupPtrTy();
}
+ virtual void DiagnoseUseOfUnimplementedSelectors() {}
+
/// getTypeName - Return non-null if the specified identifier is a type name
/// in the current scope.
///
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 90a1cab5cf..c23adb60d2 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -201,7 +201,7 @@ public:
/// the EOF was encountered.
bool ParseTopLevelDecl(DeclGroupPtrTy &Result);
- DeclGroupPtrTy RetrievePendingObjCImpDecl();
+ DeclGroupPtrTy FinishPendingObjCActions();
private:
//===--------------------------------------------------------------------===//
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 6b2c90c1d1..befdc7aede 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -2299,6 +2299,7 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
D->isInstanceMethod(),
D->isVariadic(),
D->isSynthesized(),
+ D->isDefined(),
D->getImplementationControl());
// FIXME: When we decide to merge method definitions, we'll need to
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index fce24dcf38..c682cf18bf 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -339,12 +339,14 @@ ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C,
bool isInstance,
bool isVariadic,
bool isSynthesized,
+ bool isDefined,
ImplementationControl impControl,
unsigned numSelectorArgs) {
return new (C) ObjCMethodDecl(beginLoc, endLoc,
SelInfo, T, ResultTInfo, contextDecl,
isInstance,
- isVariadic, isSynthesized, impControl,
+ isVariadic, isSynthesized, isDefined,
+ impControl,
numSelectorArgs);
}
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index f6788c6c30..057182d039 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -1930,7 +1930,7 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
D->getLocation(),
D->getLocation(), cxxSelector,
getContext().VoidTy, 0,
- DC, true, false, true,
+ DC, true, false, true, false,
ObjCMethodDecl::Required);
D->addInstanceMethod(DTORMethod);
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false);
@@ -1942,7 +1942,7 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
D->getLocation(),
D->getLocation(), cxxSelector,
getContext().getObjCIdType(), 0,
- DC, true, false, true,
+ DC, true, false, true, false,
ObjCMethodDecl::Required);
D->addInstanceMethod(CTORMethod);
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true);
diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp
index d1f8b3aae9..058b19dab3 100644
--- a/lib/Frontend/PCHReaderDecl.cpp
+++ b/lib/Frontend/PCHReaderDecl.cpp
@@ -324,6 +324,7 @@ void PCHDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
MD->setInstanceMethod(Record[Idx++]);
MD->setVariadic(Record[Idx++]);
MD->setSynthesized(Record[Idx++]);
+ MD->setDefined(Record[Idx++]);
MD->setDeclImplementation((ObjCMethodDecl::ImplementationControl)Record[Idx++]);
MD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]);
MD->setNumSelectorArgs(unsigned(Record[Idx++]));
diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp
index f6c6cde157..7c4a21adb6 100644
--- a/lib/Frontend/PCHWriterDecl.cpp
+++ b/lib/Frontend/PCHWriterDecl.cpp
@@ -312,6 +312,7 @@ void PCHDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
Record.push_back(D->isInstanceMethod());
Record.push_back(D->isVariadic());
Record.push_back(D->isSynthesized());
+ Record.push_back(D->isDefined());
// FIXME: stable encoding for @required/@optional
Record.push_back(D->getImplementationControl());
// FIXME: stable encoding for in/out/inout/bycopy/byref/oneway
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 68473a551d..a7e08562d0 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -1314,7 +1314,8 @@ Parser::DeclPtrTy Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) {
return Result;
}
-Parser::DeclGroupPtrTy Parser::RetrievePendingObjCImpDecl() {
+Parser::DeclGroupPtrTy Parser::FinishPendingObjCActions() {
+ Actions.DiagnoseUseOfUnimplementedSelectors();
if (PendingObjCImpDecl.empty())
return Actions.ConvertDeclToDeclGroup(DeclPtrTy());
DeclPtrTy ImpDecl = PendingObjCImpDecl.pop_back_val();
diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp
index bb0bd9e1cb..73f1167d0e 100644
--- a/lib/Sema/ParseAST.cpp
+++ b/lib/Sema/ParseAST.cpp
@@ -92,7 +92,7 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
Consumer->HandleTopLevelDecl(ADecl.getAsVal<DeclGroupRef>());
};
// Check for any pending objective-c implementation decl.
- while ((ADecl = P.RetrievePendingObjCImpDecl()))
+ while ((ADecl = P.FinishPendingObjCActions()))
Consumer->HandleTopLevelDecl(ADecl.getAsVal<DeclGroupRef>());
// Process any TopLevelDecls generated by #pragma weak.
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 490ff65cd9..0540dd9e0c 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -606,6 +606,11 @@ public:
MethodPool InstanceMethodPool;
MethodPool FactoryMethodPool;
+ /// Method selectors used in a @selector expression. Used for implementation
+ /// of -Wselector.
+ llvm::DenseMap<Selector, SourceLocation> ReferencedSelectors;
+
+
MethodPool::iterator ReadMethodPool(Selector Sel, bool isInstance);
/// Private Helper predicate to check for 'self'.
@@ -798,6 +803,8 @@ public:
DeclGroupPtrTy ConvertDeclToDeclGroup(DeclPtrTy Ptr);
+ void DiagnoseUseOfUnimplementedSelectors();
+
virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
Scope *S, CXXScopeSpec *SS,
bool isClassName = false,
@@ -1656,7 +1663,7 @@ public:
/// unit are added to a global pool. This allows us to efficiently associate
/// a selector with a method declaraation for purposes of typechecking
/// messages sent to "id" (where the class of the object is unknown).
- void AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method);
+ void AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method, bool impl=false);
/// LookupInstanceMethodInGlobalPool - Returns the method and warns if
/// there are multiple signatures.
@@ -1665,10 +1672,15 @@ public:
/// LookupFactoryMethodInGlobalPool - Returns the method and warns if
/// there are multiple signatures.
- ObjCMethodDecl *LookupFactoryMethodInGlobalPool(Selector Sel, SourceRange R);
+ ObjCMethodDecl *LookupFactoryMethodInGlobalPool(Selector Sel, SourceRange R,
+ bool warn=true);
+
+ /// LookupImplementedMethodInGlobalPool - Returns the method which has an
+ /// implementation.
+ ObjCMethodDecl *LookupImplementedMethodInGlobalPool(Selector Sel);
/// AddFactoryMethodToGlobalPool - Same as above, but for factory methods.
- void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method);
+ void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method, bool impl=false);
/// CollectIvarsToConstructOrDestruct - Collect those ivars which require
/// initialization.
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 21aeb59a08..5f2f37eb0b 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -32,10 +32,10 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) {
// Allow the rest of sema to find private method decl implementations.
if (MDecl->isInstanceMethod())
- AddInstanceMethodToGlobalPool(MDecl);
+ AddInstanceMethodToGlobalPool(MDecl, true);
else
- AddFactoryMethodToGlobalPool(MDecl);
-
+ AddFactoryMethodToGlobalPool(MDecl, true);
+
// Allow all of Sema to see that we are entering a method definition.
PushDeclContext(FnBodyScope, MDecl);
PushFunctionScope();
@@ -1130,7 +1130,7 @@ Sema::MethodPool::iterator Sema::ReadMethodPool(Selector Sel,
return FactoryMethodPool.insert(std::make_pair(Sel, Methods.second)).first;
}
-void Sema::AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method) {
+void Sema::AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method, bool impl) {
llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos
= InstanceMethodPool.find(Method->getSelector());
if (Pos == InstanceMethodPool.end()) {
@@ -1140,7 +1140,7 @@ void Sema::AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method) {
Pos = InstanceMethodPool.insert(std::make_pair(Method->getSelector(),
ObjCMethodList())).first;
}
-
+ Method->setDefined(impl);
ObjCMethodList &Entry = Pos->second;
if (Entry.Method == 0) {
// Haven't seen a method with this selector name yet - add it.
@@ -1152,8 +1152,10 @@ void Sema::AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method) {
// We've seen a method with this name, see if we have already seen this type
// signature.
for (ObjCMethodList *List = &Entry; List; List = List->Next)
- if (MatchTwoMethodDeclarations(Method, List->Method))
+ if (MatchTwoMethodDeclarations(Method, List->Method)) {
+ List->Method->setDefined(impl);
return;
+ }
// We have a new signature for an existing method - add it.
// This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
@@ -1194,7 +1196,7 @@ ObjCMethodDecl *Sema::LookupInstanceMethodInGlobalPool(Selector Sel,
return MethList.Method;
}
-void Sema::AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method) {
+void Sema::AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method, bool impl) {
llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos
= FactoryMethodPool.find(Method->getSelector());
if (Pos == FactoryMethodPool.end()) {
@@ -1204,32 +1206,31 @@ void Sema::AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method) {
Pos = FactoryMethodPool.insert(std::make_pair(Method->getSelector(),
ObjCMethodList())).first;
}
-
- ObjCMethodList &FirstMethod = Pos->second;
- if (!FirstMethod.Method) {
+ Method->setDefined(impl);
+ ObjCMethodList &Entry = Pos->second;
+ if (!Entry.Method) {
// Haven't seen a method with this selector name yet - add it.
- FirstMethod.Method = Method;
- FirstMethod.Next = 0;
- } else {
- // We've seen a method with this name, now check the type signature(s).
- bool match = MatchTwoMethodDeclarations(Method, FirstMethod.Method);
-
- for (ObjCMethodList *Next = FirstMethod.Next; !match && Next;
- Next = Next->Next)
- match = MatchTwoMethodDeclarations(Method, Next->Method);
-
- if (!match) {
- // 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>();
- ObjCMethodList *OMI = new (Mem) ObjCMethodList(Method, FirstMethod.Next);
- FirstMethod.Next = OMI;
+ Entry.Method = Method;
+ Entry.Next = 0;
+ return;
+ }
+ // We've seen a method with this name, see if we have already seen this type
+ // signature.
+ for (ObjCMethodList *List = &Entry; List; List = List->Next)
+ if (MatchTwoMethodDeclarations(Method, List->Method)) {
+ List->Method->setDefined(impl);
+ return;
}
- }
+
+ // 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>();
+ Entry.Next = new (Mem) ObjCMethodList(Method, Entry.Next);
}
ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel,
- SourceRange R) {
+ SourceRange R,
+ bool warn) {
llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos
= FactoryMethodPool.find(Sel);
if (Pos == FactoryMethodPool.end()) {
@@ -1246,7 +1247,7 @@ ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel,
for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next)
// This checks if the methods differ by size & alignment.
if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, true))
- issueWarning = true;
+ issueWarning = warn;
}
if (issueWarning && (MethList.Method && MethList.Next)) {
Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R;
@@ -1259,6 +1260,18 @@ ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel,
return MethList.Method;
}
+ObjCMethodDecl *Sema::LookupImplementedMethodInGlobalPool(Selector Sel) {
+ SourceRange SR;
+ ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(Sel,
+ SR, false);
+ if (Method && Method->isDefined())
+ return Method;
+ Method = LookupFactoryMethodInGlobalPool(Sel, SR, false);
+ if (Method && Method->isDefined())
+ return Method;
+ return 0;
+}
+
/// CompareMethodParamsInBaseAndSuper - This routine compares methods with
/// identical selector names in current and its super classes and issues
/// a warning if any of their argument types are incompatible.
@@ -1540,7 +1553,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
ResultTInfo,
cast<DeclContext>(ClassDecl),
MethodType == tok::minus, isVariadic,
- false,
+ false, false,
MethodDeclKind == tok::objc_optional ?
ObjCMethodDecl::Optional :
ObjCMethodDecl::Required);
@@ -1849,3 +1862,15 @@ void ObjCImplementationDecl::setIvarInitializers(ASTContext &C,
}
}
+void Sema::DiagnoseUseOfUnimplementedSelectors() {
+ if (ReferencedSelectors.empty())
+ return;
+ for (llvm::DenseMap<Selector, SourceLocation>::iterator S =
+ ReferencedSelectors.begin(),
+ E = ReferencedSelectors.end(); S != E; ++S) {
+ Selector Sel = (*S).first;
+ if (!LookupImplementedMethodInGlobalPool(Sel))
+ Diag((*S).second, diag::warn_unimplemented_selector) << Sel;
+ }
+ return;
+}
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 9f43471e0a..5132464d24 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -163,6 +163,11 @@ Sema::ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
if (!Method)
Diag(SelLoc, diag::warn_undeclared_selector) << Sel;
+ llvm::DenseMap<Selector, SourceLocation>::iterator Pos
+ = ReferencedSelectors.find(Sel);
+ if (Pos == ReferencedSelectors.end())
+ ReferencedSelectors.insert(std::make_pair(Sel, SelLoc));
+
QualType Ty = Context.getObjCSelType();
return new (Context) ObjCSelectorExpr(Ty, Sel, AtLoc, RParenLoc);
}
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index e7358edec3..6a7d8dbee1 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -1084,7 +1084,8 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
// for this class.
GetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(),
property->getLocation(), property->getGetterName(),
- property->getType(), 0, CD, true, false, true,
+ property->getType(), 0, CD, true, false, true,
+ false,
(property->getPropertyImplementation() ==
ObjCPropertyDecl::Optional) ?
ObjCMethodDecl::Optional :
@@ -1112,6 +1113,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
property->getLocation(),
property->getSetterName(),
Context.VoidTy, 0, CD, true, false, true,
+ false,
(property->getPropertyImplementation() ==
ObjCPropertyDecl::Optional) ?
ObjCMethodDecl::Optional :