Skip to content

Commit

Permalink
Merge pull request #7905 from jakobandersen/c_compat
Browse files Browse the repository at this point in the history
C, add compatibility flag for parsing some pre-v3 input
  • Loading branch information
jakobandersen committed Jul 14, 2020
2 parents e1a19d8 + 18b00d8 commit 03e1070
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 2 deletions.
9 changes: 9 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ Incompatible changes
Deprecated
----------

* C, parsing of pre-v3 style type directives and roles, along with the options
:confval:`c_allow_pre_v3` and :confval:`c_warn_on_allowed_pre_v3`.

Features added
--------------

Expand All @@ -24,6 +27,12 @@ Features added
* #7052: add ``:noindexentry:`` to the Python, C, C++, and Javascript domains.
Update the documentation to better reflect the relationship between this option
and the ``:noindex:`` option.
* #7899: C, add possibility of parsing of some pre-v3 style type directives and
roles and try to convert them to equivalent v3 directives/roles.
Set the new option :confval:`c_allow_pre_v3` to ``True`` to enable this.
The warnings printed from this functionality can be suppressed by setting
:confval:`c_warn_on_allowed_pre_v3`` to ``True``.
The functionality is immediately deprecated.

Bugs fixed
----------
Expand Down
17 changes: 17 additions & 0 deletions doc/usage/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2545,6 +2545,23 @@ Options for the C domain

.. versionadded:: 3.0

.. confval:: c_allow_pre_v3

A boolean (default ``False``) controlling whether to parse and try to
convert pre-v3 style type directives and type roles.

.. versionadded:: 3.2
.. deprecated:: 3.2
Use the directives and roles added in v3.

.. confval:: c_warn_on_allowed_pre_v3

A boolean (default ``True``) controlling whether to warn when a pre-v3
style type directive/role is parsed and converted.

.. versionadded:: 3.2
.. deprecated:: 3.2
Use the directives and roles added in v3.

.. _cpp-config:

Expand Down
80 changes: 78 additions & 2 deletions sphinx/domains/c.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from sphinx.addnodes import pending_xref
from sphinx.application import Sphinx
from sphinx.builders import Builder
from sphinx.deprecation import RemovedInSphinx50Warning
from sphinx.directives import ObjectDescription
from sphinx.domains import Domain, ObjType
from sphinx.environment import BuildEnvironment
Expand Down Expand Up @@ -2937,6 +2938,23 @@ def parser() -> ASTExpression:
init = ASTInitializer(initVal)
return ASTEnumerator(name, init)

def parse_pre_v3_type_definition(self) -> ASTDeclaration:
self.skip_ws()
declaration = None # type: Any
if self.skip_word('struct'):
typ = 'struct'
declaration = self._parse_struct()
elif self.skip_word('union'):
typ = 'union'
declaration = self._parse_union()
elif self.skip_word('enum'):
typ = 'enum'
declaration = self._parse_enum()
else:
self.fail("Could not parse pre-v3 type directive."
" Must start with 'struct', 'union', or 'enum'.")
return ASTDeclaration(typ, typ, declaration, False)

def parse_declaration(self, objectType: str, directiveType: str) -> ASTDeclaration:
if objectType not in ('function', 'member',
'macro', 'struct', 'union', 'enum', 'enumerator', 'type'):
Expand Down Expand Up @@ -3114,6 +3132,9 @@ def get_index_text(self, name: str) -> str:
def parse_definition(self, parser: DefinitionParser) -> ASTDeclaration:
return parser.parse_declaration(self.object_type, self.objtype)

def parse_pre_v3_type_definition(self, parser: DefinitionParser) -> ASTDeclaration:
return parser.parse_pre_v3_type_definition()

def describe_signature(self, signode: TextElement, ast: Any, options: Dict) -> None:
ast.describe_signature(signode, 'lastIsName', self.env, options)

Expand All @@ -3135,8 +3156,27 @@ def handle_signature(self, sig: str, signode: TextElement) -> ASTDeclaration:

parser = DefinitionParser(sig, location=signode, config=self.env.config)
try:
ast = self.parse_definition(parser)
parser.assert_end()
try:
ast = self.parse_definition(parser)
parser.assert_end()
except DefinitionError as eOrig:
if not self.env.config['c_allow_pre_v3']:
raise
if self.objtype != 'type':
raise
try:
ast = self.parse_pre_v3_type_definition(parser)
parser.assert_end()
except DefinitionError:
raise eOrig
self.object_type = ast.objectType # type: ignore
if self.env.config['c_warn_on_allowed_pre_v3']:
msg = "{}: Pre-v3 C type directive '.. c:type:: {}' converted to " \
"'.. c:{}:: {}'." \
"\nThe original parsing error was:\n{}"
msg = msg.format(RemovedInSphinx50Warning.__name__,
sig, ast.objectType, ast, eOrig)
logger.warning(msg, location=signode)
except DefinitionError as e:
logger.warning(e, location=signode)
# It is easier to assume some phony name than handling the error in
Expand Down Expand Up @@ -3445,6 +3485,39 @@ def process_link(self, env: BuildEnvironment, refnode: Element,
title = title[dot + 1:]
return title, target

def run(self) -> Tuple[List[Node], List[system_message]]:
if not self.env.config['c_allow_pre_v3']:
return super().run()

text = self.text.replace('\n', ' ')
parser = DefinitionParser(text, location=self.get_source_info(),
config=self.env.config)
try:
parser.parse_xref_object()
# it suceeded, so let it through
return super().run()
except DefinitionError as eOrig:
# try as if it was an c:expr
parser.pos = 0
try:
ast = parser.parse_expression()
except DefinitionError:
# that didn't go well, just default back
return super().run()
classes = ['xref', 'c', 'c-texpr']
parentSymbol = self.env.temp_data.get('cpp:parent_symbol', None)
if parentSymbol is None:
parentSymbol = self.env.domaindata['c']['root_symbol']
signode = nodes.inline(classes=classes)
ast.describe_signature(signode, 'markType', self.env, parentSymbol)

if self.env.config['c_warn_on_allowed_pre_v3']:
msg = "{}: Pre-v3 C type role ':c:type:`{}`' converted to ':c:expr:`{}`'."
msg += "\nThe original parsing error was:\n{}"
msg = msg.format(RemovedInSphinx50Warning.__name__, text, text, eOrig)
logger.warning(msg, location=self.get_source_info())
return [signode], []


class CExprRole(SphinxRole):
def __init__(self, asCode: bool) -> None:
Expand Down Expand Up @@ -3646,6 +3719,9 @@ def setup(app: Sphinx) -> Dict[str, Any]:
app.add_config_value("c_paren_attributes", [], 'env')
app.add_post_transform(AliasTransform)

app.add_config_value("c_allow_pre_v3", False, 'env')
app.add_config_value("c_warn_on_allowed_pre_v3", True, 'env')

return {
'version': 'builtin',
'env_version': 2,
Expand Down

0 comments on commit 03e1070

Please sign in to comment.