[gobject-introspection] [annotationparser] Validate the rest of the annotations



commit 7c3d1e7c5d6d209c262789b22ea6a99b0636771d
Author: Johan Dahlin <johan gnome org>
Date:   Fri Sep 24 09:59:43 2010 -0300

    [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(-)
---
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 '<DocTag %r %r>' % (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'



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]