summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohan Dahlin <johan@gnome.org>2010-09-23 17:13:29 -0300
committerJohan Dahlin <johan@gnome.org>2010-09-23 17:25:47 -0300
commite2b95cdb39d6e5f287e23dbf30a04031b49a230f (patch)
treeb3d36b0a28cf358dc1ce40459d57e4638eb965b1
parent2525786185e0f9025f88c00769d948d2b83d646d (diff)
downloadgobject-introspection-e2b95cdb39d6e5f287e23dbf30a04031b49a230f.tar.gz
[scanner] Warn for invalid scanner annotations
Warn for invalid annotations. Change so that custom attributes have to use the annotation keyword.
-rw-r--r--giscanner/annotationparser.py81
-rw-r--r--giscanner/maintransformer.py14
-rw-r--r--tests/scanner/Annotation-1.0-expected.gir4
-rw-r--r--tests/scanner/annotation.c10
-rw-r--r--tests/warn/Makefile.am1
-rw-r--r--tests/warn/invalid-option.h8
6 files changed, 95 insertions, 23 deletions
diff --git a/giscanner/annotationparser.py b/giscanner/annotationparser.py
index aad17e89..937b9be3 100644
--- a/giscanner/annotationparser.py
+++ b/giscanner/annotationparser.py
@@ -22,7 +22,7 @@
import re
-from .message import Position
+from . import message
from .odict import odict
# All gtk-doc comments needs to start with this:
@@ -45,7 +45,11 @@ TAG_GET_VALUE_FUNC = 'get value func'
# Options - annotations for parameters and return values
OPT_ALLOW_NONE = 'allow-none'
OPT_ARRAY = 'array'
+OPT_ATTRIBUTE = 'attribute'
+OPT_CLOSURE = 'closure'
+OPT_DESTROY = 'destroy'
OPT_ELEMENT_TYPE = 'element-type'
+OPT_FOREIGN = 'foreign'
OPT_IN = 'in'
OPT_INOUT = 'inout'
OPT_INOUT_ALT = 'in-out'
@@ -53,10 +57,24 @@ OPT_OUT = 'out'
OPT_SCOPE = 'scope'
OPT_TRANSFER = 'transfer'
OPT_TYPE = 'type'
-OPT_CLOSURE = 'closure'
-OPT_DESTROY = 'destroy'
OPT_SKIP = 'skip'
-OPT_FOREIGN = 'foreign'
+
+ALL_OPTIONS = [
+ OPT_ALLOW_NONE,
+ OPT_ARRAY,
+ OPT_ATTRIBUTE,
+ OPT_CLOSURE,
+ OPT_DESTROY,
+ OPT_ELEMENT_TYPE,
+ OPT_FOREIGN,
+ OPT_IN,
+ OPT_INOUT,
+ OPT_INOUT_ALT,
+ OPT_OUT,
+ OPT_SCOPE,
+ OPT_TRANSFER,
+ OPT_TYPE,
+ OPT_SKIP]
# Array options - array specific annotations
OPT_ARRAY_FIXED_SIZE = 'fixed-size'
@@ -71,11 +89,12 @@ class DocBlock(object):
def __init__(self, name):
self.name = name
- self.options = {}
+ self.options = DocOptions()
self.value = None
self.tags = odict()
self.comment = None
self.params = []
+ self.position = None
def __repr__(self):
return '<DocBlock %r %r>' % (self.name, self.options)
@@ -83,19 +102,62 @@ class DocBlock(object):
def get(self, name):
return self.tags.get(name)
+ def validate(self):
+ for tag in self.tags.values():
+ tag.validate()
+
class DocTag(object):
def __init__(self, block, name):
self.block = block
self.name = name
- self.options = {}
+ self.options = DocOptions()
self.comment = None
self.value = ''
+ self.position = None
def __repr__(self):
return '<DocTag %r %r>' % (self.name, self.options)
+ def validate(self):
+ for option in self.options:
+ if not option in ALL_OPTIONS:
+ message.warn('invalid option: %s' % (option, ),
+ positions=self.position)
+
+
+class DocOptions(object):
+ def __init__(self):
+ self.values = []
+
+ def __getitem__(self, item):
+ for key, value in self.values:
+ if key == item:
+ return value
+ raise KeyError
+
+ def __iter__(self):
+ return (k for k, v in self.values)
+
+ def add(self, name, value):
+ self.values.append((name, value))
+
+ def get(self, item, default=None):
+ for key, value in self.values:
+ if key == item:
+ return value
+ return default
+
+ def getall(self, item):
+ for key, value in self.values:
+ if key == item:
+ yield value
+
+ def iteritems(self):
+ return iter(self.values)
+
+
class DocOption(object):
def __init__(self, tag, option):
@@ -176,7 +238,7 @@ class AnnotationParser(object):
if cpos:
block_name = block_name[:cpos]
block = DocBlock(block_name)
- block.position = Position(filename, lineno)
+ block.position = message.Position(filename, lineno)
if cpos:
block.options = self.parse_options(block, block_header[cpos+2:])
comment_lines = []
@@ -271,6 +333,7 @@ class AnnotationParser(object):
comment_lines.append(line)
lineno += 1
block.comment = '\n'.join(comment_lines)
+ block.validate()
self._blocks[block.name] = block
@classmethod
@@ -278,7 +341,7 @@ class AnnotationParser(object):
# (foo)
# (bar opt1 opt2...)
opened = -1
- options = {}
+ options = DocOptions()
last = None
for i, c in enumerate(value):
if c == '(' and opened == -1:
@@ -295,7 +358,7 @@ class AnnotationParser(object):
raise AssertionError
if option is not None:
option = DocOption(tag, option)
- options[name] = option
+ options.add(name, option)
last = i + 2
opened = -1
diff --git a/giscanner/maintransformer.py b/giscanner/maintransformer.py
index a50951a3..605c5d35 100644
--- a/giscanner/maintransformer.py
+++ b/giscanner/maintransformer.py
@@ -25,8 +25,8 @@ from .annotationparser import (TAG_VFUNC, TAG_SINCE, TAG_DEPRECATED, TAG_RETURNS
TAG_ATTRIBUTES, TAG_RENAME_TO, TAG_TYPE, TAG_TRANSFER,
TAG_UNREF_FUNC, TAG_REF_FUNC, TAG_SET_VALUE_FUNC,
TAG_GET_VALUE_FUNC)
-from .annotationparser import (OPT_ALLOW_NONE,
- OPT_ARRAY, OPT_ELEMENT_TYPE, OPT_IN, OPT_INOUT,
+from .annotationparser import (OPT_ALLOW_NONE, OPT_ARRAY, OPT_ATTRIBUTE,
+ OPT_ELEMENT_TYPE, OPT_IN, OPT_INOUT,
OPT_INOUT_ALT, OPT_OUT, OPT_SCOPE,
OPT_TYPE, OPT_CLOSURE, OPT_DESTROY, OPT_SKIP,
OPT_FOREIGN, OPT_ARRAY_FIXED_SIZE,
@@ -114,6 +114,8 @@ usage is void (*_gtk_reserved1)(void);"""
ast.Record, ast.Union)):
return True
for field in node.fields:
+ if field is None:
+ continue
if (field.name.startswith('_')
and field.anonymous_node is not None
and isinstance(field.anonymous_node, ast.Callback)):
@@ -506,11 +508,9 @@ usage is void (*_gtk_reserved1)(void);"""
if tag is not None and tag.comment is not None:
node.doc = tag.comment
- for key in options:
- if '.' in key:
- value = options.get(key)
- if value:
- node.attributes.append((key, value.one()))
+ if options:
+ for attribute in options.getall(OPT_ATTRIBUTE):
+ node.attributes.append(attribute.flat())
def _apply_annotations_annotated(self, node, block):
if block is None:
diff --git a/tests/scanner/Annotation-1.0-expected.gir b/tests/scanner/Annotation-1.0-expected.gir
index 6d72dd4f..f922d582 100644
--- a/tests/scanner/Annotation-1.0-expected.gir
+++ b/tests/scanner/Annotation-1.0-expected.gir
@@ -609,8 +609,8 @@ it says it's pointer but it's actually a string.</doc>
</record>
<function name="attribute_func" c:identifier="annotation_attribute_func">
<return-value transfer-ownership="none">
- <attribute name="yet.another.annotation" value="another_value"/>
<attribute name="some.other.annotation" value="value2"/>
+ <attribute name="yet.another.annotation" value="another_value"/>
<doc xml:whitespace="preserve">The return value.</doc>
<type name="gint" c:type="gint"/>
</return-value>
@@ -620,8 +620,8 @@ it says it's pointer but it's actually a string.</doc>
<type name="Object" c:type="AnnotationObject*"/>
</parameter>
<parameter name="data" transfer-ownership="none">
- <attribute name="another.annotation" value="blahvalue"/>
<attribute name="some.annotation" value="value"/>
+ <attribute name="another.annotation" value="blahvalue"/>
<doc xml:whitespace="preserve">Some data.</doc>
<type name="utf8" c:type="gchar*"/>
</parameter>
diff --git a/tests/scanner/annotation.c b/tests/scanner/annotation.c
index 40df0860..e2e0991f 100644
--- a/tests/scanner/annotation.c
+++ b/tests/scanner/annotation.c
@@ -122,12 +122,12 @@ annotation_object_class_init (AnnotationObjectClass *klass)
/**
* AnnotationObject::attribute-signal:
* @annotation: the annotation object
- * @arg1: (some.annotation.foo1 val1): a value
- * @arg2: (some.annotation.foo2 val2): another value
+ * @arg1: (attribute some.annotation.foo1 val1): a value
+ * @arg2: (attribute some.annotation.foo2 val2): another value
*
* This signal tests a signal with attributes.
*
- * Returns: (some.annotation.foo3 val3): the return value
+ * Returns: (attribute some.annotation.foo3 val3): the return value
*/
annotation_object_signals[ATTRIBUTE_SIGNAL] =
g_signal_new ("attribute-signal",
@@ -734,9 +734,9 @@ annotation_ptr_array (GPtrArray *array)
/**
* annotation_attribute_func:
* @object: A #AnnotationObject.
- * @data: (some.annotation value) (another.annotation blahvalue): Some data.
+ * @data: (attribute some.annotation value) (attribute another.annotation blahvalue): Some data.
*
- * Returns: (some.other.annotation value2) (yet.another.annotation another_value): The return value.
+ * Returns: (attribute some.other.annotation value2) (attribute yet.another.annotation another_value): The return value.
*/
gint
annotation_attribute_func (AnnotationObject *object,
diff --git a/tests/warn/Makefile.am b/tests/warn/Makefile.am
index 81c7442b..44515d7e 100644
--- a/tests/warn/Makefile.am
+++ b/tests/warn/Makefile.am
@@ -4,6 +4,7 @@ TESTS = \
callback-invalid-scope.h \
callback-missing-scope.h \
return-gobject.h \
+ invalid-option.h \
unknown-parameter.h \
unresolved-element-type.h \
unresolved-type.h
diff --git a/tests/warn/invalid-option.h b/tests/warn/invalid-option.h
new file mode 100644
index 00000000..22483bb9
--- /dev/null
+++ b/tests/warn/invalid-option.h
@@ -0,0 +1,8 @@
+
+/**
+ * func:
+ * @param: (invalid-annotation-option):
+ */
+void test_func(int param);
+
+// EXPECT:4: Warning: Test: invalid option: invalid-annotation-option