summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/AST/DeclObjC.h11
-rw-r--r--clang/lib/Sema/Sema.h14
-rw-r--r--clang/lib/Sema/SemaDeclObjC.cpp99
-rw-r--r--clang/test/SemaObjC/method-undef-extension-warn-1.m25
4 files changed, 67 insertions, 82 deletions
diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h
index bdb8759b582..33662b287d5 100644
--- a/clang/include/clang/AST/DeclObjC.h
+++ b/clang/include/clang/AST/DeclObjC.h
@@ -757,13 +757,16 @@ class ObjCImplDecl : public Decl, public DeclContext {
llvm::SmallVector<ObjCPropertyImplDecl*, 8> PropertyImplementations;
SourceLocation EndLoc;
+
protected:
ObjCImplDecl(Kind DK, DeclContext *DC, SourceLocation L,
ObjCInterfaceDecl *classInterface)
- : Decl(DK, DC, L), DeclContext(DK),
- ClassInterface(classInterface) {}
+ : Decl(DK, DC, L), DeclContext(DK),
+ ClassInterface(classInterface) {}
public:
+ virtual ~ObjCImplDecl() {}
+
const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; }
ObjCInterfaceDecl *getClassInterface() { return ClassInterface; }
@@ -849,12 +852,12 @@ public:
/// interface associated with this implementation as a C string
/// (const char*).
const char *getNameAsCString() const {
- return Id->getName();
+ return Id ? Id->getName() : "";
}
/// @brief Get the name of the class associated with this interface.
std::string getNameAsString() const {
- return Id->getName();
+ return Id ? Id->getName() : "";
}
static bool classof(const Decl *D) { return D->getKind() == ObjCCategoryImpl;}
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h
index 3e9d07aefb6..6e0b935b88a 100644
--- a/clang/lib/Sema/Sema.h
+++ b/clang/lib/Sema/Sema.h
@@ -68,6 +68,7 @@ namespace clang {
class ObjCInterfaceDecl;
class ObjCCompatibleAliasDecl;
class ObjCProtocolDecl;
+ class ObjCImplDecl;
class ObjCImplementationDecl;
class ObjCCategoryImplDecl;
class ObjCCategoryDecl;
@@ -930,14 +931,11 @@ public:
SourceLocation Loc);
/// ImplMethodsVsClassMethods - This is main routine to warn if any method
- /// remains unimplemented in the @implementation class.
- void ImplMethodsVsClassMethods(ObjCImplementationDecl* IMPDecl,
- ObjCInterfaceDecl* IDecl);
-
- /// ImplCategoryMethodsVsIntfMethods - Checks that methods declared in the
- /// category interface is implemented in the category @implementation.
- void ImplCategoryMethodsVsIntfMethods(ObjCCategoryImplDecl *CatImplDecl,
- ObjCCategoryDecl *CatClassDecl);
+ /// remains unimplemented in the class or category @implementation.
+ void ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
+ ObjCContainerDecl* IDecl,
+ bool IncompleteImpl = false);
+
/// MatchTwoMethodDeclarations - Checks if two methods' type match and returns
/// true, or false, accordingly.
bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method,
diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp
index 654891d5ab5..f1f03844a24 100644
--- a/clang/lib/Sema/SemaDeclObjC.cpp
+++ b/clang/lib/Sema/SemaDeclObjC.cpp
@@ -814,8 +814,9 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
CheckProtocolMethodDefs(ImpLoc, *PI, IncompleteImpl, InsMap, ClsMap, IDecl);
}
-void Sema::ImplMethodsVsClassMethods(ObjCImplementationDecl* IMPDecl,
- ObjCInterfaceDecl* IDecl) {
+void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
+ ObjCContainerDecl* CDecl,
+ bool IncompleteImpl) {
llvm::DenseSet<Selector> InsMap;
// Check and see if instance methods in class interface have been
// implemented in the implementation class.
@@ -823,9 +824,8 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplementationDecl* IMPDecl,
E = IMPDecl->instmeth_end(); I != E; ++I)
InsMap.insert((*I)->getSelector());
- bool IncompleteImpl = false;
- for (ObjCInterfaceDecl::instmeth_iterator I = IDecl->instmeth_begin(),
- E = IDecl->instmeth_end(); I != E; ++I) {
+ for (ObjCInterfaceDecl::instmeth_iterator I = CDecl->instmeth_begin(),
+ E = CDecl->instmeth_end(); I != E; ++I) {
if (!(*I)->isSynthesized() && !InsMap.count((*I)->getSelector())) {
WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl);
continue;
@@ -834,7 +834,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplementationDecl* IMPDecl,
ObjCMethodDecl *ImpMethodDecl =
IMPDecl->getInstanceMethod((*I)->getSelector());
ObjCMethodDecl *IntfMethodDecl =
- IDecl->getInstanceMethod((*I)->getSelector());
+ CDecl->getInstanceMethod((*I)->getSelector());
assert(IntfMethodDecl &&
"IntfMethodDecl is null in ImplMethodsVsClassMethods");
// ImpMethodDecl may be null as in a @dynamic property.
@@ -849,82 +849,41 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplementationDecl* IMPDecl,
E = IMPDecl->classmeth_end(); I != E; ++I)
ClsMap.insert((*I)->getSelector());
- for (ObjCInterfaceDecl::classmeth_iterator I = IDecl->classmeth_begin(),
- E = IDecl->classmeth_end(); I != E; ++I)
+ for (ObjCInterfaceDecl::classmeth_iterator I = CDecl->classmeth_begin(),
+ E = CDecl->classmeth_end(); I != E; ++I)
if (!ClsMap.count((*I)->getSelector()))
WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl);
else {
ObjCMethodDecl *ImpMethodDecl =
IMPDecl->getClassMethod((*I)->getSelector());
ObjCMethodDecl *IntfMethodDecl =
- IDecl->getClassMethod((*I)->getSelector());
+ CDecl->getClassMethod((*I)->getSelector());
WarnConflictingTypedMethods(ImpMethodDecl, IntfMethodDecl);
}
// Check the protocol list for unimplemented methods in the @implementation
// class.
- const ObjCList<ObjCProtocolDecl> &Protocols =
- IDecl->getReferencedProtocols();
- for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
- E = Protocols.end(); I != E; ++I)
- CheckProtocolMethodDefs(IMPDecl->getLocation(), *I,
- IncompleteImpl, InsMap, ClsMap, IDecl);
-}
-
-/// ImplCategoryMethodsVsIntfMethods - Checks that methods declared in the
-/// category interface are implemented in the category @implementation.
-void Sema::ImplCategoryMethodsVsIntfMethods(ObjCCategoryImplDecl *CatImplDecl,
- ObjCCategoryDecl *CatClassDecl) {
- llvm::DenseSet<Selector> InsMap;
- // Check and see if instance methods in category interface have been
- // implemented in its implementation class.
- for (ObjCCategoryImplDecl::instmeth_iterator I =CatImplDecl->instmeth_begin(),
- E = CatImplDecl->instmeth_end(); I != E; ++I)
- InsMap.insert((*I)->getSelector());
-
- bool IncompleteImpl = false;
- for (ObjCCategoryDecl::instmeth_iterator I = CatClassDecl->instmeth_begin(),
- E = CatClassDecl->instmeth_end(); I != E; ++I)
- if (!(*I)->isSynthesized() && !InsMap.count((*I)->getSelector()))
- WarnUndefinedMethod(CatImplDecl->getLocation(), *I, IncompleteImpl);
- else {
- ObjCMethodDecl *ImpMethodDecl =
- CatImplDecl->getInstanceMethod((*I)->getSelector());
- ObjCMethodDecl *IntfMethodDecl =
- CatClassDecl->getInstanceMethod((*I)->getSelector());
- assert(IntfMethodDecl &&
- "IntfMethodDecl is null in ImplCategoryMethodsVsIntfMethods");
- // ImpMethodDecl may be null as in a @dynamic property.
- if (ImpMethodDecl)
- WarnConflictingTypedMethods(ImpMethodDecl, IntfMethodDecl);
- }
-
- llvm::DenseSet<Selector> ClsMap;
- // Check and see if class methods in category interface have been
- // implemented in its implementation class.
- for (ObjCCategoryImplDecl::classmeth_iterator
- I = CatImplDecl->classmeth_begin(), E = CatImplDecl->classmeth_end();
- I != E; ++I)
- ClsMap.insert((*I)->getSelector());
-
- for (ObjCCategoryDecl::classmeth_iterator I = CatClassDecl->classmeth_begin(),
- E = CatClassDecl->classmeth_end(); I != E; ++I)
- if (!ClsMap.count((*I)->getSelector()))
- WarnUndefinedMethod(CatImplDecl->getLocation(), *I, IncompleteImpl);
- else {
- ObjCMethodDecl *ImpMethodDecl =
- CatImplDecl->getClassMethod((*I)->getSelector());
- ObjCMethodDecl *IntfMethodDecl =
- CatClassDecl->getClassMethod((*I)->getSelector());
- WarnConflictingTypedMethods(ImpMethodDecl, IntfMethodDecl);
+ if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl> (CDecl)) {
+ for (ObjCCategoryDecl::protocol_iterator PI = I->protocol_begin(),
+ E = I->protocol_end(); PI != E; ++PI)
+ CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl,
+ InsMap, ClsMap, I);
+ // Check class extensions (unnamed categories)
+ for (ObjCCategoryDecl *Categories = I->getCategoryList();
+ Categories; Categories = Categories->getNextClassCategory()) {
+ if (!Categories->getIdentifier()) {
+ ImplMethodsVsClassMethods(IMPDecl, Categories, IncompleteImpl);
+ break;
+ }
}
- // Check the protocol list for unimplemented methods in the @implementation
- // class.
- for (ObjCCategoryDecl::protocol_iterator PI = CatClassDecl->protocol_begin(),
- E = CatClassDecl->protocol_end(); PI != E; ++PI)
- CheckProtocolMethodDefs(CatImplDecl->getLocation(), *PI, IncompleteImpl,
- InsMap, ClsMap, CatClassDecl->getClassInterface());
+ } else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) {
+ for (ObjCCategoryDecl::protocol_iterator PI = C->protocol_begin(),
+ E = C->protocol_end(); PI != E; ++PI)
+ CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl,
+ InsMap, ClsMap, C->getClassInterface());
+ } else
+ assert(false && "invalid ObjCContainerDecl type.");
}
/// ActOnForwardClassDeclaration -
@@ -1302,7 +1261,7 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclTy *classDecl,
for (ObjCCategoryDecl *Categories = IDecl->getCategoryList();
Categories; Categories = Categories->getNextClassCategory()) {
if (Categories->getIdentifier() == CatImplClass->getIdentifier()) {
- ImplCategoryMethodsVsIntfMethods(CatImplClass, Categories);
+ ImplMethodsVsClassMethods(CatImplClass, Categories);
break;
}
}
diff --git a/clang/test/SemaObjC/method-undef-extension-warn-1.m b/clang/test/SemaObjC/method-undef-extension-warn-1.m
new file mode 100644
index 00000000000..00201c88a44
--- /dev/null
+++ b/clang/test/SemaObjC/method-undef-extension-warn-1.m
@@ -0,0 +1,25 @@
+// RUN: clang -fsyntax-only -verify %s
+
+@interface MyClass
+@end
+
+@protocol P
+- (void)Pmeth;
+- (void)Pmeth1;
+@end
+
+// Class extension
+@interface MyClass () <P>
+- (void)meth2;
+@end
+
+// Add a category to test that clang does not emit warning for this method.
+@interface MyClass (Category)
+- (void)categoryMethod;
+@end
+
+@implementation MyClass // expected-warning {{incomplete implementation}} \
+ expected-warning {{method definition for 'meth2' not found}} \
+ expected-warning {{method definition for 'Pmeth1' not found}}
+- (void)Pmeth {}
+@end
OpenPOWER on IntegriCloud