Skip to content

Commit

Permalink
Merge pull request sphinx-doc#8928 from jakobandersen/c_fixes
Browse files Browse the repository at this point in the history
C fixes
  • Loading branch information
jakobandersen authored Feb 24, 2021
2 parents 3f4a58b + 0256daf commit e0a1233
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 52 deletions.
2 changes: 2 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ Bugs fixed
with size explicitly set in pixels) (fixed for ``'pdflatex'/'lualatex'`` only)
* #8911: C++: remove the longest matching prefix in
:confval:`cpp_index_common_prefix` instead of the first that matches.
* C, properly reject function declarations when a keyword is used
as parameter name.

Testing
--------
Expand Down
43 changes: 8 additions & 35 deletions sphinx/domains/c.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,19 +387,6 @@ def describe_signature(self, signode: TextElement, mode: str,
signode.append(nodes.Text('--'))


class ASTPostfixMember(ASTPostfixOp):
def __init__(self, name):
self.name = name

def _stringify(self, transform: StringifyTransform) -> str:
return '.' + transform(self.name)

def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
signode.append(nodes.Text('.'))
self.name.describe_signature(signode, 'noneIsName', env, symbol)


class ASTPostfixMemberOfPointer(ASTPostfixOp):
def __init__(self, name):
self.name = name
Expand Down Expand Up @@ -2256,7 +2243,7 @@ def _parse_postfix_expression(self) -> ASTPostfixExpr:
# | postfix "[" expression "]"
# | postfix "[" braced-init-list [opt] "]"
# | postfix "(" expression-list [opt] ")"
# | postfix "." id-expression
# | postfix "." id-expression // taken care of in primary by nested name
# | postfix "->" id-expression
# | postfix "++"
# | postfix "--"
Expand All @@ -2274,17 +2261,6 @@ def _parse_postfix_expression(self) -> ASTPostfixExpr:
self.fail("Expected ']' in end of postfix expression.")
postFixes.append(ASTPostfixArray(expr))
continue
if self.skip_string('.'):
if self.skip_string('*'):
# don't steal the dot
self.pos -= 2
elif self.skip_string('..'):
# don't steal the dot
self.pos -= 3
else:
name = self._parse_nested_name()
postFixes.append(ASTPostfixMember(name))
continue
if self.skip_string('->'):
if self.skip_string('*'):
# don't steal the arrow
Expand Down Expand Up @@ -2693,16 +2669,13 @@ def _parse_decl_specs(self, outer: str, typed: bool = True) -> ASTDeclSpecs:
def _parse_declarator_name_suffix(
self, named: Union[bool, str], paramMode: str, typed: bool
) -> ASTDeclarator:
assert named in (True, False, 'single')
# now we should parse the name, and then suffixes
if named == 'maybe':
pos = self.pos
try:
declId = self._parse_nested_name()
except DefinitionError:
self.pos = pos
declId = None
elif named == 'single':
if named == 'single':
if self.match(identifier_re):
if self.matched_text in _keywords:
self.fail("Expected identifier, "
"got keyword: %s" % self.matched_text)
identifier = ASTIdentifier(self.matched_text)
declId = ASTNestedName([identifier], rooted=False)
else:
Expand Down Expand Up @@ -2880,8 +2853,8 @@ def parser():

def _parse_type(self, named: Union[bool, str], outer: str = None) -> ASTType:
"""
named=False|'maybe'|True: 'maybe' is e.g., for function objects which
doesn't need to name the arguments
named=False|'single'|True: 'single' is e.g., for function objects which
doesn't need to name the arguments, but otherwise is a single name
"""
if outer: # always named
if outer not in ('type', 'member', 'function'):
Expand Down
2 changes: 2 additions & 0 deletions tests/roots/test-domain-c/anon-dup-decl.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. c:namespace:: anon_dup_decl_ns
.. c:struct:: anon_dup_decl
.. c:struct:: @a.A
Expand Down
2 changes: 2 additions & 0 deletions tests/roots/test-domain-c/function_param_target.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. c:namespace:: function_param_target
.. c:function:: void f(int i)
- :c:var:`i`
Expand Down
2 changes: 2 additions & 0 deletions tests/roots/test-domain-c/index.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. c:namespace:: index
test-domain-c
=============

Expand Down
10 changes: 0 additions & 10 deletions tests/roots/test-domain-c/semicolon.rst

This file was deleted.

38 changes: 31 additions & 7 deletions tests/test_domain_c.py
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,9 @@ def test_function_definitions():
check('function', 'void f(int arr[const static volatile 42])', {1: 'f'},
output='void f(int arr[static volatile const 42])')

with pytest.raises(DefinitionError):
parse('function', 'void f(int for)')


def test_nested_name():
check('struct', '{key}.A', {1: "A"})
Expand Down Expand Up @@ -523,8 +526,15 @@ def test_attributes():
# raise DefinitionError("")


def split_warnigns(warning):
ws = warning.getvalue().split("\n")
assert len(ws) >= 1
assert ws[-1] == ""
return ws[:-1]


def filter_warnings(warning, file):
lines = warning.getvalue().split("\n")
lines = split_warnigns(warning)
res = [l for l in lines if "domain-c" in l and "{}.rst".format(file) in l and
"WARNING: document isn't included in any toctree" not in l]
print("Filtered warnings for file '{}':".format(file))
Expand Down Expand Up @@ -578,10 +588,22 @@ def test_build_domain_c_anon_dup_decl(app, status, warning):
assert "WARNING: c:identifier reference target not found: @b" in ws[1]


@pytest.mark.sphinx(testroot='domain-c', confoverrides={'nitpicky': True})
def test_build_domain_c_semicolon(app, status, warning):
app.builder.build_all()
ws = filter_warnings(warning, "semicolon")
@pytest.mark.sphinx(confoverrides={'nitpicky': True})
def test_build_domain_c_semicolon(app, warning):
text = """
.. c:member:: int member;
.. c:var:: int var;
.. c:function:: void f();
.. .. c:macro:: NO_SEMICOLON;
.. c:struct:: Struct;
.. c:union:: Union;
.. c:enum:: Enum;
.. c:enumerator:: Enumerator;
.. c:type:: Type;
.. c:type:: int TypeDef;
"""
restructuredtext.parse(app, text)
ws = split_warnigns(warning)
assert len(ws) == 0


Expand All @@ -593,8 +615,8 @@ def test_build_function_param_target(app, warning):
assert len(ws) == 0
entries = extract_role_links(app, "function_param_target.html")
assert entries == [
('c.f', 'i', 'i'),
('c.f', 'f.i', 'f.i'),
('c.function_param_target.f', 'i', 'i'),
('c.function_param_target.f', 'f.i', 'f.i'),
]


Expand Down Expand Up @@ -656,6 +678,8 @@ def test_noindexentry(app):

@pytest.mark.sphinx(testroot='domain-c-intersphinx', confoverrides={'nitpicky': True})
def test_intersphinx(tempdir, app, status, warning):
# a splitting of test_ids_vs_tags0 into the primary directives in a remote project,
# and then the references in the test project
origSource = """\
.. c:member:: int _member
.. c:var:: int _var
Expand Down

0 comments on commit e0a1233

Please sign in to comment.