From bb09f9215449fcd1524a8c2d3b5cc56009f98a9a Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 10 Aug 2020 16:09:47 +0900 Subject: [PATCH 1/8] Fix #8091: autodoc: AttributeError is raised on documenting an attribute Until Python 3.5.2, typing.get_type_hints() raises AttributeError if given object does not have `__code__` attribute. This handles the exception not to crash building documents. Note: The AttributeError was fixed at 3.5.3 refs: https://github.com/python/cpython/commit/991d14fee1805e17647940a2a8cbf4f62f0f09ea --- CHANGES | 2 ++ sphinx/ext/autodoc/__init__.py | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/CHANGES b/CHANGES index d0e4e6316..1d523f3fd 100644 --- a/CHANGES +++ b/CHANGES @@ -40,6 +40,8 @@ Bugs fixed * #8074: napoleon: Crashes during processing C-ext module * #8084: autodoc: KeyError is raised on documenting an attribute of the broken class +* #8091: autodoc: AttributeError is raised on documenting an attribute on Python + 3.5.2 Testing -------- diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 47f6bcb25..f3820f715 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -1613,6 +1613,9 @@ class DataDocumenter(ModuleLevelDocumenter): except KeyError: # a broken class found (refs: https://github.com/sphinx-doc/sphinx/issues/8084) annotations = {} + except AttributeError: + # AttributeError is raised on 3.5.2 (fixed by 3.5.3) + annotations = {} if self.objpath[-1] in annotations: objrepr = stringify_typehint(annotations.get(self.objpath[-1])) @@ -1986,6 +1989,9 @@ class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): except KeyError: # a broken class found (refs: https://github.com/sphinx-doc/sphinx/issues/8084) annotations = {} + except AttributeError: + # AttributeError is raised on 3.5.2 (fixed by 3.5.3) + annotations = {} if self.objpath[-1] in annotations: objrepr = stringify_typehint(annotations.get(self.objpath[-1])) From 2d180e49c268fa5f9574a1f594e7e253e4c196b7 Mon Sep 17 00:00:00 2001 From: Keewis Date: Mon, 10 Aug 2020 13:03:50 +0200 Subject: [PATCH 2/8] add a setting to disable the type preprocessor --- sphinx/ext/napoleon/__init__.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sphinx/ext/napoleon/__init__.py b/sphinx/ext/napoleon/__init__.py index 6cab63c9f..793384dd2 100644 --- a/sphinx/ext/napoleon/__init__.py +++ b/sphinx/ext/napoleon/__init__.py @@ -41,6 +41,7 @@ class Config: napoleon_use_param = True napoleon_use_rtype = True napoleon_use_keyword = True + napoleon_preprocess_types = True napoleon_type_aliases = None napoleon_custom_sections = None @@ -237,9 +238,12 @@ class Config: :returns: *bool* -- True if successful, False otherwise + napoleon_preprocess_types : :obj:`bool` (Defaults to True) + Enable the type preprocessor for numpy style docstrings. + napoleon_type_aliases : :obj:`dict` (Defaults to None) Add a mapping of strings to string, translating types in numpy - style docstrings. + style docstrings. Only works if ``napoleon_preprocess_types = True``. napoleon_custom_sections : :obj:`list` (Defaults to None) Add a list of custom sections to include, expanding the list of parsed sections. @@ -268,6 +272,7 @@ class Config: 'napoleon_use_param': (True, 'env'), 'napoleon_use_rtype': (True, 'env'), 'napoleon_use_keyword': (True, 'env'), + 'napoleon_preprocess_types': (True, 'env'), 'napoleon_type_aliases': (None, 'env'), 'napoleon_custom_sections': (None, 'env') } From 27c252ccbab0a266ed9588355be9af261105b29e Mon Sep 17 00:00:00 2001 From: Keewis Date: Mon, 10 Aug 2020 13:04:21 +0200 Subject: [PATCH 3/8] only preprocess if the preprocessor is enabled --- sphinx/ext/napoleon/docstring.py | 11 ++++++----- tests/test_ext_napoleon_docstring.py | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/sphinx/ext/napoleon/docstring.py b/sphinx/ext/napoleon/docstring.py index 29799cb06..a629f147f 100644 --- a/sphinx/ext/napoleon/docstring.py +++ b/sphinx/ext/napoleon/docstring.py @@ -1104,11 +1104,12 @@ class NumpyDocstring(GoogleDocstring): _name, _type = line, '' _name, _type = _name.strip(), _type.strip() _name = self._escape_args_and_kwargs(_name) - _type = _convert_numpy_type_spec( - _type, - location=self._get_location(), - translations=self._config.napoleon_type_aliases or {}, - ) + if self._config.napoleon_enable_type_preprocessor: + _type = _convert_numpy_type_spec( + _type, + location=self._get_location(), + translations=self._config.napoleon_type_aliases or {}, + ) if prefer_type and not _type: _type, _name = _name, _type diff --git a/tests/test_ext_napoleon_docstring.py b/tests/test_ext_napoleon_docstring.py index 7eb908058..06a4a0c1a 100644 --- a/tests/test_ext_napoleon_docstring.py +++ b/tests/test_ext_napoleon_docstring.py @@ -1317,6 +1317,27 @@ class NumpyDocstringTest(BaseDocstringTest): expected = dedent(expected) self.assertEqual(expected, actual) + def test_type_preprocessor(self): + docstring = dedent(""" + Single line summary + + Parameters + ---------- + arg1:str + Extended + description of arg1 + """) + + config = Config(napoleon_preprocess_types=False, napoleon_use_param=False) + actual = str(NumpyDocstring(docstring, config)) + expected = dedent(""" + Single line summary + + :Parameters: **arg1** (*str*) -- Extended + description of arg1 + """) + self.assertEqual(expected, actual) + def test_parameters_with_class_reference(self): docstring = """\ Parameters From be65bded764597476474bdeb7862707ae965ee5b Mon Sep 17 00:00:00 2001 From: Keewis Date: Mon, 10 Aug 2020 23:10:27 +0200 Subject: [PATCH 4/8] fix a typo --- sphinx/ext/napoleon/docstring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/ext/napoleon/docstring.py b/sphinx/ext/napoleon/docstring.py index a629f147f..4397d0e41 100644 --- a/sphinx/ext/napoleon/docstring.py +++ b/sphinx/ext/napoleon/docstring.py @@ -1104,7 +1104,7 @@ class NumpyDocstring(GoogleDocstring): _name, _type = line, '' _name, _type = _name.strip(), _type.strip() _name = self._escape_args_and_kwargs(_name) - if self._config.napoleon_enable_type_preprocessor: + if self._config.napoleon_preprocess_types: _type = _convert_numpy_type_spec( _type, location=self._get_location(), From 1c388241b463c70f3191aacad2b0867c53245f49 Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 12 Aug 2020 19:48:07 +0200 Subject: [PATCH 5/8] default to False and update the tests --- sphinx/ext/napoleon/__init__.py | 6 +-- tests/test_ext_napoleon_docstring.py | 60 ++++++++++++++-------------- 2 files changed, 34 insertions(+), 32 deletions(-) diff --git a/sphinx/ext/napoleon/__init__.py b/sphinx/ext/napoleon/__init__.py index 793384dd2..e62ef7152 100644 --- a/sphinx/ext/napoleon/__init__.py +++ b/sphinx/ext/napoleon/__init__.py @@ -41,7 +41,7 @@ class Config: napoleon_use_param = True napoleon_use_rtype = True napoleon_use_keyword = True - napoleon_preprocess_types = True + napoleon_preprocess_types = False napoleon_type_aliases = None napoleon_custom_sections = None @@ -238,7 +238,7 @@ class Config: :returns: *bool* -- True if successful, False otherwise - napoleon_preprocess_types : :obj:`bool` (Defaults to True) + napoleon_preprocess_types : :obj:`bool` (Defaults to False) Enable the type preprocessor for numpy style docstrings. napoleon_type_aliases : :obj:`dict` (Defaults to None) @@ -272,7 +272,7 @@ class Config: 'napoleon_use_param': (True, 'env'), 'napoleon_use_rtype': (True, 'env'), 'napoleon_use_keyword': (True, 'env'), - 'napoleon_preprocess_types': (True, 'env'), + 'napoleon_preprocess_types': (False, 'env'), 'napoleon_type_aliases': (None, 'env'), 'napoleon_custom_sections': (None, 'env') } diff --git a/tests/test_ext_napoleon_docstring.py b/tests/test_ext_napoleon_docstring.py index 06a4a0c1a..bbc075edd 100644 --- a/tests/test_ext_napoleon_docstring.py +++ b/tests/test_ext_napoleon_docstring.py @@ -66,19 +66,19 @@ Sample namedtuple subclass Quick description of attr1 - :type: :class:`Arbitrary type` + :type: Arbitrary type .. attribute:: attr2 Quick description of attr2 - :type: :class:`Another arbitrary type` + :type: Another arbitrary type .. attribute:: attr3 Adds a newline after the type - :type: :class:`Type` + :type: Type """ self.assertEqual(expected, actual) @@ -1311,7 +1311,8 @@ class NumpyDocstringTest(BaseDocstringTest): config = Config( napoleon_use_param=False, napoleon_use_rtype=False, - napoleon_use_keyword=False) + napoleon_use_keyword=False, + napoleon_preprocess_types=True) for docstring, expected in self.docstrings: actual = str(NumpyDocstring(dedent(docstring), config)) expected = dedent(expected) @@ -1373,7 +1374,7 @@ x1, x2 : array_like config = Config(napoleon_use_param=False) actual = str(NumpyDocstring(docstring, config)) expected = """\ -:Parameters: **x1, x2** (:class:`array_like`) -- Input arrays, description of ``x1``, ``x2``. +:Parameters: **x1, x2** (*array_like*) -- Input arrays, description of ``x1``, ``x2``. """ self.assertEqual(expected, actual) @@ -1381,9 +1382,9 @@ x1, x2 : array_like actual = str(NumpyDocstring(dedent(docstring), config)) expected = """\ :param x1: Input arrays, description of ``x1``, ``x2``. -:type x1: :class:`array_like` +:type x1: array_like :param x2: Input arrays, description of ``x1``, ``x2``. -:type x2: :class:`array_like` +:type x2: array_like """ self.assertEqual(expected, actual) @@ -1398,7 +1399,7 @@ param1 : MyClass instance config = Config(napoleon_use_param=False) actual = str(NumpyDocstring(docstring, config)) expected = """\ -:Parameters: **param1** (:class:`MyClass instance`) +:Parameters: **param1** (*MyClass instance*) """ self.assertEqual(expected, actual) @@ -1406,7 +1407,7 @@ param1 : MyClass instance actual = str(NumpyDocstring(dedent(docstring), config)) expected = """\ :param param1: -:type param1: :class:`MyClass instance` +:type param1: MyClass instance """ self.assertEqual(expected, actual) @@ -1495,7 +1496,7 @@ arg_ : type expected = """ :ivar arg_: some description -:vartype arg_: :class:`type` +:vartype arg_: type """ config = Config(napoleon_use_ivar=True) @@ -1515,7 +1516,7 @@ arg_ : type expected = """ :ivar arg\\_: some description -:vartype arg\\_: :class:`type` +:vartype arg\\_: type """ config = Config(napoleon_use_ivar=True) @@ -1883,59 +1884,59 @@ definition_after_normal_text : int expected = """One line summary. :param no_list: -:type no_list: :class:`int` +:type no_list: int :param one_bullet_empty: * -:type one_bullet_empty: :class:`int` +:type one_bullet_empty: int :param one_bullet_single_line: - first line -:type one_bullet_single_line: :class:`int` +:type one_bullet_single_line: int :param one_bullet_two_lines: + first line continued -:type one_bullet_two_lines: :class:`int` +:type one_bullet_two_lines: int :param two_bullets_single_line: - first line - second line -:type two_bullets_single_line: :class:`int` +:type two_bullets_single_line: int :param two_bullets_two_lines: * first line continued * second line continued -:type two_bullets_two_lines: :class:`int` +:type two_bullets_two_lines: int :param one_enumeration_single_line: 1. first line -:type one_enumeration_single_line: :class:`int` +:type one_enumeration_single_line: int :param one_enumeration_two_lines: 1) first line continued -:type one_enumeration_two_lines: :class:`int` +:type one_enumeration_two_lines: int :param two_enumerations_one_line: (iii) first line (iv) second line -:type two_enumerations_one_line: :class:`int` +:type two_enumerations_one_line: int :param two_enumerations_two_lines: a. first line continued b. second line continued -:type two_enumerations_two_lines: :class:`int` +:type two_enumerations_two_lines: int :param one_definition_one_line: item 1 first line -:type one_definition_one_line: :class:`int` +:type one_definition_one_line: int :param one_definition_two_lines: item 1 first line continued -:type one_definition_two_lines: :class:`int` +:type one_definition_two_lines: int :param two_definitions_one_line: item 1 first line item 2 second line -:type two_definitions_one_line: :class:`int` +:type two_definitions_one_line: int :param two_definitions_two_lines: item 1 first line @@ -1943,14 +1944,14 @@ definition_after_normal_text : int item 2 second line continued -:type two_definitions_two_lines: :class:`int` +:type two_definitions_two_lines: int :param one_definition_blank_line: item 1 first line extra first line -:type one_definition_blank_line: :class:`int` +:type one_definition_blank_line: int :param two_definitions_blank_lines: item 1 @@ -1963,12 +1964,12 @@ definition_after_normal_text : int second line extra second line -:type two_definitions_blank_lines: :class:`int` +:type two_definitions_blank_lines: int :param definition_after_normal_text: text line item 1 first line -:type definition_after_normal_text: :class:`int` +:type definition_after_normal_text: int """ config = Config(napoleon_use_param=True) actual = str(NumpyDocstring(docstring, config)) @@ -2062,7 +2063,7 @@ definition_after_normal_text : int item 1 first line """ - config = Config(napoleon_use_param=False) + config = Config(napoleon_use_param=False, napoleon_preprocess_types=True) actual = str(NumpyDocstring(docstring, config)) self.assertEqual(expected, actual) @@ -2243,6 +2244,7 @@ definition_after_normal_text : int config = Config( napoleon_use_param=True, napoleon_use_rtype=True, + napoleon_preprocess_types=True, napoleon_type_aliases=translations, ) actual = str(NumpyDocstring(docstring, config)) From 99e36398fcb5fd4e07dd0dcad1c36afaa7e75800 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 13 Aug 2020 22:38:57 +0900 Subject: [PATCH 6/8] Update CHANGES for PR #8095 --- CHANGES | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES b/CHANGES index 1d523f3fd..b852b6992 100644 --- a/CHANGES +++ b/CHANGES @@ -34,10 +34,15 @@ Deprecated Features added -------------- +* #8095: napoleon: Add :confval:`napoleon_preprocess_types` to enable the type + preprocessor for numpy style docstrings + Bugs fixed ---------- * #8074: napoleon: Crashes during processing C-ext module +* #8088: napoleon: "Inline literal start-string without end-string" warning in + Numpy style Parameters section * #8084: autodoc: KeyError is raised on documenting an attribute of the broken class * #8091: autodoc: AttributeError is raised on documenting an attribute on Python From d72fedb69d7a90eebf8ca92cbaa4c678c381e11a Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Thu, 13 Aug 2020 17:08:39 +0200 Subject: [PATCH 7/8] C++, fix template template parameter parsing https://github.com/sphinx-doc/sphinx/pull/8037#issuecomment-673511490 --- CHANGES | 1 + sphinx/domains/cpp.py | 1 + tests/test_domain_cpp.py | 1 + 3 files changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index b852b6992..282646967 100644 --- a/CHANGES +++ b/CHANGES @@ -47,6 +47,7 @@ Bugs fixed class * #8091: autodoc: AttributeError is raised on documenting an attribute on Python 3.5.2 +* C++, fix parsing of template template paramters, broken by the fix of #7944 Testing -------- diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 46708b846..0b3c02e83 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -6251,6 +6251,7 @@ class DefinitionParser(BaseParser): # ========================================================================== def _parse_template_paramter(self) -> ASTTemplateParam: + self.skip_ws() if self.skip_word('template'): # declare a tenplate template parameter nestedParams = self._parse_template_parameter_list() diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index 118227cd7..513205cab 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -764,6 +764,7 @@ def test_templates(): check('class', "template typename> {key}A", {2: "II0E0E1A"}) check('class', "template typename ...T> {key}A", {2: "II0EDpE1A"}) check('class', "template typename...> {key}A", {2: "II0EDpE1A"}) + check('class', "template typename...> {key}A", {2: "I0I0EDpE1A"}) check('class', "template {key}A", {2: "I_iE1A"}) check('class', "template {key}A", {2: "I_iE1A"}) From 52140be6b8d32795aaf99d4535121eaea6d8b3b3 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Thu, 13 Aug 2020 18:39:28 +0200 Subject: [PATCH 8/8] C and C++, parsing function attributes Fixes sphinx-doc/sphinx#8114 --- CHANGES | 1 + sphinx/domains/c.py | 21 ++++++++++++++++++--- sphinx/domains/cpp.py | 19 +++++++++++++++++-- sphinx/util/cfamily.py | 2 +- tests/test_domain_c.py | 9 ++++----- tests/test_domain_cpp.py | 6 +++--- 6 files changed, 44 insertions(+), 14 deletions(-) diff --git a/CHANGES b/CHANGES index 282646967..50008f519 100644 --- a/CHANGES +++ b/CHANGES @@ -36,6 +36,7 @@ Features added * #8095: napoleon: Add :confval:`napoleon_preprocess_types` to enable the type preprocessor for numpy style docstrings +* #8114: C and C++, parse function attributes after parameters and qualifiers. Bugs fixed ---------- diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py index 65786b5de..d8ccc2e3d 100644 --- a/sphinx/domains/c.py +++ b/sphinx/domains/c.py @@ -32,7 +32,7 @@ from sphinx.transforms import SphinxTransform from sphinx.transforms.post_transforms import ReferencesResolver from sphinx.util import logging from sphinx.util.cfamily import ( - NoOldIdError, ASTBaseBase, ASTBaseParenExprList, + NoOldIdError, ASTBaseBase, ASTAttribute, ASTBaseParenExprList, verify_description_mode, StringifyTransform, BaseParser, DefinitionError, UnsupportedMultiCharacterCharLiteral, identifier_re, anon_identifier_re, integer_literal_re, octal_literal_re, @@ -652,8 +652,9 @@ class ASTFunctionParameter(ASTBase): class ASTParameters(ASTBase): - def __init__(self, args: List[ASTFunctionParameter]) -> None: + def __init__(self, args: List[ASTFunctionParameter], attrs: List[ASTAttribute]) -> None: self.args = args + self.attrs = attrs @property def function_params(self) -> List[ASTFunctionParameter]: @@ -669,6 +670,9 @@ class ASTParameters(ASTBase): first = False res.append(str(a)) res.append(')') + for attr in self.attrs: + res.append(' ') + res.append(transform(attr)) return ''.join(res) def describe_signature(self, signode: TextElement, mode: str, @@ -683,6 +687,9 @@ class ASTParameters(ASTBase): arg.describe_signature(param, 'markType', env, symbol=symbol) paramlist += param signode += paramlist + for attr in self.attrs: + signode += nodes.Text(' ') + attr.describe_signature(signode) class ASTDeclSpecsSimple(ASTBaseBase): @@ -2572,7 +2579,15 @@ class DefinitionParser(BaseParser): self.fail( 'Expecting "," or ")" in parameters, ' 'got "%s".' % self.current_char) - return ASTParameters(args) + + attrs = [] + while True: + attr = self._parse_attribute() + if attr is None: + break + attrs.append(attr) + + return ASTParameters(args, attrs) def _parse_decl_specs_simple(self, outer: str, typed: bool) -> ASTDeclSpecsSimple: """Just parse the simple ones.""" diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 0b3c02e83..92d578427 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -1879,7 +1879,8 @@ class ASTNoexceptSpec(ASTBase): class ASTParametersQualifiers(ASTBase): def __init__(self, args: List[ASTFunctionParameter], volatile: bool, const: bool, refQual: str, exceptionSpec: ASTNoexceptSpec, trailingReturn: "ASTType", - override: bool, final: bool, initializer: str) -> None: + override: bool, final: bool, attrs: List[ASTAttribute], + initializer: str) -> None: self.args = args self.volatile = volatile self.const = const @@ -1888,6 +1889,7 @@ class ASTParametersQualifiers(ASTBase): self.trailingReturn = trailingReturn self.override = override self.final = final + self.attrs = attrs self.initializer = initializer @property @@ -1947,6 +1949,9 @@ class ASTParametersQualifiers(ASTBase): res.append(' final') if self.override: res.append(' override') + for attr in self.attrs: + res.append(' ') + res.append(transform(attr)) if self.initializer: res.append(' = ') res.append(self.initializer) @@ -1988,6 +1993,9 @@ class ASTParametersQualifiers(ASTBase): _add_anno(signode, 'final') if self.override: _add_anno(signode, 'override') + for attr in self.attrs: + signode += nodes.Text(' ') + attr.describe_signature(signode) if self.initializer: _add_text(signode, '= ' + str(self.initializer)) @@ -5709,6 +5717,13 @@ class DefinitionParser(BaseParser): override = self.skip_word_and_ws( 'override') # they can be permuted + attrs = [] + while True: + attr = self._parse_attribute() + if attr is None: + break + attrs.append(attr) + self.skip_ws() initializer = None if self.skip_string('='): @@ -5725,7 +5740,7 @@ class DefinitionParser(BaseParser): return ASTParametersQualifiers( args, volatile, const, refQual, exceptionSpec, trailingReturn, - override, final, initializer) + override, final, attrs, initializer) def _parse_decl_specs_simple(self, outer: str, typed: bool) -> ASTDeclSpecsSimple: """Just parse the simple ones.""" diff --git a/sphinx/util/cfamily.py b/sphinx/util/cfamily.py index a67b2a0ad..0edea128c 100644 --- a/sphinx/util/cfamily.py +++ b/sphinx/util/cfamily.py @@ -391,7 +391,7 @@ class BaseParser: % startPos) return self.definition[startPos:self.pos] - def _parse_attribute(self) -> ASTAttribute: + def _parse_attribute(self) -> Optional[ASTAttribute]: self.skip_ws() # try C++11 style startPos = self.pos diff --git a/tests/test_domain_c.py b/tests/test_domain_c.py index 71bf251e9..b6f72287e 100644 --- a/tests/test_domain_c.py +++ b/tests/test_domain_c.py @@ -497,17 +497,16 @@ def test_attributes(): parse('member', 'paren_attr({]}) int f') # position: decl specs - check('function', 'static inline __attribute__(()) void f()', - {1: 'f'}, + check('function', 'static inline __attribute__(()) void f()', {1: 'f'}, output='__attribute__(()) static inline void f()') - check('function', '[[attr1]] [[attr2]] void f()', - {1: 'f'}, - output='[[attr1]] [[attr2]] void f()') + check('function', '[[attr1]] [[attr2]] void f()', {1: 'f'}) # position: declarator check('member', 'int *[[attr]] i', {1: 'i'}) check('member', 'int *const [[attr]] volatile i', {1: 'i'}, output='int *[[attr]] volatile const i') check('member', 'int *[[attr]] *i', {1: 'i'}) + # position: parameters + check('function', 'void f() [[attr1]] [[attr2]]', {1: 'f'}) # issue michaeljones/breathe#500 check('function', 'LIGHTGBM_C_EXPORT int LGBM_BoosterFree(int handle)', diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index 513205cab..558d69911 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -938,15 +938,15 @@ def test_attributes(): check('function', 'static inline __attribute__(()) void f()', {1: 'f', 2: '1fv'}, output='__attribute__(()) static inline void f()') - check('function', '[[attr1]] [[attr2]] void f()', - {1: 'f', 2: '1fv'}, - output='[[attr1]] [[attr2]] void f()') + check('function', '[[attr1]] [[attr2]] void f()', {1: 'f', 2: '1fv'}) # position: declarator check('member', 'int *[[attr]] i', {1: 'i__iP', 2: '1i'}) check('member', 'int *const [[attr]] volatile i', {1: 'i__iPVC', 2: '1i'}, output='int *[[attr]] volatile const i') check('member', 'int &[[attr]] i', {1: 'i__iR', 2: '1i'}) check('member', 'int *[[attr]] *i', {1: 'i__iPP', 2: '1i'}) + # position: parameters and qualifiers + check('function', 'void f() [[attr1]] [[attr2]]', {1: 'f', 2: '1fv'}) def test_xref_parsing():