OSDN Git Service

In gcc/objc/:
authornicola <nicola@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 27 Nov 2010 10:06:59 +0000 (10:06 +0000)
committernicola <nicola@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 27 Nov 2010 10:06:59 +0000 (10:06 +0000)
2010-11-27  Nicola Pero  <nicola.pero@meta-innovation.com>

        Implemented optional properties.
        * objc-act.h (PROPERTY_OPTIONAL): New.
        * objc-act.c (objc_add_property_declaration): Set
        PROPERTY_OPTIONAL if appropriate.
        (finish_class): When generating definitions of setter and getter
        methods associated with a property for a protocol, mark them as
        optional if the property is optional.
        (maybe_make_artificial_property_decl): Added 'getter_name'
        argument.  Set PROPERTY_OPTIONAL.
        (objc_maybe_build_component_ref): Updated calls to
        maybe_make_artificial_property_decl.  Added code for optional,
        readonly properties.
        (objc_build_class_component_ref): Updated call to
        maybe_make_artificial_property_decl.

In gcc/testsuite/:
2010-11-27  Nicola Pero  <nicola.pero@meta-innovation.com>

        * objc.dg/property/at-property-24.m: New.
        * objc.dg/property/at-property-25.m: New.
        * obj-c++.dg/property/at-property-24.mm: New.
        * obj-c++.dg/property/at-property-25.mm: New.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@167197 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/objc/ChangeLog
gcc/objc/objc-act.c
gcc/objc/objc-act.h
gcc/testsuite/ChangeLog
gcc/testsuite/obj-c++.dg/property/at-property-24.mm [new file with mode: 0644]
gcc/testsuite/obj-c++.dg/property/at-property-25.mm [new file with mode: 0644]
gcc/testsuite/objc.dg/property/at-property-24.m [new file with mode: 0644]
gcc/testsuite/objc.dg/property/at-property-25.m [new file with mode: 0644]

index 7c890ce..1ebff02 100644 (file)
@@ -1,5 +1,22 @@
 2010-11-27  Nicola Pero  <nicola.pero@meta-innovation.com>
 
+       Implemented optional properties.
+       * objc-act.h (PROPERTY_OPTIONAL): New.
+       * objc-act.c (objc_add_property_declaration): Set
+       PROPERTY_OPTIONAL if appropriate.
+       (finish_class): When generating definitions of setter and getter
+       methods associated with a property for a protocol, mark them as
+       optional if the property is optional.
+       (maybe_make_artificial_property_decl): Added 'getter_name'
+       argument.  Set PROPERTY_OPTIONAL.
+       (objc_maybe_build_component_ref): Updated calls to
+       maybe_make_artificial_property_decl.  Added code for optional,
+       readonly properties.
+       (objc_build_class_component_ref): Updated call to
+       maybe_make_artificial_property_decl.
+       
+2010-11-27  Nicola Pero  <nicola.pero@meta-innovation.com>
+
        * objc-act.c (objc_build_struct): Fixed loops that save and
        restore TYPE_OBJC_INFO to iterate over all variants of the type; a
        special case for the current type is then no longer required.
index 232708f..70056d3 100644 (file)
@@ -1181,7 +1181,7 @@ objc_add_property_declaration (location_t location, tree decl,
       /* An existing property was found; check that it has the same
         types, or it is compatible.  */
       location_t original_location = DECL_SOURCE_LOCATION (x);
-         
+
       if (PROPERTY_NONATOMIC (x) != parsed_property_nonatomic)
        {
          warning_at (location, 0,
@@ -1293,6 +1293,13 @@ objc_add_property_declaration (location_t location, tree decl,
   PROPERTY_IVAR_NAME (property_decl) = NULL_TREE;
   PROPERTY_DYNAMIC (property_decl) = 0;
 
+  /* Remember the fact that the property was found in the @optional
+     section in a @protocol, or not.  */
+  if (objc_method_optional_flag)
+    PROPERTY_OPTIONAL (property_decl) = 1;
+  else
+    PROPERTY_OPTIONAL (property_decl) = 0;
+
   /* Note that PROPERTY_GETTER_NAME is always set for all
      PROPERTY_DECLs, and PROPERTY_SETTER_NAME is always set for all
      PROPERTY_DECLs where PROPERTY_READONLY == 0.  Any time we deal
@@ -1310,18 +1317,22 @@ objc_add_property_declaration (location_t location, tree decl,
    in the implementation, and failing that, the protocol list)
    provided for a 'setter' or 'getter' for 'component' with default
    names (ie, if 'component' is "name", then search for "name" and
-   "setName:").  If any is found, then create an artificial property
-   that uses them.  Return NULL_TREE if 'getter' or 'setter' could not
-   be found.  */
+   "setName:").  It is also possible to specify a different
+   'getter_name' (this is used for @optional readonly properties).  If
+   any is found, then create an artificial property that uses them.
+   Return NULL_TREE if 'getter' or 'setter' could not be found.  */
 static tree
 maybe_make_artificial_property_decl (tree interface, tree implementation, 
-                                    tree protocol_list, tree component, bool is_class)
+                                    tree protocol_list, tree component, bool is_class,
+                                    tree getter_name)
 {
-  tree getter_name = component;
   tree setter_name = get_identifier (objc_build_property_setter_name (component));
   tree getter = NULL_TREE;
   tree setter = NULL_TREE;
 
+  if (getter_name == NULL_TREE)
+    getter_name = component;
+
   /* First, check the @interface and all superclasses.  */
   if (interface)
     {
@@ -1401,6 +1412,7 @@ maybe_make_artificial_property_decl (tree interface, tree implementation,
       PROPERTY_ASSIGN_SEMANTICS (property_decl) = 0;
       PROPERTY_IVAR_NAME (property_decl) = NULL_TREE;
       PROPERTY_DYNAMIC (property_decl) = 0;
+      PROPERTY_OPTIONAL (property_decl) = 0;
 
       if (!getter)
        PROPERTY_HAS_NO_GETTER (property_decl) = 1;
@@ -1481,7 +1493,7 @@ objc_maybe_build_component_ref (tree object, tree property_ident)
                 properties.  */
              if (!IS_CLASS (rtype))
                x = lookup_property_in_protocol_list (rprotos, property_ident);
-             
+
              if (x == NULL_TREE)
                {
                  /* Ok, no property.  Maybe it was an
@@ -1493,7 +1505,25 @@ objc_maybe_build_component_ref (tree object, tree property_ident)
                                                           NULL_TREE,
                                                           rprotos, 
                                                           property_ident,
-                                                          IS_CLASS (rtype));
+                                                          IS_CLASS (rtype),
+                                                          NULL_TREE);
+               }
+             else if (PROPERTY_OPTIONAL (x) && PROPERTY_READONLY (x))
+               {
+                 /* This is a special, complicated case.  If the
+                    property is optional, and is read-only, then the
+                    property is always used for reading, but an
+                    eventual existing non-property setter can be used
+                    for writing.  We create an artificial property
+                    decl copying the getter from the optional
+                    property, and looking up the setter in the
+                    interface.  */
+                 x = maybe_make_artificial_property_decl (NULL_TREE,
+                                                          NULL_TREE,
+                                                          rprotos,
+                                                          property_ident,
+                                                          false,
+                                                          PROPERTY_GETTER_NAME (x));             
                }
            }
        }
@@ -1538,7 +1568,22 @@ objc_maybe_build_component_ref (tree object, tree property_ident)
                  x = maybe_make_artificial_property_decl 
                    (interface_type, implementation, NULL_TREE,
                     property_ident,
-                    (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL));
+                    (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL),
+                    NULL_TREE);
+               }
+             else if (PROPERTY_OPTIONAL (x) && PROPERTY_READONLY (x))
+               {
+                 tree implementation = NULL_TREE;
+                 
+                 if (t == self_decl)
+                   implementation = objc_implementation_context;
+                 
+                 x = maybe_make_artificial_property_decl (interface_type,
+                                                          implementation,
+                                                          NULL_TREE,
+                                                          property_ident,
+                                                          false,
+                                                          PROPERTY_GETTER_NAME (x));             
                }
            }
        }
@@ -1603,8 +1648,25 @@ objc_maybe_build_component_ref (tree object, tree property_ident)
                                                           implementation,
                                                           protocol_list, 
                                                           property_ident,
-                                                          IS_CLASS (rtype));
+                                                          IS_CLASS (rtype),
+                                                          NULL_TREE);
                }
+             else if (PROPERTY_OPTIONAL (x) && PROPERTY_READONLY (x))
+               {
+                 tree implementation = NULL_TREE;
+
+                 if (objc_implementation_context
+                     && CLASS_NAME (objc_implementation_context) 
+                     == OBJC_TYPE_NAME (interface_type))
+                   implementation = objc_implementation_context;
+                 
+                 x = maybe_make_artificial_property_decl (interface_type,
+                                                          implementation,
+                                                          protocol_list,
+                                                          property_ident,
+                                                          false,
+                                                          PROPERTY_GETTER_NAME (x));             
+               }             
            }
        }
     }
@@ -1703,7 +1765,7 @@ objc_build_class_component_ref (tree class_name, tree property_ident)
 
   x = maybe_make_artificial_property_decl (rtype, NULL_TREE, NULL_TREE,
                                           property_ident,
-                                          true);
+                                          true, NULL_TREE);
   
   if (x)
     {
@@ -10534,7 +10596,10 @@ finish_class (tree klass)
                getter_decl = build_method_decl (INSTANCE_METHOD_DECL, 
                                                 rettype, PROPERTY_GETTER_NAME (x), 
                                                 NULL_TREE, false);
-               objc_add_method (objc_interface_context, getter_decl, false, false);
+               if (PROPERTY_OPTIONAL (x))
+                 objc_add_method (objc_interface_context, getter_decl, false, true);
+               else
+                 objc_add_method (objc_interface_context, getter_decl, false, false);
                METHOD_PROPERTY_CONTEXT (getter_decl) = x;
              }
 
@@ -10574,7 +10639,10 @@ finish_class (tree klass)
                                                     ret_type, selector,
                                                     build_tree_list (NULL_TREE, NULL_TREE),
                                                     false);
-                   objc_add_method (objc_interface_context, setter_decl, false, false);
+                   if (PROPERTY_OPTIONAL (x))
+                     objc_add_method (objc_interface_context, setter_decl, false, true);
+                   else
+                     objc_add_method (objc_interface_context, setter_decl, false, false);
                    METHOD_PROPERTY_CONTEXT (setter_decl) = x;
                  }            
              }
index f612e74..6403161 100644 (file)
@@ -113,6 +113,11 @@ typedef enum objc_property_assign_semantics {
    setter, it is set to 1.  */
 #define PROPERTY_HAS_NO_SETTER(DECL) DECL_LANG_FLAG_4 (DECL)
 
+/* PROPERTY_OPTIONAL can be 0 or 1.  Normally it is 0, but if this is
+   a property declared as @optional in a @protocol, then it is set to
+   1.  */
+#define PROPERTY_OPTIONAL(DECL) DECL_LANG_FLAG_5 (DECL)
+
 /* PROPERTY_REF.  A PROPERTY_REF represents an 'object.property'
    expression.  It is normally used for property access, but when
    the Objective-C 2.0 "dot-syntax" (object.component) is used
index d0b568a..7b6f130 100644 (file)
@@ -1,5 +1,12 @@
 2010-11-27  Nicola Pero  <nicola.pero@meta-innovation.com>
 
+       * objc.dg/property/at-property-24.m: New.
+       * objc.dg/property/at-property-25.m: New.       
+       * obj-c++.dg/property/at-property-24.mm: New.
+       * obj-c++.dg/property/at-property-25.mm: New.
+
+2010-11-27  Nicola Pero  <nicola.pero@meta-innovation.com>
+
        * objc.dg/protocol-qualifier-1.m: New.  
        * objc.dg/protocol-qualifier-2.m: New.
        * obj-c++.dg/protocol-qualifier-1.mm: New.      
diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-24.mm b/gcc/testsuite/obj-c++.dg/property/at-property-24.mm
new file mode 100644 (file)
index 0000000..b4a7699
--- /dev/null
@@ -0,0 +1,118 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010.  */
+/* { dg-do run } */
+/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
+
+/* Test @optional @properties.  */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+  Class isa;
+}
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+@end
+
+/* Use a different getters/setters, so that the only way to compile
+   object.countX is to find the actual @property.  */
+@protocol count
+@required
+/* @required + @synthesize.  */
+@property (getter=number1, setter=setNumber1:) int count1;
+/* @required + manual setters/getters.  */
+@property (getter=number2, setter=setNumber2:) int count2;
+
+@optional
+/* @optional + @synthesize.  */
+@property (getter=number3, setter=setNumber3:) int count3;
+/* @optional + manual setters/getters.  */
+@property (getter=number4, setter=setNumber4:) int count4;
+
+@optional
+/* @optional + readonly, with a setter added in the class itself.  */
+@property (readonly, getter=number5) int count5;
+@end
+
+@interface MySubClass : MyRootClass <count>
+{
+  int count1;
+  int count2;
+  int count3;
+  int count4;
+  int count5;
+}
+- (void) setCount5: (int)value;
+@end
+
+@implementation MySubClass
+@synthesize count1;
+- (int) number2
+{
+  return count2;
+}
+- (void) setNumber2: (int)value
+{
+  count2 = value;
+}
+@synthesize count3;
+- (int) number4
+{
+  return count4;
+}
+- (void) setNumber4: (int)value
+{
+  count4 = value;
+}
+- (int) number5
+{
+  return count5;
+}
+- (void) setCount5: (int)value
+{
+  count5 = value;
+}
+@end
+
+int main (void)
+{
+  MySubClass *object = [[MySubClass alloc] init];
+
+  /* First, test that @required and @optional properties work as
+     expected if implemented either via @synthesize or manually.  */
+  object.count1 = 44;
+  if (object.count1 != 44)
+    abort ();
+
+  object.count2 = 88;
+  if (object.count2 != 88)
+    abort ();
+
+  object.count3 = 77;
+  if (object.count3 != 77)
+    abort ();
+
+  object.count4 = 11;
+  if (object.count4 != 11)
+    abort ();
+
+  /* Now, test the complication: @optional @property which is
+     readonly, but which has a setter manually implemented.
+     Apparently it is possible to use the dotsyntax and the @optional
+     @property getter is used when reading, while the manual setter is
+     used when writing.  */
+  object.count5 = 99;
+  if (object.count5 != 99)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-25.mm b/gcc/testsuite/obj-c++.dg/property/at-property-25.mm
new file mode 100644 (file)
index 0000000..422a29e
--- /dev/null
@@ -0,0 +1,87 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010.  */
+/* { dg-do compile } */
+
+/* Test warnings and non-warnings with @optional @properties.  */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+  Class isa;
+}
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+@end
+
+@protocol count
+@optional
+@property int count1;
+@property (readonly) int count2;
+@end
+
+
+/* A class that implements all the properties.  */
+@interface MySubClass1 : MyRootClass <count>
+{
+  int count1;
+  int count2;
+}
+@end
+
+@implementation MySubClass1
+@synthesize count1;
+@synthesize count2;
+@end
+
+
+/* A class that implements nothing; no warnings as the properties are
+   all optional.  */
+@interface MySubClass2 : MyRootClass <count>
+@end
+
+@implementation MySubClass2
+@end
+
+
+@protocol count2
+@required
+@property int count1;
+@property (readonly) int count2;
+@end
+
+/* A class that implements all the properties.  */
+@interface MySubClass3 : MyRootClass <count2>
+{
+  int count1;
+  int count2;
+}
+@end
+
+@implementation MySubClass3
+@synthesize count1;
+@synthesize count2;
+@end
+
+
+/* A class that implements nothing; warnings as the properties are
+   all required.  */
+@interface MySubClass4 : MyRootClass <count2>
+@end
+
+@implementation MySubClass4
+@end
+
+/* { dg-warning "incomplete implementation of class" "" { target *-*-* } 81 } */
+/* { dg-warning "method definition for ..setCount1:. not found" "" { target *-*-* } 81 } */
+/* { dg-warning "method definition for ..count1. not found" "" { target *-*-* } 81 } */
+/* { dg-warning "method definition for ..count2. not found" "" { target *-*-* } 81 } */
+/* { dg-warning "class .MySubClass4. does not fully implement the .count2. protocol" "" { target *-*-* } 81 } */
diff --git a/gcc/testsuite/objc.dg/property/at-property-24.m b/gcc/testsuite/objc.dg/property/at-property-24.m
new file mode 100644 (file)
index 0000000..b4a7699
--- /dev/null
@@ -0,0 +1,118 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010.  */
+/* { dg-do run } */
+/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
+
+/* Test @optional @properties.  */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+  Class isa;
+}
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+@end
+
+/* Use a different getters/setters, so that the only way to compile
+   object.countX is to find the actual @property.  */
+@protocol count
+@required
+/* @required + @synthesize.  */
+@property (getter=number1, setter=setNumber1:) int count1;
+/* @required + manual setters/getters.  */
+@property (getter=number2, setter=setNumber2:) int count2;
+
+@optional
+/* @optional + @synthesize.  */
+@property (getter=number3, setter=setNumber3:) int count3;
+/* @optional + manual setters/getters.  */
+@property (getter=number4, setter=setNumber4:) int count4;
+
+@optional
+/* @optional + readonly, with a setter added in the class itself.  */
+@property (readonly, getter=number5) int count5;
+@end
+
+@interface MySubClass : MyRootClass <count>
+{
+  int count1;
+  int count2;
+  int count3;
+  int count4;
+  int count5;
+}
+- (void) setCount5: (int)value;
+@end
+
+@implementation MySubClass
+@synthesize count1;
+- (int) number2
+{
+  return count2;
+}
+- (void) setNumber2: (int)value
+{
+  count2 = value;
+}
+@synthesize count3;
+- (int) number4
+{
+  return count4;
+}
+- (void) setNumber4: (int)value
+{
+  count4 = value;
+}
+- (int) number5
+{
+  return count5;
+}
+- (void) setCount5: (int)value
+{
+  count5 = value;
+}
+@end
+
+int main (void)
+{
+  MySubClass *object = [[MySubClass alloc] init];
+
+  /* First, test that @required and @optional properties work as
+     expected if implemented either via @synthesize or manually.  */
+  object.count1 = 44;
+  if (object.count1 != 44)
+    abort ();
+
+  object.count2 = 88;
+  if (object.count2 != 88)
+    abort ();
+
+  object.count3 = 77;
+  if (object.count3 != 77)
+    abort ();
+
+  object.count4 = 11;
+  if (object.count4 != 11)
+    abort ();
+
+  /* Now, test the complication: @optional @property which is
+     readonly, but which has a setter manually implemented.
+     Apparently it is possible to use the dotsyntax and the @optional
+     @property getter is used when reading, while the manual setter is
+     used when writing.  */
+  object.count5 = 99;
+  if (object.count5 != 99)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/objc.dg/property/at-property-25.m b/gcc/testsuite/objc.dg/property/at-property-25.m
new file mode 100644 (file)
index 0000000..422a29e
--- /dev/null
@@ -0,0 +1,87 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010.  */
+/* { dg-do compile } */
+
+/* Test warnings and non-warnings with @optional @properties.  */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+  Class isa;
+}
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+@end
+
+@protocol count
+@optional
+@property int count1;
+@property (readonly) int count2;
+@end
+
+
+/* A class that implements all the properties.  */
+@interface MySubClass1 : MyRootClass <count>
+{
+  int count1;
+  int count2;
+}
+@end
+
+@implementation MySubClass1
+@synthesize count1;
+@synthesize count2;
+@end
+
+
+/* A class that implements nothing; no warnings as the properties are
+   all optional.  */
+@interface MySubClass2 : MyRootClass <count>
+@end
+
+@implementation MySubClass2
+@end
+
+
+@protocol count2
+@required
+@property int count1;
+@property (readonly) int count2;
+@end
+
+/* A class that implements all the properties.  */
+@interface MySubClass3 : MyRootClass <count2>
+{
+  int count1;
+  int count2;
+}
+@end
+
+@implementation MySubClass3
+@synthesize count1;
+@synthesize count2;
+@end
+
+
+/* A class that implements nothing; warnings as the properties are
+   all required.  */
+@interface MySubClass4 : MyRootClass <count2>
+@end
+
+@implementation MySubClass4
+@end
+
+/* { dg-warning "incomplete implementation of class" "" { target *-*-* } 81 } */
+/* { dg-warning "method definition for ..setCount1:. not found" "" { target *-*-* } 81 } */
+/* { dg-warning "method definition for ..count1. not found" "" { target *-*-* } 81 } */
+/* { dg-warning "method definition for ..count2. not found" "" { target *-*-* } 81 } */
+/* { dg-warning "class .MySubClass4. does not fully implement the .count2. protocol" "" { target *-*-* } 81 } */