summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Withnall <philip.withnall@collabora.co.uk>2014-05-05 09:12:14 +0100
committerPhilip Withnall <philip.withnall@collabora.co.uk>2014-05-05 11:44:03 +0100
commiteee55c89f8e7821c75c645dc1583b66b8318bf95 (patch)
treeda032ee5c96b6e8aa0334f6a43b66c055db3d957
parent2da365c985d90096aa82efefa9bbacb3b5a3962a (diff)
clang-plugin: Add support for checking g_variant_get() calls
This required a little further work on top of the work for checking g_variant_new() calls, as g_variant_get() takes outbound arguments, rather than inbound ones, so has an extra level of indirection. Further to that, integer promotion doesn’t occur, and nullable arguments are treated a little differently. This includes a set of unit tests for g_variant_get().
-rw-r--r--clang-plugin/gvariant-checker.cpp282
-rw-r--r--tests/Makefile.am4
-rw-r--r--tests/gvariant-get.c510
-rw-r--r--tests/gvariant-new.c2
-rwxr-xr-xtests/wrapper-compiler-errors4
5 files changed, 705 insertions, 97 deletions
diff --git a/clang-plugin/gvariant-checker.cpp b/clang-plugin/gvariant-checker.cpp
index 94356ee..35155de 100644
--- a/clang-plugin/gvariant-checker.cpp
+++ b/clang-plugin/gvariant-checker.cpp
@@ -88,20 +88,22 @@ typedef struct {
unsigned int first_vararg_param_index;
/* Whether the function takes a va_list instead of varargs. */
bool uses_va_list;
+ /* True if the argument direction is in; false if it’s out. */
+ bool args_in;
} VariantFuncInfo;
static const VariantFuncInfo gvariant_format_funcs[] = {
- { "g_variant_new", 0, 1, false },
- { "g_variant_new_va", 0, 2, true },
-/* TODO:
- { "g_variant_get", 1, 2, false },
- { "g_variant_get_va", 1, 3, true },
- { "g_variant_get_child", 2, 3, false },
- { "g_variant_lookup", 2, 3, false },
- { "g_variant_iter_next", 1, 2, false },
- { "g_variant_iter_loop", 1, 2, false },
- { "g_variant_builder_add", 1, 2, false },
- { "g_variant_builder_add_parsed", 1, 2, false },
+ { "g_variant_new", 0, 1, false, true },
+ { "g_variant_new_va", 0, 2, true, true },
+ { "g_variant_get", 1, 2, false, false },
+ { "g_variant_get_va", 1, 3, true, false },
+/*
+ { "g_variant_get_child", 2, 3, false, false },
+ { "g_variant_lookup", 2, 3, false, false },
+ { "g_variant_iter_next", 1, 2, false, false },
+ { "g_variant_iter_loop", 1, 2, false, false },
+ { "g_variant_builder_add", 1, 2, false, true },
+ { "g_variant_builder_add_parsed", 1, 2, false, true },
*/
};
@@ -114,8 +116,17 @@ static const VariantFuncInfo gvariant_format_funcs[] = {
* variadic argument to be consumed to be GVariantBuilder*.
* @CHECK_FLAG_FORCE_VALIST: Force the expected type of the next variadic
* argument to be consumed to be va_list*.
+ * @CHECK_FLAG_FORCE_GVARIANTITER: Force the expected type of the next variadic
+ * argument to be consumed to be GVariantIter*.
+ * @CHECK_FLAG_REQUIRE_CONST: Require that the pointee of the expected type (if
+ * it is a pointer type) must be constant. This is ignored it
+ * %CHECK_FLAG_DIRECTION_OUT is not set.
+ * @CHECK_FLAG_DIRECTION_OUT: Expect the argument to be out-bound, so an extra
+ * level of pointer indirection will be expected on the expected type. If
+ * %CHECK_FLAG_ALLOW_MAYBE is also set, the top-most pointer can be %NULL.
* @CHECK_FLAG_ALLOW_MAYBE: Allow the next variadic argument to be consumed to
- * be potentially %NULL.
+ * be potentially %NULL. This always examines the top-most argument, not the
+ * value it points to if it’s a pointer.
* @CHECK_FLAG_CONSUME_ARGS: Consume variadic arguments when parsing. If this
* is not specified, the argument pointer will never be advanced, and all
* GVariant format strings for a given call will be checked against the same
@@ -128,7 +139,9 @@ typedef enum {
CHECK_FLAG_FORCE_GVARIANT = 1 << 0,
CHECK_FLAG_FORCE_GVARIANTBUILDER = 1 << 1,
CHECK_FLAG_FORCE_VALIST = 1 << 2,
- /* … */
+ CHECK_FLAG_FORCE_GVARIANTITER = 1 << 3,
+ CHECK_FLAG_REQUIRE_CONST = 1 << 4,
+ CHECK_FLAG_DIRECTION_OUT = 1 << 5,
CHECK_FLAG_ALLOW_MAYBE = 1 << 6,
CHECK_FLAG_CONSUME_ARGS = 1 << 7,
} VariantCheckFlags;
@@ -152,13 +165,68 @@ _func_uses_gvariant_format (const FunctionDecl& func)
return NULL;
}
+/*
+ * Return true if @actual_type and @expected_type compare equal, taking
+ * qualifications into account as specified by @flags.
+ *
+ * Check that @actual_type and @expected_type are equal. For inbound arguments,
+ * we need to compare the unqualified (with const, volatile, restrict removed)
+ * types, plus the unqualified pointee types if the normal types are pointers,
+ * plus the unqualified pointee pointee types, etc.
+ *
+ * .e.g.
+ * char* ≡ const char*
+ * int ≡ int
+ * char* ≡ char*
+ * GVariant* ≡ const GVariant*
+ * char** ≡ const char * const *
+ *
+ * For outbound arguments, we must compare qualified types.
+ */
+static bool
+_compare_types (const QualType actual_type, const QualType expected_type,
+ unsigned int /* VariantCheckFlags */ flags, ASTContext& context)
+{
+ DEBUG ("Comparing type ‘" << actual_type.getAsString () << "’ with ‘" <<
+ expected_type.getAsString () << "’.");
+
+ /* Fast path: Simple comparison. */
+ if (context.hasSameType (actual_type, expected_type)) {
+ return true;
+ }
+
+ /* Slow path: Strip pointers off and remove qualifiers for inbound
+ * actual types. */
+ const PointerType *actual_pointer_type = dyn_cast<PointerType> (actual_type);
+ const PointerType *expected_pointer_type = dyn_cast<PointerType> (expected_type);
+
+ if (actual_pointer_type == NULL || expected_pointer_type == NULL) {
+ return false;
+ }
+
+ QualType actual_pointee_type, expected_pointee_type;
+
+ actual_pointee_type = actual_pointer_type->getPointeeType ();
+ expected_pointee_type = expected_pointer_type->getPointeeType ();
+
+ /* Inbound arguments can be const or not. It’s a bit trickier for
+ * outbound arguments. */
+ if (!(flags & CHECK_FLAG_DIRECTION_OUT)) {
+ actual_pointee_type = actual_pointee_type.getUnqualifiedType ();
+ }
+
+ return _compare_types (actual_pointee_type, expected_pointee_type,
+ flags, context);
+}
+
/* Consume a single variadic argument from the varargs array, checking that one
* exists and has the given @expected_type. If %CHECK_FLAG_FORCE_GVARIANT is
* set, the expected type is forced to be GVariant*. (This is necessary because
* I can find no way to represent GVariant* as a QualType. If someone can fix
* that, the boolean argument can be removed.) Same for
- * %CHECK_FLAG_FORCE_GVARIANTBUILDER, but with GVariantBuilder*; and
- * %CHECK_FLAG_FORCE_VALIST, but with va_list*.
+ * %CHECK_FLAG_FORCE_GVARIANTBUILDER, but with GVariantBuilder*;
+ * %CHECK_FLAG_FORCE_VALIST, but with va_list*; and
+ * %CHECK_FLAG_FORCE_GVARIANTITER, but with GVariantIter*.
*
* Iff %CHECK_FLAG_ALLOW_MAYBE is set, the variadic argument may be NULL.
*
@@ -172,30 +240,50 @@ _consume_variadic_argument (QualType expected_type,
const StringLiteral *format_arg_str,
ASTContext& context)
{
- DEBUG ("Consuming variadic argument with expected type ‘" <<
- expected_type.getAsString () << "’.");
-
std::string expected_type_str;
if (flags & CHECK_FLAG_FORCE_GVARIANTBUILDER) {
/* Note: Stricter checking is implemented below. */
- DEBUG ("Forcing expected type to ‘GVariantBuilder*’.");
expected_type = context.VoidPtrTy;
expected_type_str = std::string ("GVariantBuilder *");
} else if (flags & CHECK_FLAG_FORCE_GVARIANT) {
/* Note: Stricter checking is implemented below. */
- DEBUG ("Forcing expected type to ‘GVariant*’.");
expected_type = context.VoidPtrTy;
expected_type_str = std::string ("GVariant *");
} else if (flags & CHECK_FLAG_FORCE_VALIST) {
/* Note: Stricter checking is implemented below. */
- DEBUG ("Forcing expected type to ‘va_list*’.");
expected_type = context.VoidPtrTy;
expected_type_str = std::string ("va_list *");
+ } else if (flags & CHECK_FLAG_FORCE_GVARIANTITER) {
+ /* Note: Stricter checking is implemented below. */
+ expected_type = context.VoidPtrTy;
+ expected_type_str = std::string ("GVariantIter *");
} else {
expected_type_str = expected_type.getAsString ();
}
+ /* Handle const-ness of out arguments. We have to insert the const one
+ * layer of pointer indirection down. i.e. char* becomes const char*. */
+ if ((flags & CHECK_FLAG_DIRECTION_OUT) &&
+ (flags & CHECK_FLAG_REQUIRE_CONST) &&
+ expected_type->isPointerType ()) {
+ const PointerType *expected2_type = dyn_cast<PointerType> (expected_type);
+ QualType expected_pointee_type = expected2_type->getPointeeType ();
+ expected_pointee_type = context.getConstType (expected_pointee_type);
+ expected_type = context.getPointerType (expected_pointee_type);
+ expected_type_str = "const " + expected_type_str;
+ }
+
+ /* Handle in/out arguments. This must be done after constness. */
+ if ((flags & CHECK_FLAG_DIRECTION_OUT) &&
+ !(flags & CHECK_FLAG_FORCE_VALIST)) {
+ expected_type = context.getPointerType (expected_type);
+ expected_type_str = expected_type_str + "*";
+ }
+
+ DEBUG ("Consuming variadic argument with expected type ‘" <<
+ expected_type.getAsString () << "’.");
+
if (*args_begin == *args_end) {
gchar *error;
@@ -232,7 +320,8 @@ _consume_variadic_argument (QualType expected_type,
} else if (!is_null_constant &&
(flags & (CHECK_FLAG_FORCE_GVARIANT |
CHECK_FLAG_FORCE_GVARIANTBUILDER |
- CHECK_FLAG_FORCE_VALIST))) {
+ CHECK_FLAG_FORCE_VALIST |
+ CHECK_FLAG_FORCE_GVARIANTITER))) {
/* Special case handling for GVariant[Builder]* types, because I
* can’t find a reasonable way of retrieving the QualType for
* the GVariant or GVariantBuilder typedefs; so we use this
@@ -254,12 +343,43 @@ _consume_variadic_argument (QualType expected_type,
}
QualType actual_pointee_type = actual_pointer_type->getPointeeType ();
+
+ /* Inbound arguments can be const or not. It’s a bit trickier
+ * for outbound arguments. Outbound arguments must have an extra
+ * level of pointer indirection stripped off. */
+ if (!(flags & CHECK_FLAG_DIRECTION_OUT)) {
+ actual_pointee_type = actual_pointee_type.getUnqualifiedType ();
+ } else if (!(flags & CHECK_FLAG_FORCE_VALIST)) {
+ const PointerType *actual_pointer2_type = dyn_cast<PointerType> (actual_pointee_type);
+ if (actual_pointer2_type == NULL) {
+ gchar *error;
+
+ error = g_strdup_printf (
+ "Expected a GVariant variadic argument "
+ "of type ‘%s’ but saw one of type "
+ "‘%s’.",
+ expected_type_str.c_str (),
+ actual_type.getAsString ().c_str ());
+ Debug::emit_error (error, compiler,
+ arg->getLocStart ());
+ g_free (error);
+
+ return false;
+ }
+
+ actual_pointee_type = actual_pointer2_type->getPointeeType ();
+ }
+
+ std::string actual_pointee_type_str = actual_pointee_type.getAsString ();
+
if (!(flags & CHECK_FLAG_FORCE_GVARIANTBUILDER &&
- actual_pointee_type.getUnqualifiedType ().getAsString () == "GVariantBuilder") &&
+ actual_pointee_type_str == "GVariantBuilder") &&
!(flags & CHECK_FLAG_FORCE_GVARIANT &&
- actual_pointee_type.getUnqualifiedType ().getAsString () == "GVariant") &&
+ actual_pointee_type_str == "GVariant") &&
!(flags & CHECK_FLAG_FORCE_VALIST &&
- actual_pointee_type.getUnqualifiedType ().getAsString () == "va_list")) {
+ actual_pointee_type_str == "va_list") &&
+ !(flags & CHECK_FLAG_FORCE_GVARIANTITER &&
+ actual_pointee_type_str == "GVariantIter")) {
gchar *error;
error = g_strdup_printf (
@@ -276,54 +396,11 @@ _consume_variadic_argument (QualType expected_type,
} else if (!is_null_constant &&
!(flags & (CHECK_FLAG_FORCE_GVARIANT |
CHECK_FLAG_FORCE_GVARIANTBUILDER |
- CHECK_FLAG_FORCE_VALIST))) {
+ CHECK_FLAG_FORCE_VALIST |
+ CHECK_FLAG_FORCE_GVARIANTITER))) {
/* Normal non-GVariant, non-GVariantBuilder case. */
- const PointerType *actual_pointer_type = dyn_cast<PointerType> (actual_type);
- const PointerType *actual_pointer2_type = NULL;
- QualType actual_pointee_type, actual_pointee2_type;
-
- if (actual_pointer_type != NULL) {
- actual_pointee_type = actual_pointer_type->getPointeeType ();
-
- actual_pointer2_type = dyn_cast<PointerType> (actual_pointee_type);
- if (actual_pointer2_type != NULL) {
- actual_pointee2_type = actual_pointer2_type->getPointeeType ();
- }
- }
-
- const PointerType *expected_pointer_type = dyn_cast<PointerType> (expected_type);
- const PointerType *expected_pointer2_type = NULL;
- QualType expected_pointee_type, expected_pointee2_type;
-
- if (expected_pointer_type != NULL) {
- expected_pointee_type = expected_pointer_type->getPointeeType ();
-
- expected_pointer2_type = dyn_cast<PointerType> (expected_pointee_type);
- if (expected_pointer2_type != NULL) {
- expected_pointee2_type = expected_pointer2_type->getPointeeType ();
- }
- }
-
- /* Check it’s of @expected_type. We need to compare the
- * unqualified (with const, volatile, restrict removed) types,
- * plus the unqualified pointee types if the normal types are
- * pointers, plus the unqualified pointee pointee types.
- * .e.g
- * char* ≡ const char*
- * int ≡ int
- * char* ≡ char*
- * GVariant* ≡ const GVariant*
- * char** ≡ const char * const * */
- if (!context.hasSameUnqualifiedType (actual_type,
- expected_type) &&
- (actual_pointer_type == NULL ||
- expected_pointer_type == NULL ||
- !context.hasSameUnqualifiedType (actual_pointee_type,
- expected_pointee_type)) &&
- (actual_pointer2_type == NULL ||
- expected_pointer2_type == NULL ||
- !context.hasSameUnqualifiedType (actual_pointee2_type,
- expected_pointee2_type))) {
+ if (!_compare_types (actual_type, expected_type,
+ flags, context)) {
gchar *error;
error = g_strdup_printf (
@@ -437,7 +514,8 @@ _check_basic_type_string (const gchar **type_str,
* • GVariant Format Strings, §Numeric Types
* • ISO/IEC 9899, §6.5.2.2¶6
*/
- if (**type_str == 'y' || **type_str == 'n' || **type_str == 'q') {
+ if (!(flags & CHECK_FLAG_DIRECTION_OUT) &&
+ (**type_str == 'y' || **type_str == 'n' || **type_str == 'q')) {
assert (expected_type->isPromotableIntegerType ());
expected_type = context.IntTy;
}
@@ -484,25 +562,29 @@ _check_type_string (const gchar **type_str,
/* Consume the ‘a’. */
*type_str = *type_str + 1;
+ /* Update flags for the array element type.
+ *
+ * FIXME: ALLOW_MAYBE only for definite types */
+ flags |= CHECK_FLAG_ALLOW_MAYBE;
+
+ if (flags & CHECK_FLAG_DIRECTION_OUT) {
+ flags |= CHECK_FLAG_FORCE_GVARIANTITER;
+ } else {
+ flags |= CHECK_FLAG_FORCE_GVARIANTBUILDER;
+ }
+
/* Check and consume the type string for the array element
* type. */
if (!_check_type_string (type_str, args_begin, args_end,
- (flags |
- CHECK_FLAG_FORCE_GVARIANTBUILDER |
- CHECK_FLAG_ALLOW_MAYBE) &
- ~CHECK_FLAG_CONSUME_ARGS,
- compiler, format_arg_str, context)) {
+ flags & ~CHECK_FLAG_CONSUME_ARGS,
+ compiler, format_arg_str, context)) {
return false;
}
- /* Consume the single GVariantBuilder for the array.
- * FIXME: ALLOW_MAYBE only for definite types */
+ /* Consume the single GVariantBuilder for the array. */
return _consume_variadic_argument (context.VoidPtrTy,
args_begin, args_end,
- flags |
- CHECK_FLAG_FORCE_GVARIANTBUILDER |
- CHECK_FLAG_ALLOW_MAYBE,
- compiler,
+ flags, compiler,
format_arg_str, context);
/* Maybe Types */
case 'm':
@@ -654,18 +736,22 @@ _check_basic_format_string (const gchar **format_str,
compiler, format_arg_str,
context);
case '&':
- /* Ignore it. */
+ /* Ignore it for inbound arguments; require that outbound
+ * arguments are const. */
*format_str = *format_str + 1;
return _check_basic_type_string (format_str, args_begin,
args_end,
- flags, compiler,
- format_arg_str, context);
+ flags |
+ CHECK_FLAG_REQUIRE_CONST,
+ compiler, format_arg_str,
+ context);
case '^': {
/* Various different hard-coded types. */
*format_str = *format_str + 1;
QualType expected_type;
QualType char_array = context.getPointerType (context.CharTy);
+ QualType const_char_array = context.getPointerType (context.getConstType (context.CharTy));
guint skip;
/* Effectively hard-code the table from
@@ -675,18 +761,20 @@ _check_basic_format_string (const gchar **format_str,
expected_type = context.getPointerType (char_array);
skip = 2;
} else if (strcmp (*format_str, "a&s") == 0 ||
- strcmp (*format_str, "a&o") == 0 ||
- strcmp (*format_str, "aay") == 0) {
+ strcmp (*format_str, "a&o") == 0) {
+ expected_type = context.getPointerType (const_char_array);
+ skip = 3;
+ } else if (strcmp (*format_str, "aay") == 0) {
expected_type = context.getPointerType (char_array);
skip = 3;
} else if (strcmp (*format_str, "ay") == 0) {
expected_type = char_array;
skip = 2;
} else if (strcmp (*format_str, "&ay") == 0) {
- expected_type = char_array;
+ expected_type = const_char_array;
skip = 3;
} else if (strcmp (*format_str, "a&ay") == 0) {
- expected_type = context.getPointerType (char_array);
+ expected_type = context.getPointerType (const_char_array);
skip = 4;
} else {
Debug::emit_error (
@@ -831,11 +919,12 @@ _check_format_string (const gchar **format_str,
return true;
case '&':
- /* Ignore it. */
+ /* Ignore it for inbound arguments; require that outbound
+ * arguments are const. */
*format_str = *format_str + 1;
return _check_type_string (format_str, args_begin, args_end,
- flags, compiler,
- format_arg_str, context);
+ flags | CHECK_FLAG_REQUIRE_CONST,
+ compiler, format_arg_str, context);
case '^':
/* Handled by the basic format string parser. */
return _check_basic_format_string (format_str, args_begin,
@@ -910,6 +999,11 @@ _check_gvariant_format_param (const CallExpr& call,
else
flags |= CHECK_FLAG_FORCE_VALIST;
+ /* Outbound arguments may always be NULL to skip that GVariant
+ * element. */
+ if (!func_info->args_in)
+ flags |= (CHECK_FLAG_DIRECTION_OUT | CHECK_FLAG_ALLOW_MAYBE);
+
if (!_check_format_string (&format_str, &args_begin, &args_end,
flags, compiler, format_arg_str, context)) {
return false;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index eb297d9..131bf19 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -6,6 +6,8 @@ TEST_EXTENSIONS = .c
C_LOG_COMPILER = ./wrapper-compiler-errors
TESTS = \
- gvariant-new.c
+ gvariant-new.c \
+ gvariant-get.c \
+ $(NULL)
-include $(top_srcdir)/git.mk
diff --git a/tests/gvariant-get.c b/tests/gvariant-get.c
new file mode 100644
index 0000000..f4e0fa4
--- /dev/null
+++ b/tests/gvariant-get.c
@@ -0,0 +1,510 @@
+/*
+ * No error
+ */
+{
+ gchar *str1 = NULL, *str2 = NULL;
+ g_variant_get (existing_variant, "(ss)", &str1, &str2);
+}
+
+/*
+ * No error
+ */
+{
+ gchar *str1 = NULL, *str2 = NULL;
+ g_variant_get (existing_variant, "(ss)", NULL, NULL);
+}
+
+/*
+ * No error
+ */
+{
+ const gchar *str1 = NULL, *str2 = NULL;
+ g_variant_get (existing_variant, "(&s&s)", &str1, &str2);
+}
+
+/*
+ * Expected a GVariant variadic argument of type ‘const char **’ but saw one of type ‘gchar **’.
+ * g_variant_get (existing_variant, "(&s&s)", &str1, &str2);
+ * ^
+ */
+{
+ // Outbound pointers must be const if ‘&’ is used.
+ gchar *str1 = NULL, *str2 = NULL;
+ g_variant_get (existing_variant, "(&s&s)", &str1, &str2);
+}
+
+/*
+ * Expected a GVariant variadic argument of type ‘int *’ but there wasn’t one.
+ * g_variant_get ("invalid");
+ * ^
+ */
+{
+ g_variant_get (existing_variant, "invalid");
+}
+
+/*
+ * No error
+ */
+{
+ gchar **some_str_array;
+ g_variant_get (existing_variant, "^as", &some_str_array);
+}
+
+/*
+ * Expected a GVariant variadic argument of type ‘char ***’ but saw one of type ‘const gchar ***’.
+ * g_variant_get (existing_variant, "^as", &some_str_array);
+ * ^
+ */
+{
+ const gchar **some_str_array;
+ g_variant_get (existing_variant, "^as", &some_str_array);
+}
+
+/*
+ * No error
+ */
+{
+ const gchar **some_str_array;
+ g_variant_get (existing_variant, "^a&s", &some_str_array);
+}
+
+/*
+ * Expected a GVariant variadic argument of type ‘const char ***’ but saw one of type ‘gchar ***’.
+ * g_variant_get (existing_variant, "^a&s", &some_str_array);
+ * ^
+ */
+{
+ gchar **some_str_array;
+ g_variant_get (existing_variant, "^a&s", &some_str_array);
+}
+
+/*
+ * No error
+ */
+{
+ gchar **some_str_array;
+ g_variant_get (existing_variant, "^ao", &some_str_array);
+}
+
+/*
+ * No error
+ */
+{
+ const gchar **some_str_array;
+ g_variant_get (existing_variant, "^a&o", &some_str_array);
+}
+
+/*
+ * No error
+ */
+{
+ gchar *some_byte_str;
+ g_variant_get (existing_variant, "^ay", &some_byte_str);
+}
+
+/*
+ * Expected a GVariant variadic argument of type ‘char **’ but saw one of type ‘const gchar **’.
+ * g_variant_get (existing_variant, "^ay", &some_byte_str);
+ * ^
+ */
+{
+ const gchar *some_byte_str;
+ g_variant_get (existing_variant, "^ay", &some_byte_str);
+}
+
+/*
+ * No error
+ */
+{
+ const gchar *some_byte_str;
+ g_variant_get (existing_variant, "^&ay", &some_byte_str);
+}
+
+/*
+ * Expected a GVariant variadic argument of type ‘const char **’ but saw one of type ‘gchar **’.
+ * g_variant_get (existing_variant, "^&ay", &some_byte_str);
+ * ^
+ */
+{
+ gchar *some_byte_str;
+ g_variant_get (existing_variant, "^&ay", &some_byte_str);
+}
+
+/*
+ * No error
+ */
+{
+ gchar **some_bytes_array;
+ g_variant_get (existing_variant, "^aay", &some_bytes_array);
+}
+
+/*
+ * Expected a GVariant variadic argument of type ‘char ***’ but saw one of type ‘const gchar ***’.
+ * g_variant_get (existing_variant, "^aay", &some_bytes_array);
+ * ^
+ */
+{
+ const gchar **some_bytes_array;
+ g_variant_get (existing_variant, "^aay", &some_bytes_array);
+}
+
+/*
+ * No error
+ */
+{
+ const gchar **some_bytes_array;
+ g_variant_get (existing_variant, "^a&ay", &some_bytes_array);
+}
+
+/*
+ * Expected a GVariant variadic argument of type ‘const char ***’ but saw one of type ‘gchar ***’.
+ * g_variant_get (existing_variant, "^a&ay", &some_bytes_array);
+ * ^
+ */
+{
+ gchar **some_bytes_array;
+ g_variant_get (existing_variant, "^a&ay", &some_bytes_array);
+}
+
+/*
+ * No error
+ */
+{
+ g_variant_get (existing_variant, "@s", NULL);
+}
+
+/*
+ * Expected a GVariant variadic argument of type ‘GVariant **’ but saw one of type ‘char **’.
+ * g_variant_get (existing_variant, "@s", &some_str);
+ * ^
+ */
+{
+ gchar *some_str;
+ g_variant_get (existing_variant, "@s", &some_str);
+}
+
+/*
+ * No error
+ */
+{
+ GVariant *some_variant;
+ g_variant_get (existing_variant, "@s", &some_variant);
+}
+
+/*
+ * Expected a GVariant variadic argument of type ‘GVariant **’ but saw one of type ‘const GVariant **’.
+ * g_variant_get (existing_variant, "@s", &some_variant);
+ * ^
+ */
+{
+ const GVariant *some_variant;
+ g_variant_get (existing_variant, "@s", &some_variant);
+}
+
+/*
+ * No error
+ */
+{
+ GVariant *some_variant1, *some_variant2;
+ gchar *some_str;
+ g_variant_get (existing_variant, "(@s@ss)", &some_variant1, &some_variant2, &some_str);
+}
+
+
+/*
+ * Unexpected GVariant format strings ‘u’ with unpaired arguments. If using multiple format strings, they should be enclosed in brackets to create a tuple (e.g. ‘(su)’).
+ * g_variant_get (existing_variant, "su", &some_str, &some_int);
+ * ^
+ */
+{
+ // Missing tuple brackets
+ gchar *some_str;
+ gint32 some_int;
+ g_variant_get (existing_variant, "si", &some_str, &some_int);
+}
+
+/*
+ * No error
+ */
+{
+ // Simple tuple
+ gchar *some_str;
+ gint32 some_int;
+ g_variant_get (existing_variant, "(si)", &some_str, &some_int);
+}
+
+/*
+ * No error
+ */
+{
+ // Nested tuples
+ gchar *str1, *str2;
+ gint32 int1;
+ g_variant_get (existing_variant, "((s)(si))", &str1, &str2, &int1);
+}
+
+/*
+ * No error
+ */
+{
+ // Empty tuple
+ g_variant_get (existing_variant, "()");
+}
+
+/*
+ * Invalid GVariant format string: tuple did not end with ‘)’.
+ * g_variant_get (existing_variant, "(si", &str1, &int1);
+ * ^
+ */
+{
+ // Unbalanced brackets
+ gchar *str1;
+ gint32 int1;
+ g_variant_get (existing_variant, "(si", &str1, &int1);
+}
+
+/*
+ * No error
+ */
+{
+ GVariant *some_var;
+ g_variant_get (existing_variant, "v", &some_var);
+}
+
+/*
+ * Expected a GVariant variadic argument of type ‘GVariant **’ but saw one of type ‘const GVariant **’.
+ * g_variant_get (existing_variant, "v", &some_var);
+ * ^
+ */
+{
+ const GVariant *some_var;
+ g_variant_get (existing_variant, "v", &some_var);
+}
+
+/*
+ * No error
+ */
+{
+ g_variant_get (existing_variant, "v", NULL);
+}
+
+/*
+ * Expected a GVariant variadic argument of type ‘GVariant **’ but saw one of type ‘char *’.
+ * g_variant_get (existing_variant, "v", "nope");
+ * ^
+ */
+{
+ g_variant_get (existing_variant, "v", "nope");
+}
+
+/*
+ * No error
+ */
+{
+ gchar *some_str;
+ g_variant_get (existing_variant, "ms", &some_str);
+}
+
+/*
+ * No error
+ */
+{
+ g_variant_get (existing_variant, "ms", NULL);
+}
+
+/*
+ * No error
+ */
+{
+ g_variant_get (existing_variant, "m&s", NULL);
+}
+
+/*
+ * No error
+ */
+{
+ const gchar *some_str;
+ g_variant_get (existing_variant, "m&s", &some_str);
+}
+
+/*
+ * Expected a GVariant variadic argument of type ‘const char **’ but saw one of type ‘gchar **’.
+ * g_variant_get (existing_variant, "m&s", &some_str);
+ * ^
+ */
+{
+ gchar *some_str;
+ g_variant_get (existing_variant, "m&s", &some_str);
+}
+
+
+/*
+ * No error
+ */
+{
+ GVariantIter *some_iter;
+ g_variant_get (existing_variant, "as", &some_iter);
+ g_variant_iter_free (some_iter);
+}
+
+/*
+ * Expected a GVariant variadic argument of type ‘GVariantIter **’ but saw one of type ‘GVariantIter *’.
+ * g_variant_get (existing_variant, "as", some_iter);
+ * ^
+ */
+{
+ // Incorrectly don’t pass @some_iter by reference.
+ GVariantIter *some_iter;
+ g_variant_get (existing_variant, "as", some_iter);
+ g_variant_iter_free (some_iter);
+}
+
+/*
+ * No error
+ */
+{
+ g_variant_get (existing_variant, "as", NULL);
+}
+
+/*
+ * No error
+ */
+{
+ g_variant_get (existing_variant, "a?", NULL);
+}
+
+/*
+ * No error
+ */
+{
+ GVariantIter *some_iter;
+ g_variant_get (existing_variant, "a(sss)", &some_iter);
+ g_variant_iter_free (some_iter);
+}
+
+/*
+ * No error
+ */
+{
+ GVariantIter *some_iter;
+ g_variant_get (existing_variant, "a{?*}", &some_iter);
+ g_variant_iter_free (some_iter);
+}
+
+/*
+ * Expected a GVariant variadic argument of type ‘GVariantIter **’ but saw one of type ‘char *’.
+ * g_variant_get (existing_variant, "au", "nope");
+ * ^
+ */
+{
+ g_variant_get (existing_variant, "au", "nope");
+}
+
+/*
+ * No error
+ */
+{
+ gboolean some_bool;
+ g_variant_get (existing_variant, "b", &some_bool);
+}
+
+/*
+ * Expected a GVariant variadic argument of type ‘int *’ but saw one of type ‘gchar *’.
+ * g_variant_get (existing_variant, "b", &some_not_bool);
+ * ^
+ */
+{
+ gchar some_not_bool;
+ g_variant_get (existing_variant, "b", &some_not_bool);
+}
+
+/*
+ * No error
+ */
+{
+ guchar some_uchar;
+ g_variant_get (existing_variant, "y", &some_uchar);
+}
+
+/*
+ * Expected a GVariant variadic argument of type ‘unsigned char *’ but saw one of type ‘guint *’.
+ * g_variant_get (existing_variant, "y", &some_uchar);
+ * ^
+ */
+{
+ // Type promotion doesn’t occur with g_variant_get().
+ guint some_uchar;
+ g_variant_get (existing_variant, "y", &some_uchar);
+}
+
+/*
+ * No error
+ */
+{
+ guint some_uchar;
+ g_variant_get (existing_variant, "y", (guchar *) &some_uchar);
+}
+
+/*
+ * No error
+ */
+{
+ gdouble some_double;
+ g_variant_get (existing_variant, "d", &some_double);
+}
+
+/*
+ * Expected a GVariant variadic argument of type ‘double *’ but saw one of type ‘gfloat *’.
+ * g_variant_get (existing_variant, "d", &some_float);
+ * ^
+ */
+{
+ gfloat some_float;
+ g_variant_get (existing_variant, "d", &some_float);
+}
+
+/*
+ * Expected a GVariant variadic argument of type ‘long *’ but saw one of type ‘gint32 *’.
+ * g_variant_get (existing_variant, "x", &some_int);
+ * ^
+ */
+{
+ gint32 some_int;
+ g_variant_get (existing_variant, "x", &some_int);
+}
+
+/*
+ * No error
+ */
+{
+ gint64 some_int;
+ g_variant_get (existing_variant, "x", &some_int);
+}
+
+/*
+ * Expected a GVariant variadic argument of type ‘long *’ but saw one of type ‘guint64 *’.
+ * g_variant_get (existing_variant, "x", &some_uint);
+ * ^
+ */
+{
+ guint64 some_uint;
+ g_variant_get (existing_variant, "x", &some_uint);
+}
+
+/*
+ * No error
+ */
+{
+ va_list some_va_list;
+ g_variant_get_va (existing_variant, "(sss)", NULL, &some_va_list);
+}
+
+/*
+ * Unexpected GVariant format strings ‘nvalid’ with unpaired arguments. If using multiple format strings, they should be enclosed in brackets to create a tuple (e.g. ‘(invalid)’).
+ * g_variant_get_va (existing_variant, "invalid", NULL, &some_va_list);
+ * ^
+ */
+{
+ va_list some_va_list;
+ g_variant_get_va (existing_variant, "invalid", NULL, &some_va_list);
+}
diff --git a/tests/gvariant-new.c b/tests/gvariant-new.c
index 2aebff9..451a610 100644
--- a/tests/gvariant-new.c
+++ b/tests/gvariant-new.c
@@ -895,7 +895,7 @@
* No error
*/
{
- floating_variant = g_variant_new ("^&ay", "some byte string");
+ floating_variant = g_variant_new ("^&ay", (const char *) "some byte string");
}
/*
diff --git a/tests/wrapper-compiler-errors b/tests/wrapper-compiler-errors
index ec2441b..d6459bc 100755
--- a/tests/wrapper-compiler-errors
+++ b/tests/wrapper-compiler-errors
@@ -56,10 +56,12 @@ while [[ -f `printf "${temp_dir}/${input_filename}_%02d.c" ${num}` ]]; do
int
main (void)
{
- GVariant *floating_variant = NULL;
+ GVariant *floating_variant = NULL, *existing_variant;
+ existing_variant = g_variant_new_boolean (FALSE); /* arbitrary */
EOF
cat $section_filename
cat << EOF
+ g_variant_unref (existing_variant);
if (floating_variant != NULL)
g_variant_unref (floating_variant);
}