diff options
author | Philip Withnall <philip.withnall@collabora.co.uk> | 2014-06-20 13:52:14 +0100 |
---|---|---|
committer | Colin Walters <walters@verbum.org> | 2015-10-04 17:46:09 -0400 |
commit | 10cb665fee2cc378dd2f13bad16e6384836a8b16 (patch) | |
tree | 3d699aa40290c4902774233290ec89d277ff9dec /giscanner | |
parent | 0a134a608f5b471c3a12739785e149ceaf90df27 (diff) | |
download | gobject-introspection-10cb665fee2cc378dd2f13bad16e6384836a8b16.tar.gz |
giscanner: Mark gpointer nodes as nullable by default
gpointer parameters and return types should be marked as nullable by
default, unless:
• also annotated with (type) and not with (nullable); or
• explicitly annotated with (not nullable).
This introduces the (not nullable) annotation as a direct opposite to
(nullable). In future, (not) could be extended to invert other
annotations.
https://bugzilla.gnome.org/show_bug.cgi?id=729660
Diffstat (limited to 'giscanner')
-rw-r--r-- | giscanner/annotationparser.py | 36 | ||||
-rw-r--r-- | giscanner/ast.py | 13 | ||||
-rw-r--r-- | giscanner/girparser.py | 2 | ||||
-rw-r--r-- | giscanner/girwriter.py | 4 | ||||
-rw-r--r-- | giscanner/maintransformer.py | 20 |
5 files changed, 62 insertions, 13 deletions
diff --git a/giscanner/annotationparser.py b/giscanner/annotationparser.py index d48ed616..31a62927 100644 --- a/giscanner/annotationparser.py +++ b/giscanner/annotationparser.py @@ -208,6 +208,7 @@ ANN_INOUT = 'inout' ANN_METHOD = 'method' ANN_NULLABLE = 'nullable' ANN_OPTIONAL = 'optional' +ANN_NOT = 'not' ANN_OUT = 'out' ANN_REF_FUNC = 'ref-func' ANN_RENAME_TO = 'rename-to' @@ -223,6 +224,7 @@ ANN_VALUE = 'value' GI_ANNS = [ANN_ALLOW_NONE, ANN_NULLABLE, ANN_OPTIONAL, + ANN_NOT, ANN_ARRAY, ANN_ATTRIBUTES, ANN_CLOSURE, @@ -273,6 +275,11 @@ OPT_OUT_CALLER_ALLOCATES = 'caller-allocates' OUT_OPTIONS = [OPT_OUT_CALLEE_ALLOCATES, OPT_OUT_CALLER_ALLOCATES] +# (not) annotation options +OPT_NOT_NULLABLE = 'nullable' + +NOT_OPTIONS = [OPT_NOT_NULLABLE] + # (scope) annotation options OPT_SCOPE_ASYNC = 'async' OPT_SCOPE_CALL = 'call' @@ -568,6 +575,18 @@ class GtkDocAnnotatable(object): # GObject-Instrospection version. warn('unknown annotation: %s' % (ann_name, ), position) + # Validate that (nullable) and (not nullable) are not both + # present. Same for (allow-none) and (not nullable). + if ann_name == ANN_NOT and OPT_NOT_NULLABLE in options: + if ANN_NULLABLE in self.annotations: + warn('cannot have both "%s" and "%s" present' % + (ANN_NOT + ' ' + OPT_NOT_NULLABLE, ANN_NULLABLE), + position) + if ANN_ALLOW_NONE in self.annotations: + warn('cannot have both "%s" and "%s" present' % + (ANN_NOT + ' ' + OPT_NOT_NULLABLE, ANN_ALLOW_NONE), + position) + def _validate_options(self, position, ann_name, n_options, expected_n_options, operator, message): ''' @@ -829,6 +848,19 @@ class GtkDocAnnotatable(object): self._validate_annotation(position, ann_name, options, exact_n_options=0) + def _do_validate_not(self, position, ann_name, options): + ''' + Validate the ``(not)`` annotation. + + :param position: :class:`giscanner.message.Position` of the line in the source file + containing the annotation to be validated + :param ann_name: name of the annotation holding the options to validate + :param options: annotation options held by the annotation + ''' + + self._validate_annotation(position, ann_name, options, exact_n_options=1, + choices=NOT_OPTIONS) + def _do_validate_out(self, position, ann_name, options): ''' Validate the ``(out)`` annotation. @@ -974,7 +1006,7 @@ class GtkDocParameter(GtkDocAnnotatable): valid_annotations = (ANN_ALLOW_NONE, ANN_ARRAY, ANN_ATTRIBUTES, ANN_CLOSURE, ANN_DESTROY, ANN_ELEMENT_TYPE, ANN_IN, ANN_INOUT, ANN_OUT, ANN_SCOPE, ANN_SKIP, - ANN_TRANSFER, ANN_TYPE, ANN_OPTIONAL, ANN_NULLABLE) + ANN_TRANSFER, ANN_TYPE, ANN_OPTIONAL, ANN_NULLABLE, ANN_NOT) def __init__(self, name, position=None): GtkDocAnnotatable.__init__(self, position) @@ -997,7 +1029,7 @@ class GtkDocTag(GtkDocAnnotatable): __slots__ = ('name', 'value', 'description') valid_annotations = (ANN_ALLOW_NONE, ANN_ARRAY, ANN_ATTRIBUTES, ANN_ELEMENT_TYPE, ANN_SKIP, - ANN_TRANSFER, ANN_TYPE, ANN_NULLABLE, ANN_OPTIONAL) + ANN_TRANSFER, ANN_TYPE, ANN_NULLABLE, ANN_OPTIONAL, ANN_NOT) def __init__(self, name, position=None): GtkDocAnnotatable.__init__(self, position) diff --git a/giscanner/ast.py b/giscanner/ast.py index aeb49ed2..99bbd3e1 100644 --- a/giscanner/ast.py +++ b/giscanner/ast.py @@ -845,10 +845,11 @@ class Alias(Node): class TypeContainer(Annotated): """A fundamental base class for Return and Parameter.""" - def __init__(self, typenode, nullable, transfer, direction): + def __init__(self, typenode, nullable, not_nullable, transfer, direction): Annotated.__init__(self) self.type = typenode self.nullable = nullable + self.not_nullable = not_nullable self.direction = direction if transfer is not None: self.transfer = transfer @@ -864,8 +865,9 @@ class Parameter(TypeContainer): def __init__(self, argname, typenode, direction=None, transfer=None, nullable=False, optional=False, allow_none=False, scope=None, - caller_allocates=False): - TypeContainer.__init__(self, typenode, nullable, transfer, direction) + caller_allocates=False, not_nullable=False): + TypeContainer.__init__(self, typenode, nullable, not_nullable, + transfer, direction) self.argname = argname self.optional = optional self.parent = None # A Callable @@ -889,8 +891,9 @@ class Parameter(TypeContainer): class Return(TypeContainer): """A return value from a function.""" - def __init__(self, rtype, nullable=False, transfer=None): - TypeContainer.__init__(self, rtype, nullable, transfer, + def __init__(self, rtype, nullable=False, not_nullable=False, + transfer=None): + TypeContainer.__init__(self, rtype, nullable, not_nullable, transfer, direction=PARAM_DIRECTION_OUT) self.parent = None # A Callable diff --git a/giscanner/girparser.py b/giscanner/girparser.py index 57f3e908..909e08d9 100644 --- a/giscanner/girparser.py +++ b/giscanner/girparser.py @@ -318,7 +318,7 @@ class GIRParser(object): raise ValueError('node %r has no return-value' % (name, )) transfer = returnnode.attrib.get('transfer-ownership') nullable = returnnode.attrib.get('nullable') == '1' - retval = ast.Return(self._parse_type(returnnode), nullable, transfer) + retval = ast.Return(self._parse_type(returnnode), nullable, False, transfer) self._parse_generic_attribs(returnnode, retval) parameters = [] diff --git a/giscanner/girwriter.py b/giscanner/girwriter.py index e73dcaca..f637376f 100644 --- a/giscanner/girwriter.py +++ b/giscanner/girwriter.py @@ -214,7 +214,7 @@ class GIRWriter(XMLWriter): attrs.append(('transfer-ownership', return_.transfer)) if return_.skip: attrs.append(('skip', '1')) - if return_.nullable: + if return_.nullable and not return_.not_nullable: attrs.append(('nullable', '1')) with self.tagcontext('return-value', attrs): self._write_generic(return_) @@ -240,7 +240,7 @@ class GIRWriter(XMLWriter): if parameter.transfer: attrs.append(('transfer-ownership', parameter.transfer)) - if parameter.nullable: + if parameter.nullable and not parameter.not_nullable: attrs.append(('nullable', '1')) if parameter.direction != ast.PARAM_DIRECTION_OUT: attrs.append(('allow-none', '1')) diff --git a/giscanner/maintransformer.py b/giscanner/maintransformer.py index 8bac1430..5ea1f5b4 100644 --- a/giscanner/maintransformer.py +++ b/giscanner/maintransformer.py @@ -32,10 +32,11 @@ from .annotationparser import (ANN_ALLOW_NONE, ANN_ARRAY, ANN_ATTRIBUTES, ANN_CL ANN_GET_VALUE_FUNC, ANN_IN, ANN_INOUT, ANN_METHOD, ANN_OUT, ANN_REF_FUNC, ANN_RENAME_TO, ANN_SCOPE, ANN_SET_VALUE_FUNC, ANN_SKIP, ANN_TRANSFER, ANN_TYPE, ANN_UNREF_FUNC, ANN_VALUE, - ANN_VFUNC, ANN_NULLABLE, ANN_OPTIONAL) + ANN_VFUNC, ANN_NULLABLE, ANN_OPTIONAL, ANN_NOT) from .annotationparser import (OPT_ARRAY_FIXED_SIZE, OPT_ARRAY_LENGTH, OPT_ARRAY_ZERO_TERMINATED, OPT_OUT_CALLEE_ALLOCATES, OPT_OUT_CALLER_ALLOCATES, - OPT_TRANSFER_CONTAINER, OPT_TRANSFER_FLOATING, OPT_TRANSFER_NONE) + OPT_TRANSFER_CONTAINER, OPT_TRANSFER_FLOATING, OPT_TRANSFER_NONE, + OPT_NOT_NULLABLE) from .utils import to_underscores_noprefix @@ -646,9 +647,16 @@ class MainTransformer(object): self._apply_transfer_annotation(parent, node, annotations) self._adjust_container_type(parent, node, annotations) + # gpointer parameters and return values are always nullable unless: + # - annotated with (type) and not also with (nullable); or + # - annotated (not nullable) + # See: https://bugzilla.gnome.org/show_bug.cgi?id=719966#c22 + if node.type.is_equiv(ast.TYPE_ANY): + node.nullable = True if ANN_NULLABLE in annotations: if self._is_pointer_type(node, annotations): node.nullable = True + node.not_nullable = False else: message.warn('invalid "nullable" annotation: ' 'only valid for pointer types and out parameters', @@ -679,6 +687,11 @@ class MainTransformer(object): node.type.target_giname == 'Gio.Cancellable')): node.nullable = True + # Final override for nullability + if ANN_NOT in annotations: + node.nullable = False + node.not_nullable = True + if tag and tag.description: node.doc = tag.description @@ -1443,7 +1456,8 @@ method or constructor of some type.""" for param in params: # By convention, closure user_data parameters are always nullable. if param.closure_name is not None and \ - param.closure_name == param.argname: + param.closure_name == param.argname and \ + not param.not_nullable: param.nullable = True def _pass3_callable_throws(self, node): |