Merge branch '2.3.2' into 2.0

This commit is contained in:
Takeshi KOMIYA 2020-02-09 15:29:10 +09:00
commit a17ad5cd39
6 changed files with 404 additions and 5 deletions

12
CHANGES
View File

@ -120,6 +120,18 @@ Features added
Bugs fixed Bugs fixed
---------- ----------
* C++:
- Don't crash when using the ``struct`` role in some cases.
- Don't warn when using the ``var``/``member`` role for function
parameters.
- Render call and braced-init expressions correctly.
* #7097: Filenames of images generated by
``sphinx.transforms.post_transforms.images.ImageConverter``
or its subclasses (used for latex build) are now sanitized,
to prevent broken paths
Testing Testing
-------- --------

View File

@ -3004,7 +3004,7 @@ class ASTParenExprList(ASTBase):
signode.append(nodes.Text(', ')) signode.append(nodes.Text(', '))
else: else:
first = False first = False
e.describe_signature(signode, mode, env, symbol) e.describe_signature(signode, mode, env, symbol)
signode.append(nodes.Text(')')) signode.append(nodes.Text(')'))
@ -3031,7 +3031,7 @@ class ASTBracedInitList(ASTBase):
signode.append(nodes.Text(', ')) signode.append(nodes.Text(', '))
else: else:
first = False first = False
e.describe_signature(signode, mode, env, symbol) e.describe_signature(signode, mode, env, symbol)
if self.trailingComma: if self.trailingComma:
signode.append(nodes.Text(',')) signode.append(nodes.Text(','))
signode.append(nodes.Text('}')) signode.append(nodes.Text('}'))
@ -6862,23 +6862,30 @@ class CPPDomain(Domain):
if typ.startswith('cpp:'): if typ.startswith('cpp:'):
typ = typ[4:] typ = typ[4:]
origTyp = typ
if typ == 'func': if typ == 'func':
typ = 'function' typ = 'function'
if typ == 'struct':
typ = 'class'
declTyp = s.declaration.objectType declTyp = s.declaration.objectType
def checkType(): def checkType():
if typ == 'any' or typ == 'identifier': if typ == 'any' or typ == 'identifier':
return True return True
if declTyp == 'templateParam': if declTyp == 'templateParam':
# TODO: perhaps this should be strengthened one day
return True return True
if declTyp == 'functionParam':
if typ == 'var' or typ == 'member':
return True
objtypes = self.objtypes_for_role(typ) objtypes = self.objtypes_for_role(typ)
if objtypes: if objtypes:
return declTyp in objtypes return declTyp in objtypes
print("Type is %s, declType is %s" % (typ, declTyp)) print("Type is %s (originally: %s), declType is %s" % (typ, origTyp, declTyp))
assert False assert False
if not checkType(): if not checkType():
warner.warn("cpp:%s targets a %s (%s)." warner.warn("cpp:%s targets a %s (%s)."
% (typ, s.declaration.objectType, % (origTyp, s.declaration.objectType,
s.get_full_nested_name())) s.get_full_nested_name()))
declaration = s.declaration declaration = s.declaration

View File

@ -9,6 +9,7 @@
""" """
import os import os
import re
from hashlib import sha1 from hashlib import sha1
from math import ceil from math import ceil
from typing import Any, Dict, List, Tuple from typing import Any, Dict, List, Tuple
@ -27,6 +28,7 @@ from sphinx.util.osutil import ensuredir, movefile
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
MAX_FILENAME_LEN = 32 MAX_FILENAME_LEN = 32
CRITICAL_PATH_CHAR_RE = re.compile('[:;<>|*" ]')
class BaseImageConverter(SphinxTransform): class BaseImageConverter(SphinxTransform):
@ -65,6 +67,7 @@ class ImageDownloader(BaseImageConverter):
if basename == '' or len(basename) > MAX_FILENAME_LEN: if basename == '' or len(basename) > MAX_FILENAME_LEN:
filename, ext = os.path.splitext(node['uri']) filename, ext = os.path.splitext(node['uri'])
basename = sha1(filename.encode()).hexdigest() + ext basename = sha1(filename.encode()).hexdigest() + ext
basename = re.sub(CRITICAL_PATH_CHAR_RE, "_", basename)
dirname = node['uri'].replace('://', '/').translate({ord("?"): "/", dirname = node['uri'].replace('://', '/').translate({ord("?"): "/",
ord("&"): "/"}) ord("&"): "/"})
@ -146,6 +149,7 @@ class DataURIExtractor(BaseImageConverter):
def get_filename_for(filename: str, mimetype: str) -> str: def get_filename_for(filename: str, mimetype: str) -> str:
basename = os.path.basename(filename) basename = os.path.basename(filename)
basename = re.sub(CRITICAL_PATH_CHAR_RE, "_", basename)
return os.path.splitext(basename)[0] + get_image_extension(mimetype) return os.path.splitext(basename)[0] + get_image_extension(mimetype)

View File

@ -0,0 +1,170 @@
.. default-domain:: cpp
.. namespace:: RolesTargetsOk
.. class:: Class
:cpp:any:`Class`
:class:`Class`
:struct:`Class`
union
func
member
var
:type:`Class`
concept
enum
enumerator
.. union:: Union
:cpp:any:`Union`
class
struct
:union:`Union`
func
member
var
:type:`Union`
concept
enum
enumerator
.. function:: void Function()
:cpp:any:`Function`
class
struct
union
:func:`Function`
member
var
:type:`Function`
concept
enum
enumerator
.. var:: int Variable
:cpp:any:`Variable`
class
struct
union
function
:member:`Variable`
:var:`Variables`
type
concept
enum
enumerator
.. type:: Type = void
:cpp:any:`Type`
class
struct
union
function
member
var
:type:`Type`
concept
enum
enumerator
.. concept:: template<typename T> Concept
:cpp:any:`Concept`
class
struct
union
function
member
var
type
:concept:`Concept`
enum
enumerator
.. enum-struct:: Enum
:cpp:any:`Enum`
class
struct
union
function
member
var
:type:`Enum`
concept
:enum:`Enum`
enumerator
.. enumerator:: Enumerator
:cpp:any:`Enumerator`
class
struct
union
function
member
var
type
concept
enum
:enumerator:`Enumerator`
.. class:: template<typename TParamType, \
int TParamVar, \
template<typename> typename TParamTemplate \
> ClassTemplate
:cpp:any:`TParamType`
:class:`TParamType`
:struct:`TParamType`
:union:`TParamType`
:func:`TParamType`
:member:`TParamType`
:var:`TParamType`
:type:`TParamType`
:concept:`TParamType`
:enum:`TParamType`
:enumerator:`TParamType`
:cpp:any:`TParamVar`
:class:`TParamVar`
:struct:`TParamVar`
:union:`TParamVar`
:func:`TParamVar`
:member:`TParamVar`
:var:`TParamVar`
:type:`TParamVar`
:concept:`TParamVar`
:enum:`TParamVar`
:enumerator:`TParamVar`
:cpp:any:`TParamTemplate`
:class:`TParamTemplate`
:struct:`TParamTemplate`
:union:`TParamTemplate`
:func:`TParamTemplate`
:member:`TParamTemplate`
:var:`TParamTemplate`
:type:`TParamTemplate`
:concept:`TParamTemplate`
:enum:`TParamTemplate`
:enumerator:`TParamTemplate`
.. function:: void FunctionParams(int FunctionParam)
:cpp:any:`FunctionParam`
class
struct
union
function
:member:`FunctionParam`
:var:`FunctionParam`
type
concept
enum
enumerator

View File

@ -0,0 +1,158 @@
.. default-domain:: cpp
.. namespace:: RolesTargetsWarn
.. class:: Class
class
struct
:union:`Class`
:func:`Class`
:member:`Class`
:var:`Class`
type
:concept:`Class`
:enum:`Class`
:enumerator:`Class`
.. union:: Union
:class:`Union`
:struct:`Union`
union
:func:`Union`
:member:`Union`
:var:`Union`
type
:concept:`Union`
:enum:`Union`
:enumerator:`Union`
.. function:: void Function()
:class:`Function`
:struct:`Function`
:union:`Function`
func
:member:`Function`
:var:`Function`
type
:concept:`Function`
:enum:`Function`
:enumerator:`Function`
.. var:: int Variable
:class:`Variable`
:struct:`Variable`
:union:`Variable`
:func:`Variable`
member
var
:type:`Variable`
:concept:`Variable`
:enum:`Variable`
:enumerator:`Variable`
.. type:: Type = void
:class:`Type`
:struct:`Type`
:union:`Type`
:func:`Type`
:member:`Type`
:var:`Type`
type
:concept:`Type`
:enum:`Type`
:enumerator:`Type`
.. concept:: template<typename T> Concept
:class:`Concept`
:struct:`Concept`
:union:`Concept`
:func:`Concept`
:member:`Concept`
:var:`Concept`
:type:`Concept`
concept
:enum:`Concept`
:enumerator:`Concept`
.. enum-struct:: Enum
:class:`Enum`
:struct:`Enum`
:union:`Enum`
:func:`Enum`
:member:`Enum`
:var:`Enum`
type
:concept:`Enum`
enum
:enumerator:`Enum`
.. enumerator:: Enumerator
:class:`Enumerator`
:struct:`Enumerator`
:union:`Enumerator`
:func:`Enumerator`
:member:`Enumerator`
:var:`Enumerator`
:type:`Enumerator`
:concept:`Enumerator`
:enum:`Enumerator`
enumerator
.. class:: template<typename TParamType, \
int TParamVar, \
template<typename> typename TParamTemplate \
> ClassTemplate
class
struct
union
func
member
var
type
concept
enum
enumerator
class
struct
union
func
member
var
type
concept
enum
enumerator
class
struct
union
func
member
var
type
concept
enum
enumerator
.. function:: void FunctionParams(int FunctionParam)
:class:`FunctionParam`
:struct:`FunctionParam`
:union:`FunctionParam`
:func:`FunctionParam`
member
var
:type:`FunctionParam`
:concept:`FunctionParam`
:enum:`FunctionParam`
:enumerator:`FunctionParam`

View File

@ -786,11 +786,59 @@ def test_xref_parsing():
# raise DefinitionError("") # raise DefinitionError("")
def filter_warnings(warning, file):
lines = warning.getvalue().split("\n");
res = [l for l in lines if "domain-cpp" 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))
for w in res:
print(w)
return res
@pytest.mark.sphinx(testroot='domain-cpp') @pytest.mark.sphinx(testroot='domain-cpp')
def test_build_domain_cpp_misuse_of_roles(app, status, warning): def test_build_domain_cpp_misuse_of_roles(app, status, warning):
app.builder.build_all() app.builder.build_all()
ws = filter_warnings(warning, "roles-targets-ok")
assert len(ws) == 0
# TODO: properly check for the warnings we expect ws = filter_warnings(warning, "roles-targets-warn")
# the roles that should be able to generate warnings:
allRoles = ['class', 'struct', 'union', 'func', 'member', 'var', 'type', 'concept', 'enum', 'enumerator']
ok = [ # targetType, okRoles
('class', ['class', 'struct', 'type']),
('union', ['union', 'type']),
('func', ['func', 'type']),
('member', ['member', 'var']),
('type', ['type']),
('concept', ['concept']),
('enum', ['type', 'enum']),
('enumerator', ['enumerator']),
('tParam', ['class', 'struct', 'union', 'func', 'member', 'var', 'type', 'concept', 'enum', 'enumerator', 'functionParam']),
('functionParam', ['member', 'var']),
]
warn = []
for targetType, roles in ok:
txtTargetType = "function" if targetType == "func" else targetType
for r in allRoles:
if r not in roles:
warn.append("WARNING: cpp:{} targets a {} (".format(r, txtTargetType))
warn = list(sorted(warn))
for w in ws:
assert "targets a" in w
ws = [w[w.index("WARNING:"):] for w in ws]
ws = list(sorted(ws))
print("Expected warnings:")
for w in warn:
print(w)
print("Actual warnings:")
for w in ws:
print(w)
for i in range(min(len(warn), len(ws))):
assert ws[i].startswith(warn[i])
assert len(ws) == len(warn)
@pytest.mark.skipif(docutils.__version_info__ < (0, 13), @pytest.mark.skipif(docutils.__version_info__ < (0, 13),