diff options
author | Rico Tzschichholz <ricotz@ubuntu.com> | 2022-04-04 09:28:34 +0200 |
---|---|---|
committer | Rico Tzschichholz <ricotz@ubuntu.com> | 2022-04-04 09:28:34 +0200 |
commit | f56bbc7a7faa47565defa5ccf1b4fe940f6ecc77 (patch) | |
tree | ee308f4521730b34c4092c79b03eb3a0097e80ef | |
parent | 53b003b3a12b1ed5e36b7a4428b19eb578ed36e4 (diff) | |
download | vala-f56bbc7a7faa47565defa5ccf1b4fe940f6ecc77.tar.gz |
vala: Improve accessibility check inside member initializer
Fixes https://gitlab.gnome.org/GNOME/vala/issues/1300
-rw-r--r-- | tests/Makefile.am | 4 | ||||
-rw-r--r-- | tests/control-semantic/member-protected.test | 11 | ||||
-rw-r--r-- | tests/objects/member-initializer-private.c-expected | 329 | ||||
-rw-r--r-- | tests/objects/member-initializer-private.vala | 12 | ||||
-rw-r--r-- | tests/objects/member-initializer-protected.c-expected | 316 | ||||
-rw-r--r-- | tests/objects/member-initializer-protected.vala | 12 | ||||
-rw-r--r-- | tests/semantic/member-access-private-invalid.test | 10 | ||||
-rw-r--r-- | vala/valamemberaccess.vala | 1 | ||||
-rw-r--r-- | vala/valamemberinitializer.vala | 47 |
9 files changed, 738 insertions, 4 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am index 7666b7c29..cb07869a2 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -338,6 +338,7 @@ TESTS = \ control-semantic/member-incompatible-type.test \ control-semantic/member-invalid.test \ control-semantic/member-private.test \ + control-semantic/member-protected.test \ control-semantic/member-readonly.test \ control-semantic/printf-too-few.test \ control-semantic/printf-too-many.test \ @@ -527,8 +528,10 @@ TESTS = \ objects/member-initializer-base-properties.vala \ objects/member-initializer-chained.vala \ objects/member-initializer-chained-2.vala \ + objects/member-initializer-private.vala \ objects/member-initializer-property.vala \ objects/member-initializer-property-owned-setter.vala \ + objects/member-initializer-protected.vala \ objects/methods.vala \ objects/paramspec.vala \ objects/plugin-module-init.vala \ @@ -1150,6 +1153,7 @@ TESTS = \ semantic/member-access-capture-valist-parameter.test \ semantic/member-access-capture-valist-variable.test \ semantic/member-access-not-found.test \ + semantic/member-access-private-invalid.test \ semantic/member-access-protected-invalid.test \ semantic/member-access-this-invalid.test \ semantic/member-access-undefined.test \ diff --git a/tests/control-semantic/member-protected.test b/tests/control-semantic/member-protected.test new file mode 100644 index 000000000..dd251c679 --- /dev/null +++ b/tests/control-semantic/member-protected.test @@ -0,0 +1,11 @@ +Invalid Code + +class Foo { + protected string foo { get; set; } +} + +void main () { + var foo = new Foo () { + foo = "foo" + }; +} diff --git a/tests/objects/member-initializer-private.c-expected b/tests/objects/member-initializer-private.c-expected new file mode 100644 index 000000000..9027b52e5 --- /dev/null +++ b/tests/objects/member-initializer-private.c-expected @@ -0,0 +1,329 @@ +/* objects_member_initializer_private.c generated by valac, the Vala compiler + * generated from objects_member_initializer_private.vala, do not modify */ + +#include <glib-object.h> +#include <stdlib.h> +#include <string.h> +#include <glib.h> +#include <gobject/gvaluecollector.h> + +#if !defined(VALA_EXTERN) +#if defined(_MSC_VER) +#define VALA_EXTERN __declspec(dllexport) extern +#elif __GNUC__ >= 4 +#define VALA_EXTERN __attribute__((visibility("default"))) extern +#else +#define VALA_EXTERN extern +#endif +#endif + +#define TYPE_FOO (foo_get_type ()) +#define FOO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_FOO, Foo)) +#define FOO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_FOO, FooClass)) +#define IS_FOO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_FOO)) +#define IS_FOO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_FOO)) +#define FOO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_FOO, FooClass)) + +typedef struct _Foo Foo; +typedef struct _FooClass FooClass; +typedef struct _FooPrivate FooPrivate; +#define _g_free0(var) (var = (g_free (var), NULL)) +#define _foo_unref0(var) ((var == NULL) ? NULL : (var = (foo_unref (var), NULL))) +typedef struct _ParamSpecFoo ParamSpecFoo; + +struct _Foo { + GTypeInstance parent_instance; + volatile int ref_count; + FooPrivate * priv; +}; + +struct _FooClass { + GTypeClass parent_class; + void (*finalize) (Foo *self); +}; + +struct _FooPrivate { + gchar* baz; +}; + +struct _ParamSpecFoo { + GParamSpec parent_instance; +}; + +static gint Foo_private_offset; +static gpointer foo_parent_class = NULL; + +VALA_EXTERN gpointer foo_ref (gpointer instance); +VALA_EXTERN void foo_unref (gpointer instance); +VALA_EXTERN GParamSpec* param_spec_foo (const gchar* name, + const gchar* nick, + const gchar* blurb, + GType object_type, + GParamFlags flags); +VALA_EXTERN void value_set_foo (GValue* value, + gpointer v_object); +VALA_EXTERN void value_take_foo (GValue* value, + gpointer v_object); +VALA_EXTERN gpointer value_get_foo (const GValue* value); +VALA_EXTERN GType foo_get_type (void) G_GNUC_CONST ; +G_DEFINE_AUTOPTR_CLEANUP_FUNC (Foo, foo_unref) +static void foo_bar (Foo* self); +VALA_EXTERN Foo* foo_new (void); +VALA_EXTERN Foo* foo_construct (GType object_type); +static void foo_finalize (Foo * obj); +static GType foo_get_type_once (void); +static void _vala_main (void); + +static inline gpointer +foo_get_instance_private (Foo* self) +{ + return G_STRUCT_MEMBER_P (self, Foo_private_offset); +} + +static void +foo_bar (Foo* self) +{ + Foo* foo = NULL; + const gchar* _tmp0_; + gchar* _tmp1_; + Foo* _tmp2_ = NULL; + g_return_if_fail (IS_FOO (self)); + _tmp0_ = self->priv->baz; + _tmp1_ = g_strdup (_tmp0_); + _tmp2_ = foo_new (); + _g_free0 (_tmp2_->priv->baz); + _tmp2_->priv->baz = _tmp1_; + foo = _tmp2_; + _foo_unref0 (foo); +} + +Foo* +foo_construct (GType object_type) +{ + Foo* self = NULL; + self = (Foo*) g_type_create_instance (object_type); + return self; +} + +Foo* +foo_new (void) +{ + return foo_construct (TYPE_FOO); +} + +static void +value_foo_init (GValue* value) +{ + value->data[0].v_pointer = NULL; +} + +static void +value_foo_free_value (GValue* value) +{ + if (value->data[0].v_pointer) { + foo_unref (value->data[0].v_pointer); + } +} + +static void +value_foo_copy_value (const GValue* src_value, + GValue* dest_value) +{ + if (src_value->data[0].v_pointer) { + dest_value->data[0].v_pointer = foo_ref (src_value->data[0].v_pointer); + } else { + dest_value->data[0].v_pointer = NULL; + } +} + +static gpointer +value_foo_peek_pointer (const GValue* value) +{ + return value->data[0].v_pointer; +} + +static gchar* +value_foo_collect_value (GValue* value, + guint n_collect_values, + GTypeCValue* collect_values, + guint collect_flags) +{ + if (collect_values[0].v_pointer) { + Foo * object; + object = collect_values[0].v_pointer; + if (object->parent_instance.g_class == NULL) { + return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); + } else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) { + return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); + } + value->data[0].v_pointer = foo_ref (object); + } else { + value->data[0].v_pointer = NULL; + } + return NULL; +} + +static gchar* +value_foo_lcopy_value (const GValue* value, + guint n_collect_values, + GTypeCValue* collect_values, + guint collect_flags) +{ + Foo ** object_p; + object_p = collect_values[0].v_pointer; + if (!object_p) { + return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); + } + if (!value->data[0].v_pointer) { + *object_p = NULL; + } else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { + *object_p = value->data[0].v_pointer; + } else { + *object_p = foo_ref (value->data[0].v_pointer); + } + return NULL; +} + +GParamSpec* +param_spec_foo (const gchar* name, + const gchar* nick, + const gchar* blurb, + GType object_type, + GParamFlags flags) +{ + ParamSpecFoo* spec; + g_return_val_if_fail (g_type_is_a (object_type, TYPE_FOO), NULL); + spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags); + G_PARAM_SPEC (spec)->value_type = object_type; + return G_PARAM_SPEC (spec); +} + +gpointer +value_get_foo (const GValue* value) +{ + g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_FOO), NULL); + return value->data[0].v_pointer; +} + +void +value_set_foo (GValue* value, + gpointer v_object) +{ + Foo * old; + g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_FOO)); + old = value->data[0].v_pointer; + if (v_object) { + g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_FOO)); + g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); + value->data[0].v_pointer = v_object; + foo_ref (value->data[0].v_pointer); + } else { + value->data[0].v_pointer = NULL; + } + if (old) { + foo_unref (old); + } +} + +void +value_take_foo (GValue* value, + gpointer v_object) +{ + Foo * old; + g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_FOO)); + old = value->data[0].v_pointer; + if (v_object) { + g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_FOO)); + g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); + value->data[0].v_pointer = v_object; + } else { + value->data[0].v_pointer = NULL; + } + if (old) { + foo_unref (old); + } +} + +static void +foo_class_init (FooClass * klass, + gpointer klass_data) +{ + foo_parent_class = g_type_class_peek_parent (klass); + ((FooClass *) klass)->finalize = foo_finalize; + g_type_class_adjust_private_offset (klass, &Foo_private_offset); +} + +static void +foo_instance_init (Foo * self, + gpointer klass) +{ + self->priv = foo_get_instance_private (self); + self->ref_count = 1; +} + +static void +foo_finalize (Foo * obj) +{ + Foo * self; + self = G_TYPE_CHECK_INSTANCE_CAST (obj, TYPE_FOO, Foo); + g_signal_handlers_destroy (self); + _g_free0 (self->priv->baz); +} + +static GType +foo_get_type_once (void) +{ + static const GTypeValueTable g_define_type_value_table = { value_foo_init, value_foo_free_value, value_foo_copy_value, value_foo_peek_pointer, "p", value_foo_collect_value, "p", value_foo_lcopy_value }; + static const GTypeInfo g_define_type_info = { sizeof (FooClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) foo_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (Foo), 0, (GInstanceInitFunc) foo_instance_init, &g_define_type_value_table }; + static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) }; + GType foo_type_id; + foo_type_id = g_type_register_fundamental (g_type_fundamental_next (), "Foo", &g_define_type_info, &g_define_type_fundamental_info, 0); + Foo_private_offset = g_type_add_instance_private (foo_type_id, sizeof (FooPrivate)); + return foo_type_id; +} + +GType +foo_get_type (void) +{ + static volatile gsize foo_type_id__once = 0; + if (g_once_init_enter (&foo_type_id__once)) { + GType foo_type_id; + foo_type_id = foo_get_type_once (); + g_once_init_leave (&foo_type_id__once, foo_type_id); + } + return foo_type_id__once; +} + +gpointer +foo_ref (gpointer instance) +{ + Foo * self; + self = instance; + g_atomic_int_inc (&self->ref_count); + return instance; +} + +void +foo_unref (gpointer instance) +{ + Foo * self; + self = instance; + if (g_atomic_int_dec_and_test (&self->ref_count)) { + FOO_GET_CLASS (self)->finalize (self); + g_type_free_instance ((GTypeInstance *) self); + } +} + +static void +_vala_main (void) +{ +} + +int +main (int argc, + char ** argv) +{ + _vala_main (); + return 0; +} + diff --git a/tests/objects/member-initializer-private.vala b/tests/objects/member-initializer-private.vala new file mode 100644 index 000000000..2175b6cb5 --- /dev/null +++ b/tests/objects/member-initializer-private.vala @@ -0,0 +1,12 @@ +class Foo { + private string baz; + + void bar () { + var foo = new Foo () { + baz = baz + }; + } +} + +void main () { +} diff --git a/tests/objects/member-initializer-protected.c-expected b/tests/objects/member-initializer-protected.c-expected new file mode 100644 index 000000000..951bb1b0f --- /dev/null +++ b/tests/objects/member-initializer-protected.c-expected @@ -0,0 +1,316 @@ +/* objects_member_initializer_protected.c generated by valac, the Vala compiler + * generated from objects_member_initializer_protected.vala, do not modify */ + +#include <glib-object.h> +#include <stdlib.h> +#include <string.h> +#include <glib.h> +#include <gobject/gvaluecollector.h> + +#if !defined(VALA_EXTERN) +#if defined(_MSC_VER) +#define VALA_EXTERN __declspec(dllexport) extern +#elif __GNUC__ >= 4 +#define VALA_EXTERN __attribute__((visibility("default"))) extern +#else +#define VALA_EXTERN extern +#endif +#endif + +#define TYPE_FOO (foo_get_type ()) +#define FOO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_FOO, Foo)) +#define FOO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_FOO, FooClass)) +#define IS_FOO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_FOO)) +#define IS_FOO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_FOO)) +#define FOO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_FOO, FooClass)) + +typedef struct _Foo Foo; +typedef struct _FooClass FooClass; +typedef struct _FooPrivate FooPrivate; +#define _g_free0(var) (var = (g_free (var), NULL)) +#define _foo_unref0(var) ((var == NULL) ? NULL : (var = (foo_unref (var), NULL))) +typedef struct _ParamSpecFoo ParamSpecFoo; + +struct _Foo { + GTypeInstance parent_instance; + volatile int ref_count; + FooPrivate * priv; + gchar* baz; +}; + +struct _FooClass { + GTypeClass parent_class; + void (*finalize) (Foo *self); +}; + +struct _ParamSpecFoo { + GParamSpec parent_instance; +}; + +static gpointer foo_parent_class = NULL; + +VALA_EXTERN gpointer foo_ref (gpointer instance); +VALA_EXTERN void foo_unref (gpointer instance); +VALA_EXTERN GParamSpec* param_spec_foo (const gchar* name, + const gchar* nick, + const gchar* blurb, + GType object_type, + GParamFlags flags); +VALA_EXTERN void value_set_foo (GValue* value, + gpointer v_object); +VALA_EXTERN void value_take_foo (GValue* value, + gpointer v_object); +VALA_EXTERN gpointer value_get_foo (const GValue* value); +VALA_EXTERN GType foo_get_type (void) G_GNUC_CONST ; +G_DEFINE_AUTOPTR_CLEANUP_FUNC (Foo, foo_unref) +static void foo_bar (Foo* self); +VALA_EXTERN Foo* foo_new (void); +VALA_EXTERN Foo* foo_construct (GType object_type); +static void foo_finalize (Foo * obj); +static GType foo_get_type_once (void); +static void _vala_main (void); + +static void +foo_bar (Foo* self) +{ + Foo* foo = NULL; + const gchar* _tmp0_; + gchar* _tmp1_; + Foo* _tmp2_ = NULL; + g_return_if_fail (IS_FOO (self)); + _tmp0_ = self->baz; + _tmp1_ = g_strdup (_tmp0_); + _tmp2_ = foo_new (); + _g_free0 (_tmp2_->baz); + _tmp2_->baz = _tmp1_; + foo = _tmp2_; + _foo_unref0 (foo); +} + +Foo* +foo_construct (GType object_type) +{ + Foo* self = NULL; + self = (Foo*) g_type_create_instance (object_type); + return self; +} + +Foo* +foo_new (void) +{ + return foo_construct (TYPE_FOO); +} + +static void +value_foo_init (GValue* value) +{ + value->data[0].v_pointer = NULL; +} + +static void +value_foo_free_value (GValue* value) +{ + if (value->data[0].v_pointer) { + foo_unref (value->data[0].v_pointer); + } +} + +static void +value_foo_copy_value (const GValue* src_value, + GValue* dest_value) +{ + if (src_value->data[0].v_pointer) { + dest_value->data[0].v_pointer = foo_ref (src_value->data[0].v_pointer); + } else { + dest_value->data[0].v_pointer = NULL; + } +} + +static gpointer +value_foo_peek_pointer (const GValue* value) +{ + return value->data[0].v_pointer; +} + +static gchar* +value_foo_collect_value (GValue* value, + guint n_collect_values, + GTypeCValue* collect_values, + guint collect_flags) +{ + if (collect_values[0].v_pointer) { + Foo * object; + object = collect_values[0].v_pointer; + if (object->parent_instance.g_class == NULL) { + return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); + } else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) { + return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); + } + value->data[0].v_pointer = foo_ref (object); + } else { + value->data[0].v_pointer = NULL; + } + return NULL; +} + +static gchar* +value_foo_lcopy_value (const GValue* value, + guint n_collect_values, + GTypeCValue* collect_values, + guint collect_flags) +{ + Foo ** object_p; + object_p = collect_values[0].v_pointer; + if (!object_p) { + return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); + } + if (!value->data[0].v_pointer) { + *object_p = NULL; + } else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { + *object_p = value->data[0].v_pointer; + } else { + *object_p = foo_ref (value->data[0].v_pointer); + } + return NULL; +} + +GParamSpec* +param_spec_foo (const gchar* name, + const gchar* nick, + const gchar* blurb, + GType object_type, + GParamFlags flags) +{ + ParamSpecFoo* spec; + g_return_val_if_fail (g_type_is_a (object_type, TYPE_FOO), NULL); + spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags); + G_PARAM_SPEC (spec)->value_type = object_type; + return G_PARAM_SPEC (spec); +} + +gpointer +value_get_foo (const GValue* value) +{ + g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_FOO), NULL); + return value->data[0].v_pointer; +} + +void +value_set_foo (GValue* value, + gpointer v_object) +{ + Foo * old; + g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_FOO)); + old = value->data[0].v_pointer; + if (v_object) { + g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_FOO)); + g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); + value->data[0].v_pointer = v_object; + foo_ref (value->data[0].v_pointer); + } else { + value->data[0].v_pointer = NULL; + } + if (old) { + foo_unref (old); + } +} + +void +value_take_foo (GValue* value, + gpointer v_object) +{ + Foo * old; + g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_FOO)); + old = value->data[0].v_pointer; + if (v_object) { + g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_FOO)); + g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); + value->data[0].v_pointer = v_object; + } else { + value->data[0].v_pointer = NULL; + } + if (old) { + foo_unref (old); + } +} + +static void +foo_class_init (FooClass * klass, + gpointer klass_data) +{ + foo_parent_class = g_type_class_peek_parent (klass); + ((FooClass *) klass)->finalize = foo_finalize; +} + +static void +foo_instance_init (Foo * self, + gpointer klass) +{ + self->ref_count = 1; +} + +static void +foo_finalize (Foo * obj) +{ + Foo * self; + self = G_TYPE_CHECK_INSTANCE_CAST (obj, TYPE_FOO, Foo); + g_signal_handlers_destroy (self); + _g_free0 (self->baz); +} + +static GType +foo_get_type_once (void) +{ + static const GTypeValueTable g_define_type_value_table = { value_foo_init, value_foo_free_value, value_foo_copy_value, value_foo_peek_pointer, "p", value_foo_collect_value, "p", value_foo_lcopy_value }; + static const GTypeInfo g_define_type_info = { sizeof (FooClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) foo_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (Foo), 0, (GInstanceInitFunc) foo_instance_init, &g_define_type_value_table }; + static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) }; + GType foo_type_id; + foo_type_id = g_type_register_fundamental (g_type_fundamental_next (), "Foo", &g_define_type_info, &g_define_type_fundamental_info, 0); + return foo_type_id; +} + +GType +foo_get_type (void) +{ + static volatile gsize foo_type_id__once = 0; + if (g_once_init_enter (&foo_type_id__once)) { + GType foo_type_id; + foo_type_id = foo_get_type_once (); + g_once_init_leave (&foo_type_id__once, foo_type_id); + } + return foo_type_id__once; +} + +gpointer +foo_ref (gpointer instance) +{ + Foo * self; + self = instance; + g_atomic_int_inc (&self->ref_count); + return instance; +} + +void +foo_unref (gpointer instance) +{ + Foo * self; + self = instance; + if (g_atomic_int_dec_and_test (&self->ref_count)) { + FOO_GET_CLASS (self)->finalize (self); + g_type_free_instance ((GTypeInstance *) self); + } +} + +static void +_vala_main (void) +{ +} + +int +main (int argc, + char ** argv) +{ + _vala_main (); + return 0; +} + diff --git a/tests/objects/member-initializer-protected.vala b/tests/objects/member-initializer-protected.vala new file mode 100644 index 000000000..42af13e21 --- /dev/null +++ b/tests/objects/member-initializer-protected.vala @@ -0,0 +1,12 @@ +class Foo { + protected string baz; + + void bar () { + var foo = new Foo () { + baz = baz + }; + } +} + +void main () { +} diff --git a/tests/semantic/member-access-private-invalid.test b/tests/semantic/member-access-private-invalid.test new file mode 100644 index 000000000..8bb0df8a5 --- /dev/null +++ b/tests/semantic/member-access-private-invalid.test @@ -0,0 +1,10 @@ +Invalid Code + +class Foo { + private int i; +} + +void main () { + var foo = new Foo (); + foo.i = 42; +} diff --git a/vala/valamemberaccess.vala b/vala/valamemberaccess.vala index f58f39c8d..3b91ece73 100644 --- a/vala/valamemberaccess.vala +++ b/vala/valamemberaccess.vala @@ -919,6 +919,7 @@ public class Vala.MemberAccess : Expression { } member.version.check (context, source_reference); + // FIXME Code duplication with MemberInitializer.check() if (access == SymbolAccessibility.PROTECTED && member.parent_symbol is TypeSymbol) { unowned TypeSymbol target_type = (TypeSymbol) member.parent_symbol; diff --git a/vala/valamemberinitializer.vala b/vala/valamemberinitializer.vala index 3f693120e..6fcfe312c 100644 --- a/vala/valamemberinitializer.vala +++ b/vala/valamemberinitializer.vala @@ -89,11 +89,50 @@ public class Vala.MemberInitializer : Expression { Report.error (source_reference, "Invalid member `%s' in `%s'", name, type.type_symbol.get_full_name ()); return false; } - if (symbol_reference.access != SymbolAccessibility.PUBLIC) { - error = true; - Report.error (source_reference, "Access to private member `%s' denied", symbol_reference.get_full_name ()); - return false; + + // FIXME Code duplication with MemberAccess.check() + if (symbol_reference.access == SymbolAccessibility.PROTECTED && symbol_reference.parent_symbol is TypeSymbol) { + unowned TypeSymbol target_type = (TypeSymbol) symbol_reference.parent_symbol; + + bool in_subtype = false; + for (Symbol this_symbol = context.analyzer.current_symbol; this_symbol != null; this_symbol = this_symbol.parent_symbol) { + if (this_symbol == target_type) { + // required for interfaces with non-abstract methods + // accessing protected interface members + in_subtype = true; + break; + } + + unowned Class? cl = this_symbol as Class; + if (cl != null && cl.is_subtype_of (target_type)) { + in_subtype = true; + break; + } + } + + if (!in_subtype) { + error = true; + Report.error (source_reference, "Access to protected member `%s' denied", symbol_reference.get_full_name ()); + return false; + } + } else if (symbol_reference.access == SymbolAccessibility.PRIVATE) { + unowned Symbol? target_type = symbol_reference.parent_symbol; + + bool in_target_type = false; + for (Symbol this_symbol = context.analyzer.current_symbol; this_symbol != null; this_symbol = this_symbol.parent_symbol) { + if (target_type == this_symbol) { + in_target_type = true; + break; + } + } + + if (!in_target_type) { + error = true; + Report.error (source_reference, "Access to private member `%s' denied", symbol_reference.get_full_name ()); + return false; + } } + DataType member_type = null; if (symbol_reference is Field) { unowned Field f = (Field) symbol_reference; |