From ae4c44466742d74a4a3f951757a23c88f9699464 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Wed, 7 May 2014 23:35:17 +0100 Subject: clang-plugin: Add a g_signal_connect() checker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This validates that: • The named signal exists on the given GObject subclass. • The type of the callback function matches that declared for the signal. Unit tests are included. --- tests/Makefile.am | 3 + tests/gsignal-connect.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++++ tests/gsignal.head.c | 82 +++++++++++++++++++++++ tests/gsignal.tail.c | 4 ++ 4 files changed, 263 insertions(+) create mode 100644 tests/gsignal-connect.c create mode 100644 tests/gsignal.head.c create mode 100644 tests/gsignal.tail.c (limited to 'tests') diff --git a/tests/Makefile.am b/tests/Makefile.am index 26d1c02..3fc9e91 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -8,6 +8,7 @@ C_LOG_COMPILER = $(top_srcdir)/tests/wrapper-compiler-errors c_tests = \ assertion-extraction.c \ assertion-extraction-return.c \ + gsignal-connect.c \ gvariant-builder.c \ gvariant-get.c \ gvariant-get-child.c \ @@ -24,6 +25,8 @@ templates = \ assertion-return.tail.c \ generic.head.c \ generic.tail.c \ + gsignal.head.c \ + gsignal.tail.c \ gvariant.head.c \ gvariant.tail.c \ $(NULL) diff --git a/tests/gsignal-connect.c b/tests/gsignal-connect.c new file mode 100644 index 0000000..7f529bf --- /dev/null +++ b/tests/gsignal-connect.c @@ -0,0 +1,174 @@ +/* Template: gsignal */ + +/* + * No error + */ +{ + GObject *some_object = g_malloc (5); // only checking the type + g_signal_connect (some_object, "notify", (GCallback) object_notify_cb, + NULL); +} + +/* + * No error + */ +{ + GObject *some_object = g_malloc (5); // only checking the type + + // Detailed signal + // FIXME: Check the detail is a valid property name too? + g_signal_connect (some_object, "notify::something", + (GCallback) object_notify_cb, NULL); +} + +/* + * No error + */ +{ + GObject *some_object = g_malloc (5); // only checking the type + g_signal_connect (some_object, "notify", + (GCallback) object_notify_proto_cb, + NULL); +} + +/* + * Could not check type of handler for signal ‘GObject::notify’. Callback function declaration does not contain parameter types. + * (GCallback) object_notify_no_proto_cb, + * ^ + * note: expanded from macro 'g_signal_connect' + * g_signal_connect_data ((instance), (detailed_signal), (c_handler), (data), NULL, (GConnectFlags) 0) + * ^ + */ +{ + GObject *some_object = g_malloc (5); // only checking the type + g_signal_connect (some_object, "notify", + (GCallback) object_notify_no_proto_cb, + NULL); +} + +/* + * Incorrect return type from signal handler for signal ‘GObject::notify’. Expected ‘void’ but saw ‘gboolean’. + * (GCallback) object_notify_invalid_return_cb, NULL); + * ^ + * note: expanded from macro 'g_signal_connect' + * g_signal_connect_data ((instance), (detailed_signal), (c_handler), (data), NULL, (GConnectFlags) 0) + * ^ + */ +{ + GObject *some_object = g_malloc (5); // only checking the type + g_signal_connect (some_object, "notify", + (GCallback) object_notify_invalid_return_cb, NULL); +} + +/* + * Incorrect type for argument 1 in signal handler for signal ‘GObject::notify’. Expected ‘GObject *’ but saw ‘GIOStream *’. + * (GCallback) object_notify_invalid_parameter_subclass_cb, + * ^ + * note: expanded from macro 'g_signal_connect' + * g_signal_connect_data ((instance), (detailed_signal), (c_handler), (data), NULL, (GConnectFlags) 0) + * ^ + */ +{ + GObject *some_object = g_malloc (5); // only checking the type + g_signal_connect (some_object, "notify", + (GCallback) object_notify_invalid_parameter_subclass_cb, + NULL); +} + +/* + * Incorrect type for argument 1 in signal handler for signal ‘GObject::notify’. Expected ‘GObject *’ but saw ‘const GObject *’. + * (GCallback) object_notify_invalid_parameter_const_cb, + * ^ + * note: expanded from macro 'g_signal_connect' + * g_signal_connect_data ((instance), (detailed_signal), (c_handler), (data), NULL, (GConnectFlags) 0) + * ^ + */ +{ + GObject *some_object = g_malloc (5); // only checking the type + g_signal_connect (some_object, "notify", + (GCallback) object_notify_invalid_parameter_const_cb, + NULL); +} + +/* + * Incorrect type for argument 2 in signal handler for signal ‘GObject::notify’. Expected ‘GParamSpec *’ but saw ‘void *’. + * (GCallback) object_notify_invalid_parameter_middle_cb, + * ^ + * note: expanded from macro 'g_signal_connect' + * g_signal_connect_data ((instance), (detailed_signal), (c_handler), (data), NULL, (GConnectFlags) 0) + * ^ + */ +{ + GObject *some_object = g_malloc (5); // only checking the type + g_signal_connect (some_object, "notify", + (GCallback) object_notify_invalid_parameter_middle_cb, + NULL); +} + +/* + * Incorrect type for argument 3 in signal handler for signal ‘GObject::notify’. Expected ‘void *’ but saw ‘guint’. + * (GCallback) object_notify_invalid_parameter_user_data_cb, + * ^ + * note: expanded from macro 'g_signal_connect' + * g_signal_connect_data ((instance), (detailed_signal), (c_handler), (data), NULL, (GConnectFlags) 0) + * ^ + */ +{ + GObject *some_object = g_malloc (5); // only checking the type + g_signal_connect (some_object, "notify", + (GCallback) object_notify_invalid_parameter_user_data_cb, + NULL); +} + +/* + * No error + */ +{ + // Non-void* pointer types for user_data are allowed. + GObject *some_object = g_malloc (5); // only checking the type + g_signal_connect (some_object, "notify", + (GCallback) object_notify_invalid_parameter_user_data_ptr_cb, + NULL); +} + +/* + * Incorrect number of arguments in signal handler for signal ‘GObject::notify’. Expected 3 but saw 2. + * (GCallback) object_notify_missing_parameter_cb, NULL); + * ^ + * note: expanded from macro 'g_signal_connect' + * g_signal_connect_data ((instance), (detailed_signal), (c_handler), (data), NULL, (GConnectFlags) 0) + * ^ + */ +{ + GObject *some_object = g_malloc (5); // only checking the type + g_signal_connect (some_object, "notify", + (GCallback) object_notify_missing_parameter_cb, NULL); +} + +/* + * Incorrect number of arguments in signal handler for signal ‘GObject::notify’. Expected 3 but saw 4. + * (GCallback) object_notify_extra_parameter_cb, NULL); + * ^ + * note: expanded from macro 'g_signal_connect' + * g_signal_connect_data ((instance), (detailed_signal), (c_handler), (data), NULL, (GConnectFlags) 0) + * ^ + */ +{ + GObject *some_object = g_malloc (5); // only checking the type + g_signal_connect (some_object, "notify", + (GCallback) object_notify_extra_parameter_cb, NULL); +} + +/* + * No signal named ‘invalid-signal’ in GObject class ‘Object’. + * g_signal_connect (some_object, "invalid-signal", + * ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * note: expanded from macro 'g_signal_connect' + * g_signal_connect_data ((instance), (detailed_signal), (c_handler), (data), NULL, (GConnectFlags) 0) + * ^ ~~~~~~~~~~ ~~~~~~~~~~~~~~~~~ + */ +{ + GObject *some_object = g_malloc (5); // only checking the type + g_signal_connect (some_object, "invalid-signal", + (GCallback) object_notify_cb, NULL); +} diff --git a/tests/gsignal.head.c b/tests/gsignal.head.c new file mode 100644 index 0000000..8b6e1ac --- /dev/null +++ b/tests/gsignal.head.c @@ -0,0 +1,82 @@ +#include + +#include +#include +#include + +static void +object_notify_cb (GObject *gobject, GParamSpec *pspec, gpointer user_data) +{ + /* Something */ +} + +extern void +object_notify_proto_cb (GObject *gobject, GParamSpec *pspec, gpointer user_data); + +extern void +object_notify_no_proto_cb (); + +static gboolean +object_notify_invalid_return_cb (GObject *gobject, GParamSpec *pspec, + gpointer user_data) +{ + /* Something */ + return FALSE; +} + +static void +object_notify_invalid_parameter_subclass_cb (GIOStream *gobject, + GParamSpec *pspec, + gpointer user_data) +{ + /* Something */ +} + +static void +object_notify_invalid_parameter_const_cb (const GObject *gobject, + GParamSpec *pspec, + gpointer user_data) +{ + /* Something */ +} + +static void +object_notify_invalid_parameter_middle_cb (GObject *gobject, + void *pspec, + gpointer user_data) +{ + /* Something */ +} + +static void +object_notify_invalid_parameter_user_data_cb (GObject *gobject, + GParamSpec *pspec, + guint user_data) +{ + /* Something */ +} + +static void +object_notify_invalid_parameter_user_data_ptr_cb (GObject *gobject, + GParamSpec *pspec, + GObject *user_data) +{ + /* Something */ +} + +static void +object_notify_missing_parameter_cb (GObject *gobject, GParamSpec *pspec) +{ + /* Something */ +} + +static void +object_notify_extra_parameter_cb (GObject *gobject, GParamSpec *pspec, + gpointer user_data, gpointer user_data2) +{ + /* Something */ +} + +int +main (void) +{ diff --git a/tests/gsignal.tail.c b/tests/gsignal.tail.c new file mode 100644 index 0000000..aa0c781 --- /dev/null +++ b/tests/gsignal.tail.c @@ -0,0 +1,4 @@ + /* End of main(). */ + + return 0; +} -- cgit v1.2.3