From 7c3d1e7c5d6d209c262789b22ea6a99b0636771d Mon Sep 17 00:00:00 2001 From: Johan Dahlin Date: Fri, 24 Sep 2010 09:59:43 -0300 Subject: [PATCH] [annotationparser] Validate the rest of the annotations All option annotations, which uses parenthesis are now properly validated for number of values they expect --- giscanner/annotationparser.py | 106 ++++++++++++++++++++++++++++------- tests/warn/Makefile.am | 3 +- tests/warn/invalid-element-type.h | 54 ++++++++++++++++++ tests/warn/invalid-out.h | 8 +++ tests/warn/unresolved-element-type.h | 11 ---- 5 files changed, 151 insertions(+), 31 deletions(-) create mode 100644 tests/warn/invalid-element-type.h create mode 100644 tests/warn/invalid-out.h delete mode 100644 tests/warn/unresolved-element-type.h diff --git a/giscanner/annotationparser.py b/giscanner/annotationparser.py index 2bb2ee3..b8e8530 100644 --- a/giscanner/annotationparser.py +++ b/giscanner/annotationparser.py @@ -1,6 +1,6 @@ # -*- Mode: Python -*- # GObject-Introspection - a framework for introspecting GObject libraries -# Copyright (C) 2008 Johan Dahlin +# Copyright (C) 2008-2010 Johan Dahlin # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -18,7 +18,7 @@ # 02110-1301, USA. # -# AnnotationParser - parses gtk-doc annotations +# AnnotationParser - extract annotations from gtk-doc comments import re @@ -134,21 +134,29 @@ class DocTag(object): def __repr__(self): return '' % (self.name, self.options) - def _validate_option(self, name, value, required=False, n_params=None, choices=None): + def _validate_option(self, name, value, required=False, + n_params=None, choices=None): if required and value is None: - message.warn('%s annotation needs a value' % (name, ), self.position) + message.warn('%s annotation needs a value' % ( + name, ), self.position) return - if n_params is not None and value.length() != n_params: + if n_params is not None: if n_params == 0: s = 'no value' elif n_params == 1: s = 'one value' else: s = '%d values' % (n_params, ) - message.warn('%s annotation needs %s, not %d' % ( - name, s, value.length()), self.position) - return + if ((n_params > 0 and (value is None or value.length() != n_params)) or + n_params == 0 and value is not None): + if value is None: + length = 0 + else: + length = value.length() + message.warn('%s annotation needs %s, not %d' % ( + name, s, length), self.position) + return if choices is not None: valuestr = value.one() @@ -157,20 +165,63 @@ class DocTag(object): name, valuestr, ), self.position) return + def set_position(self, position): + self.position = position + self.options.position = position + def validate(self): for option in self.options: - if not option in ALL_OPTIONS: - message.warn('invalid annotation option: %s' % (option, ), - positions=self.position) value = self.options[option] - if option == OPT_TRANSFER: - self._validate_option( - 'transfer', value, required=True, - n_params=1, - choices=[OPT_TRANSFER_FULL, - OPT_TRANSFER_CONTAINER, - OPT_TRANSFER_NONE]) - + if option == OPT_ALLOW_NONE: + self._validate_option('allow-none', value, n_params=0) + elif option == OPT_ARRAY: + if value is None: + continue + for v in value.all(): + if v not in [OPT_ARRAY_LENGTH, + OPT_ARRAY_ZERO_TERMINATED, + OPT_ARRAY_FIXED_SIZE]: + message.warn( + 'invalid array annotation value: %r' % ( + v, ), self.position) + elif option == OPT_ATTRIBUTE: + self._validate_option('attribute', value, n_params=2) + elif option == OPT_CLOSURE: + self._validate_option('closure', value, n_params=1) + elif option == OPT_DESTROY: + self._validate_option('destroy', value, n_params=1) + elif option == OPT_ELEMENT_TYPE: + self._validate_option('element-type', value, required=True) + if value is None: + message.warn( + 'element-type takes at least one value, none given', + self.position) + continue + if value.length() > 2: + message.warn( + 'element-type takes at maximium 2 values, %d given' % ( + value.length()), self.position) + continue + elif option == OPT_FOREIGN: + self._validate_option('foreign', value, n_params=0) + elif option == OPT_IN: + self._validate_option('in', value, n_params=0) + elif option in [OPT_INOUT, OPT_INOUT_ALT]: + self._validate_option('inout', value, n_params=0) + elif option == OPT_OUT: + if value is None: + continue + if value.length() > 1: + message.warn( + 'out annotation takes at maximium 1 value, %d given' % ( + value.length()), self.position) + continue + value_str = value.one() + if value_str not in [OPT_OUT_CALLEE_ALLOCATES, + OPT_OUT_CALLER_ALLOCATES]: + message.warn("out annotation value is invalid: %r" % ( + value_str), self.position) + continue elif option == OPT_SCOPE: self._validate_option( 'scope', value, required=True, @@ -178,6 +229,22 @@ class DocTag(object): choices=[OPT_SCOPE_ASYNC, OPT_SCOPE_CALL, OPT_SCOPE_NOTIFIED]) + elif option == OPT_SKIP: + self._validate_option('skip', value, n_params=0) + elif option == OPT_TRANSFER: + self._validate_option( + 'transfer', value, required=True, + n_params=1, + choices=[OPT_TRANSFER_FULL, + OPT_TRANSFER_CONTAINER, + OPT_TRANSFER_NONE]) + elif option == OPT_TYPE: + self._validate_option('type', value, required=True, + n_params=1) + else: + message.warn('invalid annotation option: %s' % (option, ), + positions=self.position) + class DocOptions(object): def __init__(self): @@ -216,6 +283,7 @@ class DocOption(object): self.tag = tag self._array = [] self._dict = {} + # (annotation option1=value1 option2=value2) etc for p in option.split(' '): if '=' in p: name, value = p.split('=', 1) diff --git a/tests/warn/Makefile.am b/tests/warn/Makefile.am index bdcc970..26c2dcb 100644 --- a/tests/warn/Makefile.am +++ b/tests/warn/Makefile.am @@ -4,10 +4,11 @@ TESTS = \ callback-invalid-scope.h \ callback-missing-scope.h \ return-gobject.h \ + invalid-element-type.h \ invalid-option.h \ + invalid-out.h \ invalid-transfer.h \ unknown-parameter.h \ - unresolved-element-type.h \ unresolved-type.h EXTRA_DIST = warningtester.py common.h $(TESTS) diff --git a/tests/warn/invalid-element-type.h b/tests/warn/invalid-element-type.h new file mode 100644 index 0000000..f2cf2b9 --- /dev/null +++ b/tests/warn/invalid-element-type.h @@ -0,0 +1,54 @@ +#include "common.h" + +/** + * test_invalid_list_element_type: + * @l1: (element-type): + * @l2: (element-type int int): + */ + +void test_invalid_list_element_type(GList *l1, GList *l2); + +// EXPECT:5: Warning: Test: element-type annotation needs a value +// EXPECT:5: Warning: Test: element-type takes at least one value, none given + +/** + * test_invalid_array_element_type: + * @a1: (element-type): + * @a2: (element-type int int): + */ + +void test_invalid_array_element_type(const char *a1, const char *a2); + +// EXPECT:16: Warning: Test: element-type annotation needs a value +// EXPECT:16: Warning: Test: element-type takes at least one value, none given + +/** + * test_invalid_hash_element_type: + * @h1: (element-type): + * @h2: (element-type int): + * @h3: (element-type int int int): + */ + +void test_invalid_hash_element_type(GHashTable *h1, GHashTable *h2, GHashTable *h3); + +// EXPECT:27: Warning: Test: element-type annotation needs a value +// EXPECT:27: Warning: Test: element-type takes at least one value, none given +// EXPECT:29: Warning: Test: element-type takes at maximium 2 values, 3 given + +/** + * test_unresolved_element_type: + * + * Returns: (element-type Unresolved) (transfer full): + */ + +GList* test_unresolved_element_type(void); + + +// EXPECT:5: Warning: Test: element-type annotation takes at least one option, none given +// EXPECT:6: Warning: Test: element-type annotation for a list must have exactly one option, not 2 options +// EXPECT:16: Warning: Test: element-type annotation takes at least one option, none given +// EXPECT:20: Warning: Test: Unknown container Type(target_fundamental=utf8, ctype=char*) for element-type annotation +// EXPECT:27: Warning: Test: element-type annotation takes at least one option, none given +// EXPECT:28: Warning: Test: element-type annotation for a hash table must have exactly two options, not 1 option(s) +// EXPECT:29: Warning: Test: element-type annotation for a hash table must have exactly two options, not 3 option(s) +// EXPECT:41: Warning: Test: test_unresolved_element_type: Unknown type: 'Unresolved' diff --git a/tests/warn/invalid-out.h b/tests/warn/invalid-out.h new file mode 100644 index 0000000..fcb4f70 --- /dev/null +++ b/tests/warn/invalid-out.h @@ -0,0 +1,8 @@ +/** + * test_invalid_out: + * @out: (out invalid): + */ + +void test_invalid_out(int *out); + +// EXPECT:3: Warning: Test: out annotation value is invalid: 'invalid' diff --git a/tests/warn/unresolved-element-type.h b/tests/warn/unresolved-element-type.h deleted file mode 100644 index 26e13da..0000000 --- a/tests/warn/unresolved-element-type.h +++ /dev/null @@ -1,11 +0,0 @@ -#include "common.h" - -/** - * test_unresolved_element_type: - * - * Returns: (element-type Unresolved) (transfer full): - */ - -GList* test_unresolved_element_type(void); - -// EXPECT:6: Warning: Test: test_unresolved_element_type: Unknown type: 'Unresolved' -- 2.7.4