summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakeshi KOMIYA <i.tkomiya@gmail.com>2020-04-28 01:26:28 +0900
committerGitHub <noreply@github.com>2020-04-28 01:26:28 +0900
commitdfdc70546f9ab04985c8b2a6cae80fcc13e9a11c (patch)
tree346ab5f1d62f8cc611d0cd261f79c8912100764d
parentf388114d10753a201b961a2b440601667da615d6 (diff)
parentb1e732fd8fc14ed2fefd02d4460bcafae710f10d (diff)
downloadsphinx-git-dfdc70546f9ab04985c8b2a6cae80fcc13e9a11c.tar.gz
Merge pull request #7566 from jakobandersen/merge_c_array_declarator
Merge c array declarator PR into 3.x
-rw-r--r--CHANGES5
-rw-r--r--sphinx/domains/c.py101
-rw-r--r--sphinx/ext/autodoc/__init__.py4
-rw-r--r--tests/test_domain_c.py15
4 files changed, 106 insertions, 19 deletions
diff --git a/CHANGES b/CHANGES
index 4c97b1dc8..a1f8f1cf5 100644
--- a/CHANGES
+++ b/CHANGES
@@ -89,9 +89,14 @@ Deprecated
Features added
--------------
+* C, parse array declarators with static, qualifiers, and VLA specification.
+
Bugs fixed
----------
+* #7516: autodoc: crashes if target object raises an error on accessing
+ its attributes
+
Testing
--------
diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py
index 1e5eb57a0..8854d7941 100644
--- a/sphinx/domains/c.py
+++ b/sphinx/domains/c.py
@@ -792,20 +792,60 @@ class ASTDeclSpecs(ASTBase):
################################################################################
class ASTArray(ASTBase):
- def __init__(self, size: ASTExpression):
+ def __init__(self, static: bool, const: bool, volatile: bool, restrict: bool,
+ vla: bool, size: ASTExpression):
+ self.static = static
+ self.const = const
+ self.volatile = volatile
+ self.restrict = restrict
+ self.vla = vla
self.size = size
+ if vla:
+ assert size is None
+ if size is not None:
+ assert not vla
def _stringify(self, transform: StringifyTransform) -> str:
- if self.size:
- return '[' + transform(self.size) + ']'
- else:
- return '[]'
+ el = []
+ if self.static:
+ el.append('static')
+ if self.restrict:
+ el.append('restrict')
+ if self.volatile:
+ el.append('volatile')
+ if self.const:
+ el.append('const')
+ if self.vla:
+ return '[' + ' '.join(el) + '*]'
+ elif self.size:
+ el.append(transform(self.size))
+ return '[' + ' '.join(el) + ']'
def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
verify_description_mode(mode)
signode.append(nodes.Text("["))
- if self.size:
+ addSpace = False
+
+ def _add(signode: TextElement, text: str) -> bool:
+ if addSpace:
+ signode += nodes.Text(' ')
+ signode += addnodes.desc_annotation(text, text)
+ return True
+
+ if self.static:
+ addSpace = _add(signode, 'static')
+ if self.restrict:
+ addSpace = _add(signode, 'restrict')
+ if self.volatile:
+ addSpace = _add(signode, 'volatile')
+ if self.const:
+ addSpace = _add(signode, 'const')
+ if self.vla:
+ signode.append(nodes.Text('*'))
+ elif self.size:
+ if addSpace:
+ signode += nodes.Text(' ')
self.size.describe_signature(signode, mode, env, symbol)
signode.append(nodes.Text("]"))
@@ -2595,18 +2635,45 @@ class DefinitionParser(BaseParser):
self.skip_ws()
if typed and self.skip_string('['):
self.skip_ws()
- if self.skip_string(']'):
- arrayOps.append(ASTArray(None))
- continue
-
- def parser() -> ASTExpression:
- return self._parse_expression()
+ static = False
+ const = False
+ volatile = False
+ restrict = False
+ while True:
+ if not static:
+ if self.skip_word_and_ws('static'):
+ static = True
+ continue
+ if not const:
+ if self.skip_word_and_ws('const'):
+ const = True
+ continue
+ if not volatile:
+ if self.skip_word_and_ws('volatile'):
+ volatile = True
+ continue
+ if not restrict:
+ if self.skip_word_and_ws('restrict'):
+ restrict = True
+ continue
+ break
+ vla = False if static else self.skip_string_and_ws('*')
+ if vla:
+ if not self.skip_string(']'):
+ self.fail("Expected ']' in end of array operator.")
+ size = None
+ else:
+ if self.skip_string(']'):
+ size = None
+ else:
- value = self._parse_expression_fallback([']'], parser)
- if not self.skip_string(']'):
- self.fail("Expected ']' in end of array operator.")
- arrayOps.append(ASTArray(value))
- continue
+ def parser():
+ return self._parse_expression()
+ size = self._parse_expression_fallback([']'], parser)
+ self.skip_ws()
+ if not self.skip_string(']'):
+ self.fail("Expected ']' in end of array operator.")
+ arrayOps.append(ASTArray(static, const, volatile, restrict, vla, size))
else:
break
param = self._parse_parameters(paramMode)
diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py
index 3e8b2d765..ed717387b 100644
--- a/sphinx/ext/autodoc/__init__.py
+++ b/sphinx/ext/autodoc/__init__.py
@@ -582,9 +582,9 @@ class Documenter:
isprivate = membername.startswith('_')
keep = False
- if getattr(member, '__sphinx_mock__', False):
+ if safe_getattr(member, '__sphinx_mock__', False):
# mocked module or object
- keep = False
+ pass
elif want_all and membername.startswith('__') and \
membername.endswith('__') and len(membername) > 4:
# special __methods__
diff --git a/tests/test_domain_c.py b/tests/test_domain_c.py
index f85a0e62e..237519fcc 100644
--- a/tests/test_domain_c.py
+++ b/tests/test_domain_c.py
@@ -362,6 +362,21 @@ def test_function_definitions():
check('function', 'void f(enum E e)', {1: 'f'})
check('function', 'void f(union E e)', {1: 'f'})
+ # array declarators
+ check('function', 'void f(int arr[])', {1: 'f'})
+ check('function', 'void f(int arr[*])', {1: 'f'})
+ cvrs = ['', 'const', 'volatile', 'restrict', 'restrict volatile const']
+ for cvr in cvrs:
+ space = ' ' if len(cvr) != 0 else ''
+ check('function', 'void f(int arr[{}*])'.format(cvr), {1: 'f'})
+ check('function', 'void f(int arr[{}])'.format(cvr), {1: 'f'})
+ check('function', 'void f(int arr[{}{}42])'.format(cvr, space), {1: 'f'})
+ check('function', 'void f(int arr[static{}{} 42])'.format(space, cvr), {1: 'f'})
+ check('function', 'void f(int arr[{}{}static 42])'.format(cvr, space), {1: 'f'},
+ output='void f(int arr[static{}{} 42])'.format(space, cvr))
+ check('function', 'void f(int arr[const static volatile 42])', {1: 'f'},
+ output='void f(int arr[static volatile const 42])')
+
def test_union_definitions():
check('struct', 'A', {1: 'A'})