summaryrefslogtreecommitdiff
path: root/giscanner
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 /giscanner
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.
Diffstat (limited to 'giscanner')
-rw-r--r--giscanner/annotationparser.py81
-rw-r--r--giscanner/maintransformer.py14
2 files changed, 79 insertions, 16 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: