diff options
author | Johan Dahlin <johan@gnome.org> | 2010-09-23 17:13:29 -0300 |
---|---|---|
committer | Johan Dahlin <johan@gnome.org> | 2010-09-23 17:25:47 -0300 |
commit | e2b95cdb39d6e5f287e23dbf30a04031b49a230f (patch) | |
tree | b3d36b0a28cf358dc1ce40459d57e4638eb965b1 | |
parent | 2525786185e0f9025f88c00769d948d2b83d646d (diff) | |
download | gobject-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.py | 81 | ||||
-rw-r--r-- | giscanner/maintransformer.py | 14 | ||||
-rw-r--r-- | tests/scanner/Annotation-1.0-expected.gir | 4 | ||||
-rw-r--r-- | tests/scanner/annotation.c | 10 | ||||
-rw-r--r-- | tests/warn/Makefile.am | 1 | ||||
-rw-r--r-- | tests/warn/invalid-option.h | 8 |
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 |