From f7a1d6635951a7cae814d2a38b29ee8bf05971d3 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Mon, 11 Jan 2021 20:27:53 +0100 Subject: [PATCH] C++, fix object types for xrefs Make them all work with intersphinx. Strengthen templateParam a bit. --- sphinx/domains/cpp.py | 43 +++---- .../roots/test-domain-cpp-intersphinx/conf.py | 4 + .../test-domain-cpp-intersphinx/index.rst | 112 ++++++++++++++++++ .../test-domain-cpp/roles-targets-ok.rst | 24 ++-- .../test-domain-cpp/roles-targets-warn.rst | 24 ++-- tests/test_domain_cpp.py | 70 ++++++++++- 6 files changed, 227 insertions(+), 50 deletions(-) create mode 100644 tests/roots/test-domain-cpp-intersphinx/conf.py create mode 100644 tests/roots/test-domain-cpp-intersphinx/index.rst diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index f6e746809..4d6e189a3 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -7251,14 +7251,18 @@ class CPPDomain(Domain): name = 'cpp' label = 'C++' object_types = { - 'class': ObjType(_('class'), 'class', 'type', 'identifier'), - 'union': ObjType(_('union'), 'union', 'type', 'identifier'), - 'function': ObjType(_('function'), 'function', 'func', 'type', 'identifier'), - 'member': ObjType(_('member'), 'member', 'var'), - 'type': ObjType(_('type'), 'type', 'identifier'), - 'concept': ObjType(_('concept'), 'concept', 'identifier'), - 'enum': ObjType(_('enum'), 'enum', 'type', 'identifier'), - 'enumerator': ObjType(_('enumerator'), 'enumerator') + 'class': ObjType(_('class'), 'class', 'struct', 'identifier', 'type'), + 'union': ObjType(_('union'), 'union', 'identifier', 'type'), + 'function': ObjType(_('function'), 'func', 'identifier', 'type'), + 'member': ObjType(_('member'), 'member', 'var', 'identifier'), + 'type': ObjType(_('type'), 'identifier', 'type'), + 'concept': ObjType(_('concept'), 'concept', 'identifier'), + 'enum': ObjType(_('enum'), 'enum', 'identifier', 'type'), + 'enumerator': ObjType(_('enumerator'), 'enumerator', 'identifier'), + # generated object types + 'functionParam': ObjType(_('function parameter'), 'identifier', 'member', 'var'), # noqa + 'templateParam': ObjType(_('template parameter'), + 'identifier', 'class', 'struct', 'union', 'member', 'var', 'type'), # noqa } directives = { @@ -7435,30 +7439,19 @@ class CPPDomain(Domain): if typ.startswith('cpp:'): typ = typ[4:] - origTyp = typ - if typ == 'func': - typ = 'function' - if typ == 'struct': - typ = 'class' declTyp = s.declaration.objectType def checkType() -> bool: - if typ == 'any' or typ == 'identifier': + if typ == 'any': return True - if declTyp == 'templateParam': - # TODO: perhaps this should be strengthened one day - return True - if declTyp == 'functionParam': - if typ == 'var' or typ == 'member': - return True objtypes = self.objtypes_for_role(typ) if objtypes: return declTyp in objtypes - print("Type is %s (originally: %s), declType is %s" % (typ, origTyp, declTyp)) + print("Type is %s, declaration type is %s" % (typ, declTyp)) assert False if not checkType(): logger.warning("cpp:%s targets a %s (%s).", - origTyp, s.declaration.objectType, + typ, s.declaration.objectType, s.get_full_nested_name(), location=node) @@ -7488,10 +7481,10 @@ class CPPDomain(Domain): if env.config.add_function_parentheses and typ == 'any': addParen += 1 # and now this stuff for operator() - if (env.config.add_function_parentheses and typ == 'function' and + if (env.config.add_function_parentheses and typ == 'func' and title.endswith('operator()')): addParen += 1 - if ((typ == 'any' or typ == 'function') and + if ((typ == 'any' or typ == 'func') and title.endswith('operator') and displayName.endswith('operator()')): addParen += 1 @@ -7500,7 +7493,7 @@ class CPPDomain(Domain): if env.config.add_function_parentheses: if typ == 'any' and displayName.endswith('()'): addParen += 1 - elif typ == 'function': + elif typ == 'func': if title.endswith('()') and not displayName.endswith('()'): title = title[:-2] else: diff --git a/tests/roots/test-domain-cpp-intersphinx/conf.py b/tests/roots/test-domain-cpp-intersphinx/conf.py new file mode 100644 index 000000000..c176af775 --- /dev/null +++ b/tests/roots/test-domain-cpp-intersphinx/conf.py @@ -0,0 +1,4 @@ +exclude_patterns = ['_build'] +extensions = [ + 'sphinx.ext.intersphinx', +] diff --git a/tests/roots/test-domain-cpp-intersphinx/index.rst b/tests/roots/test-domain-cpp-intersphinx/index.rst new file mode 100644 index 000000000..9ed9493ed --- /dev/null +++ b/tests/roots/test-domain-cpp-intersphinx/index.rst @@ -0,0 +1,112 @@ +.. cpp:type:: _class __class + + - :any:`_class` + - :cpp:any:`_class` + - :cpp:class:`_class` + - :cpp:struct:`_class` + - :cpp:type:`_class` + +.. cpp:type:: _struct __struct + + - :any:`_struct` + - :cpp:any:`_struct` + - :cpp:class:`_struct` + - :cpp:struct:`_struct` + - :cpp:type:`_struct` + +.. cpp:type:: _union __union + + - :any:`_union` + - :cpp:any:`_union` + - :cpp:union:`_union` + - :cpp:type:`_union` + +.. cpp:member:: void __function = _function + + - :any:`_function` + - :cpp:any:`_function` + - :cpp:func:`_function` + - :cpp:type:`_function` + +.. cpp:member:: void __member = _member + + - :any:`_member` + - :cpp:any:`_member` + - :cpp:member:`_member` + - :cpp:var:`_member` + +.. cpp:member:: void __var = _var + + - :any:`_var` + - :cpp:any:`_var` + - :cpp:member:`_var` + - :cpp:var:`_var` + +.. cpp:type:: _type __type + + - :any:`_type` + - :cpp:any:`_type` + - :cpp:type:`_type` + +.. cpp:function:: template<_concept T> void __concept() + + - :any:`_concept` + - :cpp:any:`_concept` + - :cpp:concept:`_concept` + +.. cpp:type:: _enum __enum + + - :any:`_enum` + - :cpp:any:`_enum` + - :cpp:enum:`_enum` + - :cpp:type:`_enum` + +.. cpp:type:: _enumStruct __enumStruct + + - :any:`_enumStruct` + - :cpp:any:`_enumStruct` + - :cpp:enum:`_enumStruct` + - :cpp:type:`_enumStruct` + +.. cpp:type:: _enumClass __enumClass + + - :any:`_enumClass` + - :cpp:any:`_enumClass` + - :cpp:enum:`_enumClass` + - :cpp:type:`_enumClass` + +.. cpp:member:: void __enumerator = _enumerator + + - :any:`_enumerator` + - :cpp:any:`_enumerator` + - :cpp:enumerator:`_enumerator` + +.. cpp:member:: void __scopedEnumerator = _enumStruct::_scopedEnumerator + + - :any:`_enumStruct::_scopedEnumerator` + - :cpp:any:`_enumStruct::_scopedEnumerator` + - :cpp:enumerator:`_enumStruct::_scopedEnumerator` + +.. cpp:member:: void __enumerator2 = _enum::_enumerator + + - :any:`_enum::_enumerator` + - :cpp:any:`_enum::_enumerator` + - :cpp:enumerator:`_enum::_enumerator` + +.. cpp:member:: void __functionParam = _functionParam::param + + - :any:`_functionParam::param` + - :cpp:any:`_functionParam::param` + - :cpp:member:`_functionParam::param` + - :cpp:var:`_functionParam::param` + +.. cpp:type:: _templateParam::TParam __templateParam + + - :any:`_templateParam::TParam` + - :cpp:any:`_templateParam::TParam` + - :cpp:type:`_templateParam::TParam` + - :cpp:member:`_templateParam::TParam` + - :cpp:var:`_templateParam::TParam` + - :cpp:class:`_templateParam::TParam` + - :cpp:struct:`_templateParam::TParam` + - :cpp:union:`_templateParam::TParam` diff --git a/tests/roots/test-domain-cpp/roles-targets-ok.rst b/tests/roots/test-domain-cpp/roles-targets-ok.rst index e70b9259f..783f7b985 100644 --- a/tests/roots/test-domain-cpp/roles-targets-ok.rst +++ b/tests/roots/test-domain-cpp/roles-targets-ok.rst @@ -123,37 +123,37 @@ :class:`TParamType` :struct:`TParamType` :union:`TParamType` - :func:`TParamType` + function :member:`TParamType` :var:`TParamType` :type:`TParamType` - :concept:`TParamType` - :enum:`TParamType` - :enumerator:`TParamType` + concept + enum + enumerator :cpp:any:`TParamVar` :class:`TParamVar` :struct:`TParamVar` :union:`TParamVar` - :func:`TParamVar` + function :member:`TParamVar` :var:`TParamVar` :type:`TParamVar` - :concept:`TParamVar` - :enum:`TParamVar` - :enumerator:`TParamVar` + concept + enum + enumerator :cpp:any:`TParamTemplate` :class:`TParamTemplate` :struct:`TParamTemplate` :union:`TParamTemplate` - :func:`TParamTemplate` + function :member:`TParamTemplate` :var:`TParamTemplate` :type:`TParamTemplate` - :concept:`TParamTemplate` - :enum:`TParamTemplate` - :enumerator:`TParamTemplate` + concept + enum + enumerator .. function:: void FunctionParams(int FunctionParam) diff --git a/tests/roots/test-domain-cpp/roles-targets-warn.rst b/tests/roots/test-domain-cpp/roles-targets-warn.rst index decebe170..57083ff15 100644 --- a/tests/roots/test-domain-cpp/roles-targets-warn.rst +++ b/tests/roots/test-domain-cpp/roles-targets-warn.rst @@ -114,35 +114,35 @@ class struct union - func + :func:`TParamType` member var type - concept - enum - enumerator + :concept:`TParamType` + :enum:`TParamType` + :enumerator:`TParamType` class struct union - func + :func:`TParamVar` member var type - concept - enum - enumerator + :concept:`TParamVar` + :enum:`TParamVar` + :enumerator:`TParamVar` class struct union - func + :func:`TParamTemplate` member var type - concept - enum - enumerator + :concept:`TParamTemplate` + :enum:`TParamTemplate` + :enumerator:`TParamTemplate` .. function:: void FunctionParams(int FunctionParam) diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index b867ffb68..690093f5c 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -9,6 +9,7 @@ """ import re +import zlib import pytest @@ -17,6 +18,7 @@ from sphinx import addnodes from sphinx.addnodes import desc from sphinx.domains.cpp import (DefinitionError, DefinitionParser, NoOldIdError, Symbol, _id_prefix, _max_id) +from sphinx.ext.intersphinx import load_mappings, normalize_intersphinx_mapping from sphinx.testing import restructuredtext from sphinx.testing.util import assert_node from sphinx.util import docutils @@ -1049,8 +1051,8 @@ def test_build_domain_cpp_misuse_of_roles(app, status, warning): ('concept', ['concept']), ('enum', ['type', 'enum']), ('enumerator', ['enumerator']), - ('tParam', ['class', 'struct', 'union', 'func', 'member', 'var', 'type', 'concept', 'enum', 'enumerator', 'functionParam']), ('functionParam', ['member', 'var']), + ('templateParam', ['class', 'struct', 'union', 'member', 'var', 'type']), ] warn = [] for targetType, roles in ok: @@ -1058,6 +1060,9 @@ def test_build_domain_cpp_misuse_of_roles(app, status, warning): for r in allRoles: if r not in roles: warn.append("WARNING: cpp:{} targets a {} (".format(r, txtTargetType)) + if targetType == 'templateParam': + warn.append("WARNING: cpp:{} targets a {} (".format(r, txtTargetType)) + warn.append("WARNING: cpp:{} targets a {} (".format(r, txtTargetType)) warn = list(sorted(warn)) for w in ws: assert "targets a" in w @@ -1250,3 +1255,66 @@ def test_mix_decl_duplicate(app, warning): assert "index.rst:3: WARNING: Duplicate C++ declaration, also defined at index:1." in ws[2] assert "Declaration is '.. cpp:struct:: A'." in ws[3] assert ws[4] == "" + + +@pytest.mark.sphinx(testroot='domain-cpp-intersphinx', confoverrides={'nitpicky': True}) +def test_intersphinx(tempdir, app, status, warning): + origSource = """\ +.. cpp:class:: _class +.. cpp:struct:: _struct +.. cpp:union:: _union +.. cpp:function:: void _function() +.. cpp:member:: int _member +.. cpp:var:: int _var +.. cpp:type:: _type +.. cpp:concept:: template _concept +.. cpp:enum:: _enum + + .. cpp:enumerator:: _enumerator + +.. cpp:enum-struct:: _enumStruct + + .. cpp:enumerator:: _scopedEnumerator + +.. cpp:enum-class:: _enumClass +.. cpp:function:: void _functionParam(int param) +.. cpp:function:: template void _templateParam() +""" # noqa + inv_file = tempdir / 'inventory' + inv_file.write_bytes(b'''\ +# Sphinx inventory version 2 +# Project: C Intersphinx Test +# Version: +# The remainder of this file is compressed using zlib. +''' + zlib.compress(b'''\ +_class cpp:class 1 index.html#_CPPv46$ - +_concept cpp:concept 1 index.html#_CPPv4I0E8$ - +_concept::T cpp:templateParam 1 index.html#_CPPv4I0E8_concept - +_enum cpp:enum 1 index.html#_CPPv45$ - +_enum::_enumerator cpp:enumerator 1 index.html#_CPPv4N5_enum11_enumeratorE - +_enumClass cpp:enum 1 index.html#_CPPv410$ - +_enumStruct cpp:enum 1 index.html#_CPPv411$ - +_enumStruct::_scopedEnumerator cpp:enumerator 1 index.html#_CPPv4N11_enumStruct17_scopedEnumeratorE - +_enumerator cpp:enumerator 1 index.html#_CPPv4N5_enum11_enumeratorE - +_function cpp:function 1 index.html#_CPPv49_functionv - +_functionParam cpp:function 1 index.html#_CPPv414_functionParami - +_functionParam::param cpp:functionParam 1 index.html#_CPPv414_functionParami - +_member cpp:member 1 index.html#_CPPv47$ - +_struct cpp:class 1 index.html#_CPPv47$ - +_templateParam cpp:function 1 index.html#_CPPv4I0E14_templateParamvv - +_templateParam::TParam cpp:templateParam 1 index.html#_CPPv4I0E14_templateParamvv - +_type cpp:type 1 index.html#_CPPv45$ - +_union cpp:union 1 index.html#_CPPv46$ - +_var cpp:member 1 index.html#_CPPv44$ - +''')) # noqa + app.config.intersphinx_mapping = { + 'https://localhost/intersphinx/cpp/': inv_file, + } + app.config.intersphinx_cache_limit = 0 + # load the inventory and check if it's done correctly + normalize_intersphinx_mapping(app, app.config) + load_mappings(app) + + app.builder.build_all() + ws = filter_warnings(warning, "index") + assert len(ws) == 0