diff options
author | Philip Withnall <philip.withnall@collabora.co.uk> | 2014-05-05 09:12:14 +0100 |
---|---|---|
committer | Philip Withnall <philip.withnall@collabora.co.uk> | 2014-05-05 11:44:03 +0100 |
commit | eee55c89f8e7821c75c645dc1583b66b8318bf95 (patch) | |
tree | da032ee5c96b6e8aa0334f6a43b66c055db3d957 | |
parent | 2da365c985d90096aa82efefa9bbacb3b5a3962a (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.cpp | 282 | ||||
-rw-r--r-- | tests/Makefile.am | 4 | ||||
-rw-r--r-- | tests/gvariant-get.c | 510 | ||||
-rw-r--r-- | tests/gvariant-new.c | 2 | ||||
-rwxr-xr-x | tests/wrapper-compiler-errors | 4 |
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); } |