aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--lib/Sema/SemaStmt.cpp21
-rw-r--r--test/CodeGenObjC/for-in.m4
-rw-r--r--test/SemaObjCXX/instantiate-stmt.mm1
4 files changed, 26 insertions, 2 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 9663acc6a3..ba156b16cf 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3170,6 +3170,8 @@ def err_selector_element_type : Error<
"selector element type %0 is not a valid object">;
def err_collection_expr_type : Error<
"collection expression type %0 is not a valid object">;
+def warn_collection_expr_type : Warning<
+ "collection expression type %0 may not respond to %1">;
def err_invalid_conversion_between_ext_vectors : Error<
"invalid conversion between ext-vector type %0 and %1">;
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 097ea68655..73e142c782 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -941,6 +941,27 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
if (!SecondType->isObjCObjectPointerType())
Diag(ForLoc, diag::err_collection_expr_type)
<< SecondType << Second->getSourceRange();
+ else if (const ObjCObjectPointerType *OPT =
+ SecondType->getAsObjCInterfacePointerType()) {
+ llvm::SmallVector<IdentifierInfo *, 4> KeyIdents;
+ IdentifierInfo* selIdent =
+ &Context.Idents.get("countByEnumeratingWithState");
+ KeyIdents.push_back(selIdent);
+ selIdent = &Context.Idents.get("objects");
+ KeyIdents.push_back(selIdent);
+ selIdent = &Context.Idents.get("count");
+ KeyIdents.push_back(selIdent);
+ Selector CSelector = Context.Selectors.getSelector(3, &KeyIdents[0]);
+ if (ObjCInterfaceDecl *IDecl = OPT->getInterfaceDecl()) {
+ if (!IDecl->isForwardDecl() &&
+ !IDecl->lookupInstanceMethod(CSelector)) {
+ // Must further look into privaye implementation methods.
+ if (!LookupPrivateInstanceMethod(CSelector, IDecl))
+ Diag(ForLoc, diag::warn_collection_expr_type)
+ << SecondType << CSelector << Second->getSourceRange();
+ }
+ }
+ }
}
first.release();
second.release();
diff --git a/test/CodeGenObjC/for-in.m b/test/CodeGenObjC/for-in.m
index 354ff32c0e..7e6098a7eb 100644
--- a/test/CodeGenObjC/for-in.m
+++ b/test/CodeGenObjC/for-in.m
@@ -23,7 +23,7 @@ void t0() {
p("array.length: %d\n", [array count]);
unsigned index = 0;
- for (NSString *i in array) {
+ for (NSString *i in array) { // expected-warning {{collection expression type 'NSArray *' may not respond}}
p("element %d: %s\n", index++, [i cString]);
}
}
@@ -33,7 +33,7 @@ void t1() {
p("array.length: %d\n", [array count]);
unsigned index = 0;
- for (NSString *i in array) {
+ for (NSString *i in array) { // expected-warning {{collection expression type 'NSArray *' may not respond}}
index++;
if (index == 10)
continue;
diff --git a/test/SemaObjCXX/instantiate-stmt.mm b/test/SemaObjCXX/instantiate-stmt.mm
index e92f8e8d4f..5e8ec61573 100644
--- a/test/SemaObjCXX/instantiate-stmt.mm
+++ b/test/SemaObjCXX/instantiate-stmt.mm
@@ -25,6 +25,7 @@ template void synchronized_test(int); // expected-note{{in instantiation of}}
// fast enumeration
@interface NSArray
+- (unsigned int)countByEnumeratingWithState: (struct __objcFastEnumerationState *)state objects: (id *)items count:(unsigned int)stackcount;
@end
@interface NSString