]> granicus.if.org Git - clang/commitdiff
Patch to add semantics check for ObjC2's foreacn statement.
authorFariborz Jahanian <fjahanian@apple.com>
Fri, 4 Jan 2008 00:27:46 +0000 (00:27 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Fri, 4 Jan 2008 00:27:46 +0000 (00:27 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@45561 91177308-0d34-0410-b5e6-96231b3b80d8

Sema/Sema.cpp
Sema/Sema.h
Sema/SemaExpr.cpp
Sema/SemaStmt.cpp
include/clang/Basic/DiagnosticKinds.def
test/Parser/objc-forcollection-1.m [new file with mode: 0644]
test/Parser/objc-forcollection-neg.m [new file with mode: 0644]

index bca3ec508bf29185407ef5f09e12879339296bb7..8f340db14e0d78be00513215bb4879f30a7ee000 100644 (file)
@@ -26,6 +26,20 @@ bool Sema::isBuiltinObjcType(TypedefDecl *TD) {
          strcmp(typeName, "SEL") == 0 || strcmp(typeName, "Protocol") == 0;
 }
 
+bool Sema::isObjcObjectPointerType(QualType type) const {
+  if (!type->isPointerType() && !type->isObjcQualifiedIdType())
+    return false;
+  if (type == Context.getObjcIdType() || type == Context.getObjcClassType() ||
+      type->isObjcQualifiedIdType())
+    return true;
+  
+  while (type->isPointerType()) {
+    PointerType *pointerType = static_cast<PointerType*>(type.getTypePtr());
+    type = pointerType->getPointeeType();
+  }
+  return (type->isObjcInterfaceType() || type->isObjcQualifiedIdType());
+}
+
 void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
   TUScope = S;
   if (PP.getLangOptions().ObjC1) {
index 8846d158134f3195284f4b44a626a2490bfe3690..6f546514dbb076200e4bd3469a5637b5d72d33b4 100644 (file)
@@ -285,6 +285,10 @@ private:
   /// isBuiltinObjcType - Returns true of the type is "id", "SEL", "Class"
   /// or "Protocol".
   bool isBuiltinObjcType(TypedefDecl *TD);
+  
+  /// isObjcObjectPointerType - Returns tru if type is an objective-c pointer
+  /// to an object type; such as "id", "Class", Intf*, id<P>, etc.
+  bool isObjcObjectPointerType(QualType type) const;
 
   /// AddInstanceMethodToGlobalPool - All instance methods in a translation
   /// unit are added to a global pool. This allows us to efficiently associate
index de642c6e65e18b87f4f71a6fc317cad449ad3be4..3a3cfc18bc08a618b1d2c9ce6bb6f7bd2764ca5f 100644 (file)
@@ -2350,8 +2350,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(
           return true;
     }
   } else {
-    bool receiverIsQualId = 
-           dyn_cast<ObjcQualifiedIdType>(RExpr->getType()) != 0;
+    bool receiverIsQualId = dyn_cast<ObjcQualifiedIdType>(receiverType) != 0;
     // FIXME (snaroff): checking in this code from Patrick. Needs to be
     // revisited. how do we get the ClassDecl from the receiver expression?
     if (!receiverIsQualId)
index 2c2dc5e3f0c13a4339dfcdb1be727557030d187b..6b60bd02744218d50c36eedfeff2737f64604f2a 100644 (file)
@@ -538,8 +538,9 @@ Sema::ActOnObjcForCollectionStmt(SourceLocation ForColLoc,
   Stmt *First  = static_cast<Stmt*>(first);
   Expr *Second = static_cast<Expr*>(second);
   Stmt *Body  = static_cast<Stmt*>(body);
-  
+  QualType FirstType;
   if (DeclStmt *DS = dyn_cast_or_null<DeclStmt>(First)) {
+    FirstType = dyn_cast<ValueDecl>(DS->getDecl())->getType();
     // C99 6.8.5p3: The declaration part of a 'for' statement shall only declare
     // identifiers for objects having storage class 'auto' or 'register'.
     for (ScopedDecl *D = DS->getDecl(); D; D = D->getNextDeclarator()) {
@@ -547,19 +548,21 @@ Sema::ActOnObjcForCollectionStmt(SourceLocation ForColLoc,
       if (BVD && !BVD->hasLocalStorage())
         BVD = 0;
       if (BVD == 0)
-        Diag(dyn_cast<ScopedDecl>(D)->getLocation(), 
-             diag::err_non_variable_decl_in_for);
-      // FIXME: mark decl erroneous!
+        return Diag(dyn_cast<ScopedDecl>(D)->getLocation(), 
+                    diag::err_non_variable_decl_in_for);
     }
   }
+  else
+    FirstType = static_cast<Expr*>(first)->getType();
+  if (!isObjcObjectPointerType(FirstType))
+      Diag(ForColLoc, diag::err_selector_element_type,
+           FirstType.getAsString(), First->getSourceRange());
   if (Second) {
     DefaultFunctionArrayConversion(Second);
     QualType SecondType = Second->getType();
-#if 0
-    if (!SecondType->isScalarType()) // C99 6.8.5p2
-      return Diag(ForColLoc, diag::err_typecheck_statement_requires_scalar,
-                  SecondType.getAsString(), Second->getSourceRange());
-#endif
+    if (!isObjcObjectPointerType(SecondType))
+      Diag(ForColLoc, diag::err_collection_expr_type,
+           SecondType.getAsString(), Second->getSourceRange());
   }
   return new ObjcForCollectionStmt(First, Second, Body, ForColLoc);
 }
index 136f6021bb93a0190c2015f3508ae962b795174c..e07245659e7d2156d29f14f0dc7664c44a23e389 100644 (file)
@@ -472,6 +472,10 @@ DIAG(warn_method_not_found, WARNING,
      "method '%0%1' not found (return type defaults to 'id')")
 DIAG(warn_method_not_found_in_protocol, WARNING,
      "method '%0%1' not found in protocol (return type defaults to 'id')")
+DIAG(err_collection_expr_type, ERROR,
+     "collection expression is not of valid object type (its type is '%0')")
+DIAG(err_selector_element_type, ERROR,
+     "selector element is not of valid object type (its type is '%0')")
 
 //===----------------------------------------------------------------------===//
 // Semantic Analysis
diff --git a/test/Parser/objc-forcollection-1.m b/test/Parser/objc-forcollection-1.m
new file mode 100644 (file)
index 0000000..6db74dc
--- /dev/null
@@ -0,0 +1,43 @@
+// RUN: clang -fsyntax-only %s
+
+typedef struct objc_class *Class;
+typedef struct objc_object {
+ Class isa;
+} *id;
+    
+            
+@protocol P @end
+
+@interface MyList
+@end
+    
+@implementation MyList
+- (unsigned int)countByEnumeratingWithState:  (struct __objcFastEnumerationState *)state objects:  (id *)items count:(unsigned int)stackcount
+{
+        return 0;
+}
+@end
+
+@interface MyList (BasicTest)
+- (void)compilerTestAgainst;
+@end
+
+@implementation MyList (BasicTest)
+- (void)compilerTestAgainst {
+       int i;
+        for (id elem in self) 
+           ++i;
+        for (MyList *elem in self) 
+           ++i;
+        for (id<P> se in self) 
+           ++i;
+
+       MyList<P> *p;
+        for (p in self) 
+           ++i;
+
+       for (p in p)
+         ++i;
+}
+@end
+
diff --git a/test/Parser/objc-forcollection-neg.m b/test/Parser/objc-forcollection-neg.m
new file mode 100644 (file)
index 0000000..4137e63
--- /dev/null
@@ -0,0 +1,37 @@
+// RUN: clang -fsyntax-only -verify %s
+
+typedef struct objc_class *Class;
+typedef struct objc_object {
+ Class isa;
+} *id;
+    
+            
+@interface MyList
+@end
+    
+@implementation MyList
+- (unsigned int)countByEnumeratingWithState:  (struct __objcFastEnumerationState *)state objects:  (id *)items count:(unsigned int)stackcount
+{
+        return 0;
+}
+@end
+
+@interface MyList (BasicTest)
+- (void)compilerTestAgainst;
+@end
+
+@implementation MyList (BasicTest)
+- (void)compilerTestAgainst {
+
+        int i=0;
+        for (int * elem in elem) // expected-error {{selector element is not of valid object type (its type is 'int *')}} \
+                                   expected-error {{collection expression is not of valid object type (its type is 'int *')}}
+           ++i;
+        for (i in elem)  // expected-error {{use of undeclared identifier 'elem'}} \
+                           expected-error {{selector element is not of valid object type (its type is 'int')}}
+           ++i;
+        for (id se in i) // expected-error {{collection expression is not of valid object type (its type is 'int')}} 
+           ++i;
+}
+@end
+