2022-02-19 21:05:56 -06:00
|
|
|
"""Tests the C++ Domain"""
|
2010-03-01 18:27:44 -06:00
|
|
|
|
2021-11-30 14:32:46 -06:00
|
|
|
import itertools
|
2015-12-27 01:29:07 -06:00
|
|
|
import re
|
2021-01-11 13:27:53 -06:00
|
|
|
import zlib
|
2015-12-27 01:29:07 -06:00
|
|
|
|
2017-01-05 09:46:42 -06:00
|
|
|
import pytest
|
2014-04-29 09:44:12 -05:00
|
|
|
|
2023-08-13 11:33:33 -05:00
|
|
|
import sphinx.domains.cpp
|
2015-10-13 08:05:42 -05:00
|
|
|
from sphinx import addnodes
|
2023-05-11 08:28:57 -05:00
|
|
|
from sphinx.addnodes import (
|
|
|
|
desc,
|
|
|
|
desc_content,
|
|
|
|
desc_name,
|
|
|
|
desc_parameter,
|
|
|
|
desc_parameterlist,
|
|
|
|
desc_sig_name,
|
|
|
|
desc_sig_space,
|
|
|
|
desc_signature,
|
|
|
|
desc_signature_line,
|
|
|
|
pending_xref,
|
|
|
|
)
|
2023-01-07 12:31:15 -06:00
|
|
|
from sphinx.domains.cpp import (
|
|
|
|
DefinitionError,
|
|
|
|
DefinitionParser,
|
|
|
|
NoOldIdError,
|
|
|
|
Symbol,
|
|
|
|
_id_prefix,
|
|
|
|
_max_id,
|
|
|
|
)
|
2021-01-11 13:27:53 -06:00
|
|
|
from sphinx.ext.intersphinx import load_mappings, normalize_intersphinx_mapping
|
2020-07-04 13:16:04 -05:00
|
|
|
from sphinx.testing import restructuredtext
|
|
|
|
from sphinx.testing.util import assert_node
|
2023-05-11 08:28:57 -05:00
|
|
|
from sphinx.writers.text import STDINDENT
|
2010-03-01 18:27:44 -06:00
|
|
|
|
2015-09-06 09:08:37 -05:00
|
|
|
|
2010-03-01 18:27:44 -06:00
|
|
|
def parse(name, string):
|
2018-09-11 08:48:35 -05:00
|
|
|
class Config:
|
2016-08-05 17:08:02 -05:00
|
|
|
cpp_id_attributes = ["id_attr"]
|
|
|
|
cpp_paren_attributes = ["paren_attr"]
|
2020-04-13 03:09:41 -05:00
|
|
|
parser = DefinitionParser(string, location=None, config=Config())
|
2017-12-20 02:05:34 -06:00
|
|
|
parser.allowFallbackExpressionParsing = False
|
2019-01-09 12:27:54 -06:00
|
|
|
ast = parser.parse_declaration(name, name)
|
2017-03-19 22:19:48 -05:00
|
|
|
parser.assert_end()
|
2015-03-02 13:27:37 -06:00
|
|
|
# The scopedness would usually have been set by CPPEnumObject
|
|
|
|
if name == "enum":
|
2015-09-06 09:08:37 -05:00
|
|
|
ast.scoped = None # simulate unscoped enum
|
2015-03-02 13:27:37 -06:00
|
|
|
return ast
|
2014-07-23 18:40:48 -05:00
|
|
|
|
2015-09-06 09:08:37 -05:00
|
|
|
|
2020-05-16 04:52:42 -05:00
|
|
|
def _check(name, input, idDict, output, key, asTextOutput):
|
|
|
|
if key is None:
|
|
|
|
key = name
|
|
|
|
key += ' '
|
|
|
|
if name in ('function', 'member'):
|
|
|
|
inputActual = input
|
|
|
|
outputAst = output
|
|
|
|
outputAsText = output
|
|
|
|
else:
|
|
|
|
inputActual = input.format(key='')
|
|
|
|
outputAst = output.format(key='')
|
|
|
|
outputAsText = output.format(key=key)
|
|
|
|
if asTextOutput is not None:
|
|
|
|
outputAsText = asTextOutput
|
|
|
|
|
2014-07-23 18:40:48 -05:00
|
|
|
# first a simple check of the AST
|
2020-05-16 04:52:42 -05:00
|
|
|
ast = parse(name, inputActual)
|
2018-12-15 22:13:28 -06:00
|
|
|
res = str(ast)
|
2020-05-16 04:52:42 -05:00
|
|
|
if res != outputAst:
|
2015-09-06 13:34:01 -05:00
|
|
|
print("")
|
2018-12-16 11:55:01 -06:00
|
|
|
print("Input: ", input)
|
2014-08-10 04:59:22 -05:00
|
|
|
print("Result: ", res)
|
2020-05-16 04:52:42 -05:00
|
|
|
print("Expected: ", outputAst)
|
2023-08-13 14:07:28 -05:00
|
|
|
raise DefinitionError
|
2020-10-11 04:31:46 -05:00
|
|
|
rootSymbol = Symbol(None, None, None, None, None, None, None)
|
|
|
|
symbol = rootSymbol.add_declaration(ast, docname="TestDoc", line=42)
|
2015-10-13 08:05:42 -05:00
|
|
|
parentNode = addnodes.desc()
|
|
|
|
signode = addnodes.desc_signature(input, '')
|
|
|
|
parentNode += signode
|
2017-01-14 09:52:08 -06:00
|
|
|
ast.describe_signature(signode, 'lastIsName', symbol, options={})
|
2020-05-16 04:52:42 -05:00
|
|
|
resAsText = parentNode.astext()
|
|
|
|
if resAsText != outputAsText:
|
|
|
|
print("")
|
|
|
|
print("Input: ", input)
|
|
|
|
print("astext(): ", resAsText)
|
|
|
|
print("Expected: ", outputAsText)
|
2021-03-16 14:02:26 -05:00
|
|
|
print("Node:", parentNode)
|
2023-08-13 14:07:28 -05:00
|
|
|
raise DefinitionError
|
2015-03-05 03:51:28 -06:00
|
|
|
|
2017-03-21 06:10:41 -05:00
|
|
|
idExpected = [None]
|
|
|
|
for i in range(1, _max_id + 1):
|
|
|
|
if i in idDict:
|
|
|
|
idExpected.append(idDict[i])
|
|
|
|
else:
|
|
|
|
idExpected.append(idExpected[i - 1])
|
|
|
|
idActual = [None]
|
|
|
|
for i in range(1, _max_id + 1):
|
|
|
|
try:
|
|
|
|
id = ast.get_id(version=i)
|
|
|
|
assert id is not None
|
|
|
|
idActual.append(id[len(_id_prefix[i]):])
|
|
|
|
except NoOldIdError:
|
|
|
|
idActual.append(None)
|
|
|
|
|
|
|
|
res = [True]
|
|
|
|
for i in range(1, _max_id + 1):
|
|
|
|
res.append(idExpected[i] == idActual[i])
|
|
|
|
|
|
|
|
if not all(res):
|
2018-12-16 11:55:01 -06:00
|
|
|
print("input: %s" % input.rjust(20))
|
2017-03-21 06:10:41 -05:00
|
|
|
for i in range(1, _max_id + 1):
|
|
|
|
if res[i]:
|
|
|
|
continue
|
|
|
|
print("Error in id version %d." % i)
|
2018-12-16 11:55:01 -06:00
|
|
|
print("result: %s" % idActual[i])
|
|
|
|
print("expected: %s" % idExpected[i])
|
2015-03-02 13:27:37 -06:00
|
|
|
print(rootSymbol.dump(0))
|
2023-08-13 14:07:28 -05:00
|
|
|
raise DefinitionError
|
2010-03-01 18:27:44 -06:00
|
|
|
|
2015-09-06 09:08:37 -05:00
|
|
|
|
2020-05-16 04:52:42 -05:00
|
|
|
def check(name, input, idDict, output=None, key=None, asTextOutput=None):
|
2020-04-17 17:26:10 -05:00
|
|
|
if output is None:
|
|
|
|
output = input
|
|
|
|
# First, check without semicolon
|
2020-05-16 04:52:42 -05:00
|
|
|
_check(name, input, idDict, output, key, asTextOutput)
|
2020-04-17 17:26:10 -05:00
|
|
|
# Second, check with semicolon
|
2020-05-16 04:52:42 -05:00
|
|
|
_check(name, input + ' ;', idDict, output + ';', key,
|
|
|
|
asTextOutput + ';' if asTextOutput is not None else None)
|
2020-04-17 17:26:10 -05:00
|
|
|
|
|
|
|
|
2023-08-13 11:33:33 -05:00
|
|
|
@pytest.mark.parametrize(('type_', 'id_v2'),
|
|
|
|
sphinx.domains.cpp._id_fundamental_v2.items())
|
|
|
|
def test_domain_cpp_ast_fundamental_types(type_, id_v2):
|
2018-09-23 11:36:25 -05:00
|
|
|
# see https://en.cppreference.com/w/cpp/language/types
|
2023-08-13 11:33:33 -05:00
|
|
|
def make_id_v1():
|
|
|
|
if type_ == 'decltype(auto)':
|
|
|
|
return None
|
|
|
|
id_ = type_.replace(" ", "-").replace("long", "l")
|
|
|
|
if "__int" not in type_:
|
|
|
|
id_ = id_.replace("int", "i")
|
|
|
|
id_ = id_.replace("bool", "b").replace("char", "c")
|
|
|
|
id_ = id_.replace("wc_t", "wchar_t").replace("c16_t", "char16_t")
|
|
|
|
id_ = id_.replace("c8_t", "char8_t")
|
|
|
|
id_ = id_.replace("c32_t", "char32_t")
|
|
|
|
return f"f__{id_}"
|
|
|
|
|
|
|
|
def make_id_v2():
|
|
|
|
id_ = id_v2
|
|
|
|
if type_ == "std::nullptr_t":
|
|
|
|
id_ = "NSt9nullptr_tE"
|
|
|
|
return f"1f{id_}"
|
|
|
|
|
|
|
|
id1 = make_id_v1()
|
|
|
|
id2 = make_id_v2()
|
|
|
|
|
|
|
|
input = f"void f({type_.replace(' ', ' ')} arg)"
|
|
|
|
output = f"void f({type_} arg)"
|
|
|
|
|
|
|
|
check("function", input, {1: id1, 2: id2}, output=output)
|
|
|
|
if ' ' in type_:
|
|
|
|
# try permutations of all components
|
|
|
|
tcs = type_.split()
|
|
|
|
for p in itertools.permutations(tcs):
|
|
|
|
input = f"void f({' '.join(p)} arg)"
|
|
|
|
check("function", input, {1: id1, 2: id2})
|
2015-12-02 13:00:28 -06:00
|
|
|
|
|
|
|
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_ast_expressions():
|
2019-01-06 05:02:22 -06:00
|
|
|
def exprCheck(expr, id, id4=None):
|
2017-03-19 22:19:48 -05:00
|
|
|
ids = 'IE1CIA%s_1aE'
|
2020-05-16 04:52:42 -05:00
|
|
|
# call .format() on the expr to unescape double curly braces
|
|
|
|
idDict = {2: ids % expr.format(), 3: ids % id}
|
2019-01-06 05:02:22 -06:00
|
|
|
if id4 is not None:
|
|
|
|
idDict[4] = ids % id4
|
2020-05-16 04:52:42 -05:00
|
|
|
check('class', 'template<> {key}C<a[%s]>' % expr, idDict)
|
2020-03-16 08:10:25 -05:00
|
|
|
|
|
|
|
class Config:
|
|
|
|
cpp_id_attributes = ["id_attr"]
|
|
|
|
cpp_paren_attributes = ["paren_attr"]
|
|
|
|
|
2020-03-17 06:56:09 -05:00
|
|
|
parser = DefinitionParser(expr, location=None,
|
|
|
|
config=Config())
|
2020-03-16 08:10:25 -05:00
|
|
|
parser.allowFallbackExpressionParsing = False
|
|
|
|
ast = parser.parse_expression()
|
|
|
|
res = str(ast)
|
|
|
|
if res != expr:
|
|
|
|
print("")
|
|
|
|
print("Input: ", expr)
|
|
|
|
print("Result: ", res)
|
2023-08-13 14:07:28 -05:00
|
|
|
raise DefinitionError
|
2020-06-02 11:14:04 -05:00
|
|
|
displayString = ast.get_display_string()
|
|
|
|
if res != displayString:
|
|
|
|
# note: if the expression contains an anon name then this will trigger a falsely
|
|
|
|
print("")
|
|
|
|
print("Input: ", expr)
|
|
|
|
print("Result: ", res)
|
|
|
|
print("Display: ", displayString)
|
2023-08-13 14:07:28 -05:00
|
|
|
raise DefinitionError
|
2020-06-02 11:14:04 -05:00
|
|
|
|
2017-03-19 22:19:48 -05:00
|
|
|
# primary
|
|
|
|
exprCheck('nullptr', 'LDnE')
|
|
|
|
exprCheck('true', 'L1E')
|
|
|
|
exprCheck('false', 'L0E')
|
2021-06-24 14:12:26 -05:00
|
|
|
ints = ['5', '0', '075', '0x0123456789ABCDEF', '0XF', '0b1', '0B1',
|
|
|
|
"0b0'1'0", "00'1'2", "0x0'1'2", "1'2'3"]
|
2017-11-26 05:45:27 -06:00
|
|
|
unsignedSuffix = ['', 'u', 'U']
|
|
|
|
longSuffix = ['', 'l', 'L', 'll', 'LL']
|
|
|
|
for i in ints:
|
|
|
|
for u in unsignedSuffix:
|
|
|
|
for l in longSuffix:
|
2017-12-23 06:20:32 -06:00
|
|
|
expr = i + u + l
|
2021-06-28 12:30:59 -05:00
|
|
|
exprCheck(expr, 'L' + expr.replace("'", "") + 'E')
|
2017-12-23 06:20:32 -06:00
|
|
|
expr = i + l + u
|
2021-06-28 12:30:59 -05:00
|
|
|
exprCheck(expr, 'L' + expr.replace("'", "") + 'E')
|
2020-04-27 08:01:09 -05:00
|
|
|
decimalFloats = ['5e42', '5e+42', '5e-42',
|
2020-11-15 02:03:26 -06:00
|
|
|
'5.', '5.e42', '5.e+42', '5.e-42',
|
|
|
|
'.5', '.5e42', '.5e+42', '.5e-42',
|
2021-06-24 14:12:26 -05:00
|
|
|
'5.0', '5.0e42', '5.0e+42', '5.0e-42',
|
|
|
|
"1'2'3e7'8'9", "1'2'3.e7'8'9",
|
|
|
|
".4'5'6e7'8'9", "1'2'3.4'5'6e7'8'9"]
|
2020-04-27 08:01:09 -05:00
|
|
|
hexFloats = ['ApF', 'Ap+F', 'Ap-F',
|
|
|
|
'A.', 'A.pF', 'A.p+F', 'A.p-F',
|
|
|
|
'.A', '.ApF', '.Ap+F', '.Ap-F',
|
2021-06-24 14:12:26 -05:00
|
|
|
'A.B', 'A.BpF', 'A.Bp+F', 'A.Bp-F',
|
|
|
|
"A'B'Cp1'2'3", "A'B'C.p1'2'3",
|
|
|
|
".D'E'Fp1'2'3", "A'B'C.D'E'Fp1'2'3"]
|
2017-11-26 05:45:27 -06:00
|
|
|
for suffix in ['', 'f', 'F', 'l', 'L']:
|
2020-04-27 08:01:09 -05:00
|
|
|
for e in decimalFloats:
|
2018-12-16 09:56:55 -06:00
|
|
|
expr = e + suffix
|
2021-06-28 12:30:59 -05:00
|
|
|
exprCheck(expr, 'L' + expr.replace("'", "") + 'E')
|
2020-04-27 08:01:09 -05:00
|
|
|
for e in hexFloats:
|
2018-12-16 09:56:55 -06:00
|
|
|
expr = "0x" + e + suffix
|
2021-06-28 12:30:59 -05:00
|
|
|
exprCheck(expr, 'L' + expr.replace("'", "") + 'E')
|
2017-11-26 05:45:27 -06:00
|
|
|
exprCheck('"abc\\"cba"', 'LA8_KcE') # string
|
2018-01-17 09:12:30 -06:00
|
|
|
exprCheck('this', 'fpT')
|
2018-08-10 15:13:18 -05:00
|
|
|
# character literals
|
2020-04-27 08:01:09 -05:00
|
|
|
charPrefixAndIds = [('', 'c'), ('u8', 'c'), ('u', 'Ds'), ('U', 'Di'), ('L', 'w')]
|
|
|
|
chars = [('a', '97'), ('\\n', '10'), ('\\012', '10'), ('\\0', '0'),
|
|
|
|
('\\x0a', '10'), ('\\x0A', '10'), ('\\u0a42', '2626'), ('\\u0A42', '2626'),
|
|
|
|
('\\U0001f34c', '127820'), ('\\U0001F34C', '127820')]
|
|
|
|
for p, t in charPrefixAndIds:
|
|
|
|
for c, val in chars:
|
2022-10-17 09:54:59 -05:00
|
|
|
exprCheck(f"{p}'{c}'", t + val)
|
2020-04-27 08:01:09 -05:00
|
|
|
# user-defined literals
|
|
|
|
for i in ints:
|
2021-06-28 12:30:59 -05:00
|
|
|
exprCheck(i + '_udl', 'clL_Zli4_udlEL' + i.replace("'", "") + 'EE')
|
|
|
|
exprCheck(i + 'uludl', 'clL_Zli5uludlEL' + i.replace("'", "") + 'EE')
|
2020-04-27 08:01:09 -05:00
|
|
|
for f in decimalFloats:
|
2021-06-28 12:30:59 -05:00
|
|
|
exprCheck(f + '_udl', 'clL_Zli4_udlEL' + f.replace("'", "") + 'EE')
|
|
|
|
exprCheck(f + 'fudl', 'clL_Zli4fudlEL' + f.replace("'", "") + 'EE')
|
2020-04-27 08:01:09 -05:00
|
|
|
for f in hexFloats:
|
2021-06-28 12:30:59 -05:00
|
|
|
exprCheck('0x' + f + '_udl', 'clL_Zli4_udlEL0x' + f.replace("'", "") + 'EE')
|
2020-04-27 08:01:09 -05:00
|
|
|
for p, t in charPrefixAndIds:
|
|
|
|
for c, val in chars:
|
2022-10-17 09:54:59 -05:00
|
|
|
exprCheck(f"{p}'{c}'_udl", 'clL_Zli4_udlE' + t + val + 'E')
|
2020-04-27 08:01:09 -05:00
|
|
|
exprCheck('"abc"_udl', 'clL_Zli4_udlELA3_KcEE')
|
|
|
|
# from issue #7294
|
|
|
|
exprCheck('6.62607015e-34q_J', 'clL_Zli3q_JEL6.62607015e-34EE')
|
|
|
|
|
|
|
|
# fold expressions, paren, name
|
2019-01-06 05:02:22 -06:00
|
|
|
exprCheck('(... + Ns)', '(... + Ns)', id4='flpl2Ns')
|
|
|
|
exprCheck('(Ns + ...)', '(Ns + ...)', id4='frpl2Ns')
|
|
|
|
exprCheck('(Ns + ... + 0)', '(Ns + ... + 0)', id4='fLpl2NsL0E')
|
2017-03-19 22:19:48 -05:00
|
|
|
exprCheck('(5)', 'L5E')
|
|
|
|
exprCheck('C', '1C')
|
|
|
|
# postfix
|
|
|
|
exprCheck('A(2)', 'cl1AL2EE')
|
|
|
|
exprCheck('A[2]', 'ix1AL2E')
|
|
|
|
exprCheck('a.b.c', 'dtdt1a1b1c')
|
|
|
|
exprCheck('a->b->c', 'ptpt1a1b1c')
|
|
|
|
exprCheck('i++', 'pp1i')
|
|
|
|
exprCheck('i--', 'mm1i')
|
2018-01-17 05:35:33 -06:00
|
|
|
exprCheck('dynamic_cast<T&>(i)++', 'ppdcR1T1i')
|
|
|
|
exprCheck('static_cast<T&>(i)++', 'ppscR1T1i')
|
|
|
|
exprCheck('reinterpret_cast<T&>(i)++', 'pprcR1T1i')
|
|
|
|
exprCheck('const_cast<T&>(i)++', 'ppccR1T1i')
|
|
|
|
exprCheck('typeid(T).name', 'dtti1T4name')
|
|
|
|
exprCheck('typeid(a + b).name', 'dttepl1a1b4name')
|
2017-03-19 22:19:48 -05:00
|
|
|
# unary
|
|
|
|
exprCheck('++5', 'pp_L5E')
|
|
|
|
exprCheck('--5', 'mm_L5E')
|
|
|
|
exprCheck('*5', 'deL5E')
|
|
|
|
exprCheck('&5', 'adL5E')
|
|
|
|
exprCheck('+5', 'psL5E')
|
|
|
|
exprCheck('-5', 'ngL5E')
|
|
|
|
exprCheck('!5', 'ntL5E')
|
2020-03-24 11:26:02 -05:00
|
|
|
exprCheck('not 5', 'ntL5E')
|
2017-03-19 22:19:48 -05:00
|
|
|
exprCheck('~5', 'coL5E')
|
2020-03-24 11:26:02 -05:00
|
|
|
exprCheck('compl 5', 'coL5E')
|
2017-11-26 13:32:24 -06:00
|
|
|
exprCheck('sizeof...(a)', 'sZ1a')
|
|
|
|
exprCheck('sizeof(T)', 'st1T')
|
|
|
|
exprCheck('sizeof -42', 'szngL42E')
|
|
|
|
exprCheck('alignof(T)', 'at1T')
|
|
|
|
exprCheck('noexcept(-42)', 'nxngL42E')
|
2018-08-17 06:49:44 -05:00
|
|
|
# new-expression
|
|
|
|
exprCheck('new int', 'nw_iE')
|
|
|
|
exprCheck('new volatile int', 'nw_ViE')
|
|
|
|
exprCheck('new int[42]', 'nw_AL42E_iE')
|
|
|
|
exprCheck('new int()', 'nw_ipiE')
|
|
|
|
exprCheck('new int(5, 42)', 'nw_ipiL5EL42EE')
|
2019-01-12 07:30:00 -06:00
|
|
|
exprCheck('::new int', 'nw_iE')
|
2020-05-16 04:52:42 -05:00
|
|
|
exprCheck('new int{{}}', 'nw_iilE')
|
|
|
|
exprCheck('new int{{5, 42}}', 'nw_iilL5EL42EE')
|
2018-08-17 06:49:44 -05:00
|
|
|
# delete-expression
|
2018-08-15 03:08:31 -05:00
|
|
|
exprCheck('delete p', 'dl1p')
|
|
|
|
exprCheck('delete [] p', 'da1p')
|
|
|
|
exprCheck('::delete p', 'dl1p')
|
|
|
|
exprCheck('::delete [] p', 'da1p')
|
2017-03-19 22:19:48 -05:00
|
|
|
# cast
|
|
|
|
exprCheck('(int)2', 'cviL2E')
|
|
|
|
# binary op
|
|
|
|
exprCheck('5 || 42', 'ooL5EL42E')
|
2020-03-24 11:26:02 -05:00
|
|
|
exprCheck('5 or 42', 'ooL5EL42E')
|
2017-03-19 22:19:48 -05:00
|
|
|
exprCheck('5 && 42', 'aaL5EL42E')
|
2020-03-24 11:26:02 -05:00
|
|
|
exprCheck('5 and 42', 'aaL5EL42E')
|
2017-03-19 22:19:48 -05:00
|
|
|
exprCheck('5 | 42', 'orL5EL42E')
|
2020-03-24 11:26:02 -05:00
|
|
|
exprCheck('5 bitor 42', 'orL5EL42E')
|
2017-03-19 22:19:48 -05:00
|
|
|
exprCheck('5 ^ 42', 'eoL5EL42E')
|
2020-03-24 11:26:02 -05:00
|
|
|
exprCheck('5 xor 42', 'eoL5EL42E')
|
2017-03-19 22:19:48 -05:00
|
|
|
exprCheck('5 & 42', 'anL5EL42E')
|
2020-03-24 11:26:02 -05:00
|
|
|
exprCheck('5 bitand 42', 'anL5EL42E')
|
2017-03-19 22:19:48 -05:00
|
|
|
# ['==', '!=']
|
|
|
|
exprCheck('5 == 42', 'eqL5EL42E')
|
|
|
|
exprCheck('5 != 42', 'neL5EL42E')
|
2020-03-24 11:26:02 -05:00
|
|
|
exprCheck('5 not_eq 42', 'neL5EL42E')
|
2021-03-02 13:22:22 -06:00
|
|
|
# ['<=', '>=', '<', '>', '<=>']
|
2017-03-19 22:19:48 -05:00
|
|
|
exprCheck('5 <= 42', 'leL5EL42E')
|
2020-03-16 08:10:25 -05:00
|
|
|
exprCheck('A <= 42', 'le1AL42E')
|
2017-03-19 22:19:48 -05:00
|
|
|
exprCheck('5 >= 42', 'geL5EL42E')
|
|
|
|
exprCheck('5 < 42', 'ltL5EL42E')
|
2020-03-16 08:10:25 -05:00
|
|
|
exprCheck('A < 42', 'lt1AL42E')
|
2017-03-19 22:19:48 -05:00
|
|
|
exprCheck('5 > 42', 'gtL5EL42E')
|
2021-03-02 13:22:22 -06:00
|
|
|
exprCheck('A > 42', 'gt1AL42E')
|
|
|
|
exprCheck('5 <=> 42', 'ssL5EL42E')
|
|
|
|
exprCheck('A <=> 42', 'ss1AL42E')
|
2017-03-19 22:19:48 -05:00
|
|
|
# ['<<', '>>']
|
|
|
|
exprCheck('5 << 42', 'lsL5EL42E')
|
2020-03-16 08:10:25 -05:00
|
|
|
exprCheck('A << 42', 'ls1AL42E')
|
2017-03-19 22:19:48 -05:00
|
|
|
exprCheck('5 >> 42', 'rsL5EL42E')
|
|
|
|
# ['+', '-']
|
|
|
|
exprCheck('5 + 42', 'plL5EL42E')
|
|
|
|
exprCheck('5 - 42', 'miL5EL42E')
|
|
|
|
# ['*', '/', '%']
|
|
|
|
exprCheck('5 * 42', 'mlL5EL42E')
|
|
|
|
exprCheck('5 / 42', 'dvL5EL42E')
|
|
|
|
exprCheck('5 % 42', 'rmL5EL42E')
|
|
|
|
# ['.*', '->*']
|
|
|
|
exprCheck('5 .* 42', 'dsL5EL42E')
|
|
|
|
exprCheck('5 ->* 42', 'pmL5EL42E')
|
|
|
|
# conditional
|
2022-03-27 03:41:25 -05:00
|
|
|
exprCheck('5 ? 7 : 3', 'quL5EL7EL3E')
|
2017-03-19 22:19:48 -05:00
|
|
|
# assignment
|
|
|
|
exprCheck('a = 5', 'aS1aL5E')
|
|
|
|
exprCheck('a *= 5', 'mL1aL5E')
|
|
|
|
exprCheck('a /= 5', 'dV1aL5E')
|
|
|
|
exprCheck('a %= 5', 'rM1aL5E')
|
|
|
|
exprCheck('a += 5', 'pL1aL5E')
|
|
|
|
exprCheck('a -= 5', 'mI1aL5E')
|
|
|
|
exprCheck('a >>= 5', 'rS1aL5E')
|
|
|
|
exprCheck('a <<= 5', 'lS1aL5E')
|
|
|
|
exprCheck('a &= 5', 'aN1aL5E')
|
2020-03-24 11:26:02 -05:00
|
|
|
exprCheck('a and_eq 5', 'aN1aL5E')
|
2017-03-19 22:19:48 -05:00
|
|
|
exprCheck('a ^= 5', 'eO1aL5E')
|
2020-03-24 11:26:02 -05:00
|
|
|
exprCheck('a xor_eq 5', 'eO1aL5E')
|
2017-03-19 22:19:48 -05:00
|
|
|
exprCheck('a |= 5', 'oR1aL5E')
|
2020-03-24 11:26:02 -05:00
|
|
|
exprCheck('a or_eq 5', 'oR1aL5E')
|
2020-05-16 04:52:42 -05:00
|
|
|
exprCheck('a = {{1, 2, 3}}', 'aS1ailL1EL2EL3EE')
|
2022-03-27 04:41:15 -05:00
|
|
|
# complex assignment and conditional
|
|
|
|
exprCheck('5 = 6 = 7', 'aSL5EaSL6EL7E')
|
|
|
|
exprCheck('5 = 6 ? 7 = 8 : 3', 'aSL5EquL6EaSL7EL8EL3E')
|
2020-03-25 05:00:24 -05:00
|
|
|
# comma operator
|
|
|
|
exprCheck('a, 5', 'cm1aL5E')
|
2017-03-19 22:19:48 -05:00
|
|
|
|
|
|
|
# Additional tests
|
|
|
|
# a < expression that starts with something that could be a template
|
|
|
|
exprCheck('A < 42', 'lt1AL42E')
|
|
|
|
check('function', 'template<> void f(A<B, 2> &v)',
|
2019-01-05 11:43:36 -06:00
|
|
|
{2: "IE1fR1AI1BX2EE", 3: "IE1fR1AI1BXL2EEE", 4: "IE1fvR1AI1BXL2EEE"})
|
2017-03-28 08:29:30 -05:00
|
|
|
exprCheck('A<1>::value', 'N1AIXL1EEE5valueE')
|
2020-05-16 04:52:42 -05:00
|
|
|
check('class', "template<int T = 42> {key}A", {2: "I_iE1A"})
|
|
|
|
check('enumerator', '{key}A = std::numeric_limits<unsigned long>::max()', {2: "1A"})
|
2017-03-19 22:19:48 -05:00
|
|
|
|
2017-12-28 09:50:32 -06:00
|
|
|
exprCheck('operator()()', 'clclE')
|
|
|
|
exprCheck('operator()<int>()', 'clclIiEE')
|
|
|
|
|
2018-05-22 20:58:39 -05:00
|
|
|
# pack expansion
|
|
|
|
exprCheck('a(b(c, 1 + d...)..., e(f..., g))', 'cl1aspcl1b1cspplL1E1dEcl1esp1f1gEE')
|
|
|
|
|
2017-03-19 22:19:48 -05:00
|
|
|
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_ast_type_definitions():
|
2020-05-16 04:52:42 -05:00
|
|
|
check("type", "public bool b", {1: "b", 2: "1b"}, "{key}bool b", key='typedef')
|
|
|
|
check("type", "{key}bool A::b", {1: "A::b", 2: "N1A1bE"}, key='typedef')
|
|
|
|
check("type", "{key}bool *b", {1: "b", 2: "1b"}, key='typedef')
|
|
|
|
check("type", "{key}bool *const b", {1: "b", 2: "1b"}, key='typedef')
|
|
|
|
check("type", "{key}bool *volatile const b", {1: "b", 2: "1b"}, key='typedef')
|
|
|
|
check("type", "{key}bool *volatile const b", {1: "b", 2: "1b"}, key='typedef')
|
|
|
|
check("type", "{key}bool *volatile const *b", {1: "b", 2: "1b"}, key='typedef')
|
|
|
|
check("type", "{key}bool &b", {1: "b", 2: "1b"}, key='typedef')
|
|
|
|
check("type", "{key}bool b[]", {1: "b", 2: "1b"}, key='typedef')
|
|
|
|
check("type", "{key}std::pair<int, int> coord", {1: "coord", 2: "5coord"}, key='typedef')
|
|
|
|
check("type", "{key}long long int foo", {1: "foo", 2: "3foo"}, key='typedef')
|
|
|
|
check("type", '{key}std::vector<std::pair<std::string, long long>> module::blah',
|
|
|
|
{1: "module::blah", 2: "N6module4blahE"}, key='typedef')
|
|
|
|
check("type", "{key}std::function<void()> F", {1: "F", 2: "1F"}, key='typedef')
|
|
|
|
check("type", "{key}std::function<R(A1, A2)> F", {1: "F", 2: "1F"}, key='typedef')
|
|
|
|
check("type", "{key}std::function<R(A1, A2, A3)> F", {1: "F", 2: "1F"}, key='typedef')
|
|
|
|
check("type", "{key}std::function<R(A1, A2, A3, As...)> F", {1: "F", 2: "1F"}, key='typedef')
|
|
|
|
check("type", "{key}MyContainer::const_iterator",
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "MyContainer::const_iterator", 2: "N11MyContainer14const_iteratorE"})
|
2014-10-09 09:53:33 -05:00
|
|
|
check("type",
|
|
|
|
"public MyContainer::const_iterator",
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "MyContainer::const_iterator", 2: "N11MyContainer14const_iteratorE"},
|
2020-05-16 04:52:42 -05:00
|
|
|
output="{key}MyContainer::const_iterator")
|
2015-02-03 02:18:18 -06:00
|
|
|
# test decl specs on right
|
2020-05-16 04:52:42 -05:00
|
|
|
check("type", "{key}bool const b", {1: "b", 2: "1b"}, key='typedef')
|
2015-03-02 13:27:37 -06:00
|
|
|
# test name in global scope
|
2020-05-16 04:52:42 -05:00
|
|
|
check("type", "{key}bool ::B::b", {1: "B::b", 2: "N1B1bE"}, key='typedef')
|
2015-03-01 08:04:15 -06:00
|
|
|
|
2020-05-16 04:52:42 -05:00
|
|
|
check('type', '{key}A = B', {2: '1A'}, key='using')
|
|
|
|
check('type', '{key}A = decltype(b)', {2: '1A'}, key='using')
|
2015-12-02 13:00:28 -06:00
|
|
|
|
2016-06-15 20:54:16 -05:00
|
|
|
# from breathe#267 (named function parameters for function pointers
|
2020-05-16 04:52:42 -05:00
|
|
|
check('type', '{key}void (*gpio_callback_t)(struct device *port, uint32_t pin)',
|
|
|
|
{1: 'gpio_callback_t', 2: '15gpio_callback_t'}, key='typedef')
|
|
|
|
check('type', '{key}void (*f)(std::function<void(int i)> g)', {1: 'f', 2: '1f'},
|
|
|
|
key='typedef')
|
2016-06-15 20:54:16 -05:00
|
|
|
|
2020-05-16 04:52:42 -05:00
|
|
|
check('type', '{key}T = A::template B<int>::template C<double>', {2: '1T'}, key='using')
|
2017-12-24 09:31:10 -06:00
|
|
|
|
2020-05-16 04:52:42 -05:00
|
|
|
check('type', '{key}T = Q<A::operator()>', {2: '1T'}, key='using')
|
|
|
|
check('type', '{key}T = Q<A::operator()<int>>', {2: '1T'}, key='using')
|
|
|
|
check('type', '{key}T = Q<A::operator bool>', {2: '1T'}, key='using')
|
2017-12-28 09:50:32 -06:00
|
|
|
|
2015-12-02 13:00:28 -06:00
|
|
|
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_ast_concept_definitions():
|
2020-05-16 04:52:42 -05:00
|
|
|
check('concept', 'template<typename Param> {key}A::B::Concept',
|
2017-12-23 06:20:32 -06:00
|
|
|
{2: 'I0EN1A1B7ConceptE'})
|
2020-05-16 04:52:42 -05:00
|
|
|
check('concept', 'template<typename A, typename B, typename ...C> {key}Foo',
|
2017-12-23 06:20:32 -06:00
|
|
|
{2: 'I00DpE3Foo'})
|
2017-01-05 09:46:42 -06:00
|
|
|
with pytest.raises(DefinitionError):
|
2020-05-16 04:52:42 -05:00
|
|
|
parse('concept', '{key}Foo')
|
2017-01-05 09:46:42 -06:00
|
|
|
with pytest.raises(DefinitionError):
|
2020-05-16 04:52:42 -05:00
|
|
|
parse('concept', 'template<typename T> template<typename U> {key}Foo')
|
2016-05-28 01:31:03 -05:00
|
|
|
|
|
|
|
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_ast_member_definitions():
|
2015-03-01 08:04:15 -06:00
|
|
|
check('member', ' const std::string & name = 42',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "name__ssCR", 2: "4name"}, output='const std::string &name = 42')
|
|
|
|
check('member', ' const std::string & name', {1: "name__ssCR", 2: "4name"},
|
2015-03-01 08:04:15 -06:00
|
|
|
output='const std::string &name')
|
|
|
|
check('member', ' const std::string & name [ n ]',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "name__ssCRA", 2: "4name"}, output='const std::string &name[n]')
|
2015-03-01 08:04:15 -06:00
|
|
|
check('member', 'const std::vector< unsigned int, long> &name',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "name__std::vector:unsigned-i.l:CR", 2: "4name"},
|
2017-03-21 06:10:41 -05:00
|
|
|
output='const std::vector<unsigned int, long> &name')
|
2017-12-23 06:20:32 -06:00
|
|
|
check('member', 'module::myclass foo[n]', {1: "foo__module::myclassA", 2: "3foo"})
|
|
|
|
check('member', 'int *const p', {1: 'p__iPC', 2: '1p'})
|
|
|
|
check('member', 'extern int myInt', {1: 'myInt__i', 2: '5myInt'})
|
|
|
|
check('member', 'thread_local int myInt', {1: 'myInt__i', 2: '5myInt'})
|
|
|
|
check('member', 'extern thread_local int myInt', {1: 'myInt__i', 2: '5myInt'})
|
|
|
|
check('member', 'thread_local extern int myInt', {1: 'myInt__i', 2: '5myInt'},
|
2016-03-30 02:19:03 -05:00
|
|
|
'extern thread_local int myInt')
|
2015-03-01 08:04:15 -06:00
|
|
|
|
2019-10-06 04:20:00 -05:00
|
|
|
# tests based on https://en.cppreference.com/w/cpp/language/bit_field
|
|
|
|
check('member', 'int b : 3', {1: 'b__i', 2: '1b'})
|
|
|
|
check('member', 'int b : 8 = 42', {1: 'b__i', 2: '1b'})
|
|
|
|
check('member', 'int b : 8{42}', {1: 'b__i', 2: '1b'})
|
|
|
|
# TODO: enable once the ternary operator is supported
|
2020-11-15 02:03:26 -06:00
|
|
|
# check('member', 'int b : true ? 8 : a = 42', {1: 'b__i', 2: '1b'})
|
2019-10-06 04:20:00 -05:00
|
|
|
# TODO: enable once the ternary operator is supported
|
2020-11-15 02:03:26 -06:00
|
|
|
# check('member', 'int b : (true ? 8 : a) = 42', {1: 'b__i', 2: '1b'})
|
2019-10-06 04:20:00 -05:00
|
|
|
check('member', 'int b : 1 || new int{0}', {1: 'b__i', 2: '1b'})
|
|
|
|
|
2021-06-24 12:15:54 -05:00
|
|
|
check('member', 'inline int n', {1: 'n__i', 2: '1n'})
|
2021-06-24 12:39:15 -05:00
|
|
|
check('member', 'constinit int n', {1: 'n__i', 2: '1n'})
|
2021-06-24 12:15:54 -05:00
|
|
|
|
2015-12-02 13:00:28 -06:00
|
|
|
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_ast_function_definitions():
|
2019-01-12 07:30:00 -06:00
|
|
|
check('function', 'void f(volatile int)', {1: "f__iV", 2: "1fVi"})
|
|
|
|
check('function', 'void f(std::size_t)', {1: "f__std::s", 2: "1fNSt6size_tE"})
|
2017-12-23 06:20:32 -06:00
|
|
|
check('function', 'operator bool() const', {1: "castto-b-operatorC", 2: "NKcvbEv"})
|
2015-03-01 08:04:15 -06:00
|
|
|
check('function', 'A::operator bool() const',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "A::castto-b-operatorC", 2: "NK1AcvbEv"})
|
2015-03-01 08:04:15 -06:00
|
|
|
check('function', 'A::operator bool() volatile const &',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "A::castto-b-operatorVCR", 2: "NVKR1AcvbEv"})
|
2015-03-01 08:04:15 -06:00
|
|
|
check('function', 'A::operator bool() volatile const &&',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "A::castto-b-operatorVCO", 2: "NVKO1AcvbEv"})
|
2015-03-01 08:04:15 -06:00
|
|
|
check('function', 'bool namespaced::theclass::method(arg1, arg2)',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "namespaced::theclass::method__arg1.arg2",
|
|
|
|
2: "N10namespaced8theclass6methodE4arg14arg2"})
|
2015-03-05 03:51:28 -06:00
|
|
|
x = 'std::vector<std::pair<std::string, int>> &module::test(register int ' \
|
2014-07-23 18:40:48 -05:00
|
|
|
'foo, bar, std::string baz = "foobar, blah, bleh") const = 0'
|
2017-12-23 06:20:32 -06:00
|
|
|
check('function', x, {1: "module::test__i.bar.ssC",
|
2020-04-14 17:10:13 -05:00
|
|
|
2: "NK6module4testEi3barNSt6stringE"})
|
2015-03-01 08:04:15 -06:00
|
|
|
check('function', 'void f(std::pair<A, B>)',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "f__std::pair:A.B:", 2: "1fNSt4pairI1A1BEE"})
|
2015-03-01 08:04:15 -06:00
|
|
|
check('function', 'explicit module::myclass::foo::foo()',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "module::myclass::foo::foo", 2: "N6module7myclass3foo3fooEv"})
|
2015-03-01 08:04:15 -06:00
|
|
|
check('function', 'module::myclass::foo::~foo()',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "module::myclass::foo::~foo", 2: "N6module7myclass3fooD0Ev"})
|
2015-03-01 08:04:15 -06:00
|
|
|
check('function', 'int printf(const char *fmt, ...)',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "printf__cCP.z", 2: "6printfPKcz"})
|
2015-03-01 08:04:15 -06:00
|
|
|
check('function', 'int foo(const unsigned int j)',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "foo__unsigned-iC", 2: "3fooKj"})
|
2015-03-01 08:04:15 -06:00
|
|
|
check('function', 'int foo(const int *const ptr)',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "foo__iCPC", 2: "3fooPCKi"})
|
2015-03-01 08:04:15 -06:00
|
|
|
check('function', 'module::myclass::operator std::vector<std::string>()',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "module::myclass::castto-std::vector:ss:-operator",
|
|
|
|
2: "N6module7myclasscvNSt6vectorINSt6stringEEEEv"})
|
2014-10-09 09:53:33 -05:00
|
|
|
check('function',
|
2015-03-01 08:04:15 -06:00
|
|
|
'void operator()(const boost::array<VertexID, 2> &v) const',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "call-operator__boost::array:VertexID.2:CRC",
|
|
|
|
2: "NKclERKN5boost5arrayI8VertexIDX2EEE",
|
|
|
|
3: "NKclERKN5boost5arrayI8VertexIDXL2EEEE"})
|
2014-10-09 09:53:33 -05:00
|
|
|
check('function',
|
2015-03-01 08:04:15 -06:00
|
|
|
'void operator()(const boost::array<VertexID, 2, "foo, bar"> &v) const',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: 'call-operator__boost::array:VertexID.2."foo,--bar":CRC',
|
|
|
|
2: 'NKclERKN5boost5arrayI8VertexIDX2EX"foo, bar"EEE',
|
|
|
|
3: 'NKclERKN5boost5arrayI8VertexIDXL2EEXLA9_KcEEEE'})
|
2015-03-01 08:04:15 -06:00
|
|
|
check('function', 'MyClass::MyClass(MyClass::MyClass&&)',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "MyClass::MyClass__MyClass::MyClassRR",
|
|
|
|
2: "N7MyClass7MyClassERRN7MyClass7MyClassE"})
|
|
|
|
check('function', 'constexpr int get_value()', {1: "get_valueCE", 2: "9get_valuev"})
|
2015-03-01 08:04:15 -06:00
|
|
|
check('function', 'static constexpr int get_value()',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "get_valueCE", 2: "9get_valuev"})
|
2015-03-01 08:04:15 -06:00
|
|
|
check('function', 'int get_value() const noexcept',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "get_valueC", 2: "NK9get_valueEv"})
|
2020-04-14 17:10:13 -05:00
|
|
|
check('function', 'int get_value() const noexcept(std::is_nothrow_move_constructible<T>::value)',
|
|
|
|
{1: "get_valueC", 2: "NK9get_valueEv"})
|
|
|
|
check('function', 'int get_value() const noexcept("see below")',
|
|
|
|
{1: "get_valueC", 2: "NK9get_valueEv"})
|
2015-03-01 08:04:15 -06:00
|
|
|
check('function', 'int get_value() const noexcept = delete',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "get_valueC", 2: "NK9get_valueEv"})
|
2015-03-01 08:04:15 -06:00
|
|
|
check('function', 'int get_value() volatile const',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "get_valueVC", 2: "NVK9get_valueEv"})
|
2015-03-01 08:04:15 -06:00
|
|
|
check('function', 'MyClass::MyClass(MyClass::MyClass&&) = default',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "MyClass::MyClass__MyClass::MyClassRR",
|
|
|
|
2: "N7MyClass7MyClassERRN7MyClass7MyClassE"})
|
2015-03-01 08:04:15 -06:00
|
|
|
check('function', 'virtual MyClass::a_virtual_function() const override',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "MyClass::a_virtual_functionC", 2: "NK7MyClass18a_virtual_functionEv"})
|
|
|
|
check('function', 'A B() override', {1: "B", 2: "1Bv"})
|
|
|
|
check('function', 'A B() final', {1: "B", 2: "1Bv"})
|
|
|
|
check('function', 'A B() final override', {1: "B", 2: "1Bv"})
|
|
|
|
check('function', 'A B() override final', {1: "B", 2: "1Bv"},
|
2015-03-01 08:04:15 -06:00
|
|
|
output='A B() final override')
|
|
|
|
check('function', 'MyClass::a_member_function() volatile',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "MyClass::a_member_functionV", 2: "NV7MyClass17a_member_functionEv"})
|
2015-03-01 08:04:15 -06:00
|
|
|
check('function', 'MyClass::a_member_function() volatile const',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "MyClass::a_member_functionVC", 2: "NVK7MyClass17a_member_functionEv"})
|
2015-03-01 08:04:15 -06:00
|
|
|
check('function', 'MyClass::a_member_function() &&',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "MyClass::a_member_functionO", 2: "NO7MyClass17a_member_functionEv"})
|
2015-03-01 08:04:15 -06:00
|
|
|
check('function', 'MyClass::a_member_function() &',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "MyClass::a_member_functionR", 2: "NR7MyClass17a_member_functionEv"})
|
2015-03-01 08:04:15 -06:00
|
|
|
check('function', 'MyClass::a_member_function() const &',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "MyClass::a_member_functionCR", 2: "NKR7MyClass17a_member_functionEv"})
|
2015-03-01 08:04:15 -06:00
|
|
|
check('function', 'int main(int argc, char *argv[])',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "main__i.cPA", 2: "4mainiA_Pc"})
|
2015-03-01 08:04:15 -06:00
|
|
|
check('function', 'MyClass &MyClass::operator++()',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "MyClass::inc-operator", 2: "N7MyClassppEv"})
|
2015-03-01 08:04:15 -06:00
|
|
|
check('function', 'MyClass::pointer MyClass::operator->()',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "MyClass::pointer-operator", 2: "N7MyClassptEv"})
|
2014-07-23 18:40:48 -05:00
|
|
|
|
2015-03-05 03:51:28 -06:00
|
|
|
x = 'std::vector<std::pair<std::string, int>> &module::test(register int ' \
|
2014-07-23 18:40:48 -05:00
|
|
|
'foo, bar[n], std::string baz = "foobar, blah, bleh") const = 0'
|
2017-12-23 06:20:32 -06:00
|
|
|
check('function', x, {1: "module::test__i.barA.ssC",
|
|
|
|
2: "NK6module4testEiAn_3barNSt6stringE",
|
|
|
|
3: "NK6module4testEiA1n_3barNSt6stringE"})
|
2014-10-09 09:53:33 -05:00
|
|
|
check('function',
|
2015-03-01 08:04:15 -06:00
|
|
|
'int foo(Foo f = Foo(double(), std::make_pair(int(2), double(3.4))))',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "foo__Foo", 2: "3foo3Foo"})
|
|
|
|
check('function', 'int foo(A a = x(a))', {1: "foo__A", 2: "3foo1A"})
|
2017-01-05 09:46:42 -06:00
|
|
|
with pytest.raises(DefinitionError):
|
|
|
|
parse('function', 'int foo(B b=x(a)')
|
|
|
|
with pytest.raises(DefinitionError):
|
|
|
|
parse('function', 'int foo)C c=x(a))')
|
|
|
|
with pytest.raises(DefinitionError):
|
|
|
|
parse('function', 'int foo(D d=x(a')
|
2017-12-23 06:20:32 -06:00
|
|
|
check('function', 'int foo(const A&... a)', {1: "foo__ACRDp", 2: "3fooDpRK1A"})
|
2020-03-18 03:57:23 -05:00
|
|
|
check('function', 'int foo(const A&...)', {1: "foo__ACRDp", 2: "3fooDpRK1A"})
|
|
|
|
check('function', 'int foo(const A*... a)', {1: "foo__ACPDp", 2: "3fooDpPK1A"})
|
|
|
|
check('function', 'int foo(const A*...)', {1: "foo__ACPDp", 2: "3fooDpPK1A"})
|
|
|
|
check('function', 'int foo(const int A::*... a)', {2: "3fooDpM1AKi"})
|
|
|
|
check('function', 'int foo(const int A::*...)', {2: "3fooDpM1AKi"})
|
2020-11-15 02:03:26 -06:00
|
|
|
# check('function', 'int foo(int (*a)(A)...)', {1: "foo__ACRDp", 2: "3fooDpPK1A"})
|
|
|
|
# check('function', 'int foo(int (*)(A)...)', {1: "foo__ACRDp", 2: "3fooDpPK1A"})
|
2017-12-23 06:20:32 -06:00
|
|
|
check('function', 'virtual void f()', {1: "f", 2: "1fv"})
|
2015-02-24 02:49:43 -06:00
|
|
|
# test for ::nestedName, from issue 1738
|
2015-03-01 08:04:15 -06:00
|
|
|
check("function", "result(int val, ::std::error_category const &cat)",
|
2019-01-05 11:43:36 -06:00
|
|
|
{1: "result__i.std::error_categoryCR", 2: "6resultiRKNSt14error_categoryE"})
|
2017-12-23 06:20:32 -06:00
|
|
|
check("function", "int *f()", {1: "f", 2: "1fv"})
|
2015-03-05 03:51:28 -06:00
|
|
|
# tests derived from issue #1753 (skip to keep sanity)
|
2017-12-23 06:20:32 -06:00
|
|
|
check("function", "f(int (&array)[10])", {2: "1fRA10_i", 3: "1fRAL10E_i"})
|
|
|
|
check("function", "void f(int (&array)[10])", {2: "1fRA10_i", 3: "1fRAL10E_i"})
|
|
|
|
check("function", "void f(float *q(double))", {2: "1fFPfdE"})
|
|
|
|
check("function", "void f(float *(*q)(double))", {2: "1fPFPfdE"})
|
|
|
|
check("function", "void f(float (*q)(double))", {2: "1fPFfdE"})
|
|
|
|
check("function", "int (*f(double d))(float)", {1: "f__double", 2: "1fd"})
|
|
|
|
check("function", "int (*f(bool b))[5]", {1: "f__b", 2: "1fb"})
|
2015-03-05 03:51:28 -06:00
|
|
|
check("function", "int (*A::f(double d) const)(float)",
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: "A::f__doubleC", 2: "NK1A1fEd"})
|
2015-03-05 03:51:28 -06:00
|
|
|
check("function", "void f(std::shared_ptr<int(double)> ptr)",
|
2017-12-23 06:20:32 -06:00
|
|
|
{2: "1fNSt10shared_ptrIFidEEE"})
|
|
|
|
check("function", "void f(int *const p)", {1: "f__iPC", 2: "1fPCi"})
|
|
|
|
check("function", "void f(int *volatile const p)", {1: "f__iPVC", 2: "1fPVCi"})
|
2015-03-05 03:51:28 -06:00
|
|
|
|
2017-12-23 06:20:32 -06:00
|
|
|
check('function', 'extern int f()', {1: 'f', 2: '1fv'})
|
2021-06-24 12:39:15 -05:00
|
|
|
check('function', 'consteval int f()', {1: 'f', 2: '1fv'})
|
2016-03-30 23:40:02 -05:00
|
|
|
|
2021-06-24 13:26:22 -05:00
|
|
|
check('function', 'explicit(true) void f()', {1: 'f', 2: '1fv'})
|
|
|
|
|
2017-12-23 06:20:32 -06:00
|
|
|
check('function', 'decltype(auto) f()', {1: 'f', 2: "1fv"})
|
2017-11-26 14:41:15 -06:00
|
|
|
|
2015-03-05 03:51:28 -06:00
|
|
|
# TODO: make tests for functions in a template, e.g., Test<int&&()>
|
|
|
|
# such that the id generation for function type types is correct.
|
2015-02-06 18:26:35 -06:00
|
|
|
|
2018-06-09 05:24:34 -05:00
|
|
|
check('function', 'friend std::ostream &f(std::ostream &s, int i)',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: 'f__osR.i', 2: '1fRNSt7ostreamEi'})
|
2015-09-14 07:31:15 -05:00
|
|
|
|
2015-10-01 08:28:54 -05:00
|
|
|
# from breathe#223
|
2017-12-23 06:20:32 -06:00
|
|
|
check('function', 'void f(struct E e)', {1: 'f__E', 2: '1f1E'})
|
|
|
|
check('function', 'void f(class E e)', {1: 'f__E', 2: '1f1E'})
|
|
|
|
check('function', 'void f(typename E e)', {1: 'f__E', 2: '1f1E'})
|
|
|
|
check('function', 'void f(enum E e)', {1: 'f__E', 2: '1f1E'})
|
|
|
|
check('function', 'void f(union E e)', {1: 'f__E', 2: '1f1E'})
|
2015-10-01 08:28:54 -05:00
|
|
|
|
2015-12-02 13:00:28 -06:00
|
|
|
# pointer to member (function)
|
2017-12-23 06:20:32 -06:00
|
|
|
check('function', 'void f(int C::*)', {2: '1fM1Ci'})
|
|
|
|
check('function', 'void f(int C::* p)', {2: '1fM1Ci'})
|
|
|
|
check('function', 'void f(int ::C::* p)', {2: '1fM1Ci'})
|
2020-03-18 03:57:23 -05:00
|
|
|
check('function', 'void f(int C::*const)', {2: '1fKM1Ci'})
|
|
|
|
check('function', 'void f(int C::*const&)', {2: '1fRKM1Ci'})
|
|
|
|
check('function', 'void f(int C::*volatile)', {2: '1fVM1Ci'})
|
|
|
|
check('function', 'void f(int C::*const volatile)', {2: '1fVKM1Ci'},
|
|
|
|
output='void f(int C::*volatile const)')
|
|
|
|
check('function', 'void f(int C::*volatile const)', {2: '1fVKM1Ci'})
|
2017-12-23 06:20:32 -06:00
|
|
|
check('function', 'void f(int (C::*)(float, double))', {2: '1fM1CFifdE'})
|
|
|
|
check('function', 'void f(int (C::* p)(float, double))', {2: '1fM1CFifdE'})
|
|
|
|
check('function', 'void f(int (::C::* p)(float, double))', {2: '1fM1CFifdE'})
|
|
|
|
check('function', 'void f(void (C::*)() const &)', {2: '1fM1CKRFvvE'})
|
|
|
|
check('function', 'int C::* f(int, double)', {2: '1fid'})
|
2020-03-18 03:57:23 -05:00
|
|
|
check('function', 'void f(int C::* *p)', {2: '1fPM1Ci'})
|
|
|
|
check('function', 'void f(int C::**)', {2: '1fPM1Ci'})
|
|
|
|
check('function', 'void f(int C::*const *p)', {2: '1fPKM1Ci'})
|
|
|
|
check('function', 'void f(int C::*const*)', {2: '1fPKM1Ci'})
|
2015-12-02 13:00:28 -06:00
|
|
|
|
2019-01-05 11:43:36 -06:00
|
|
|
# exceptions from return type mangling
|
|
|
|
check('function', 'template<typename T> C()', {2: 'I0E1Cv'})
|
2022-04-17 10:27:30 -05:00
|
|
|
check('function', 'template<typename T> operator int()', {2: 'I0Ecviv'})
|
2019-01-05 11:43:36 -06:00
|
|
|
|
2020-05-01 15:01:46 -05:00
|
|
|
# trailing return types
|
|
|
|
ids = {1: 'f', 2: '1fv'}
|
|
|
|
check('function', 'int f()', ids)
|
|
|
|
check('function', 'auto f() -> int', ids)
|
|
|
|
check('function', 'virtual auto f() -> int = 0', ids)
|
|
|
|
check('function', 'virtual auto f() -> int final', ids)
|
|
|
|
check('function', 'virtual auto f() -> int override', ids)
|
|
|
|
|
|
|
|
ids = {2: 'I0E1fv', 4: 'I0E1fiv'}
|
|
|
|
check('function', 'template<typename T> int f()', ids)
|
|
|
|
check('function', 'template<typename T> f() -> int', ids)
|
|
|
|
|
|
|
|
# from breathe#441
|
|
|
|
check('function', 'auto MakeThingy() -> Thingy*', {1: 'MakeThingy', 2: '10MakeThingyv'})
|
|
|
|
|
2021-03-04 14:28:18 -06:00
|
|
|
# from #8960
|
|
|
|
check('function', 'void f(void (*p)(int, double), int i)', {2: '1fPFvidEi'})
|
|
|
|
|
2021-08-15 10:24:14 -05:00
|
|
|
# from #9535 comment
|
|
|
|
check('function', 'void f(void (*p)(int) = &foo)', {2: '1fPFviE'})
|
|
|
|
|
2015-12-02 13:00:28 -06:00
|
|
|
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_ast_operators():
|
2020-03-24 11:26:02 -05:00
|
|
|
check('function', 'void operator new()', {1: "new-operator", 2: "nwv"})
|
|
|
|
check('function', 'void operator new[]()', {1: "new-array-operator", 2: "nav"})
|
|
|
|
check('function', 'void operator delete()', {1: "delete-operator", 2: "dlv"})
|
|
|
|
check('function', 'void operator delete[]()', {1: "delete-array-operator", 2: "dav"})
|
|
|
|
check('function', 'operator bool() const', {1: "castto-b-operatorC", 2: "NKcvbEv"})
|
|
|
|
check('function', 'void operator""_udl()', {2: 'li4_udlv'})
|
|
|
|
|
|
|
|
check('function', 'void operator~()', {1: "inv-operator", 2: "cov"})
|
|
|
|
check('function', 'void operator compl()', {2: "cov"})
|
|
|
|
check('function', 'void operator+()', {1: "add-operator", 2: "plv"})
|
|
|
|
check('function', 'void operator-()', {1: "sub-operator", 2: "miv"})
|
|
|
|
check('function', 'void operator*()', {1: "mul-operator", 2: "mlv"})
|
|
|
|
check('function', 'void operator/()', {1: "div-operator", 2: "dvv"})
|
|
|
|
check('function', 'void operator%()', {1: "mod-operator", 2: "rmv"})
|
|
|
|
check('function', 'void operator&()', {1: "and-operator", 2: "anv"})
|
|
|
|
check('function', 'void operator bitand()', {2: "anv"})
|
|
|
|
check('function', 'void operator|()', {1: "or-operator", 2: "orv"})
|
|
|
|
check('function', 'void operator bitor()', {2: "orv"})
|
|
|
|
check('function', 'void operator^()', {1: "xor-operator", 2: "eov"})
|
|
|
|
check('function', 'void operator xor()', {2: "eov"})
|
|
|
|
check('function', 'void operator=()', {1: "assign-operator", 2: "aSv"})
|
|
|
|
check('function', 'void operator+=()', {1: "add-assign-operator", 2: "pLv"})
|
|
|
|
check('function', 'void operator-=()', {1: "sub-assign-operator", 2: "mIv"})
|
|
|
|
check('function', 'void operator*=()', {1: "mul-assign-operator", 2: "mLv"})
|
|
|
|
check('function', 'void operator/=()', {1: "div-assign-operator", 2: "dVv"})
|
|
|
|
check('function', 'void operator%=()', {1: "mod-assign-operator", 2: "rMv"})
|
|
|
|
check('function', 'void operator&=()', {1: "and-assign-operator", 2: "aNv"})
|
|
|
|
check('function', 'void operator and_eq()', {2: "aNv"})
|
|
|
|
check('function', 'void operator|=()', {1: "or-assign-operator", 2: "oRv"})
|
|
|
|
check('function', 'void operator or_eq()', {2: "oRv"})
|
|
|
|
check('function', 'void operator^=()', {1: "xor-assign-operator", 2: "eOv"})
|
|
|
|
check('function', 'void operator xor_eq()', {2: "eOv"})
|
|
|
|
check('function', 'void operator<<()', {1: "lshift-operator", 2: "lsv"})
|
|
|
|
check('function', 'void operator>>()', {1: "rshift-operator", 2: "rsv"})
|
|
|
|
check('function', 'void operator<<=()', {1: "lshift-assign-operator", 2: "lSv"})
|
|
|
|
check('function', 'void operator>>=()', {1: "rshift-assign-operator", 2: "rSv"})
|
|
|
|
check('function', 'void operator==()', {1: "eq-operator", 2: "eqv"})
|
|
|
|
check('function', 'void operator!=()', {1: "neq-operator", 2: "nev"})
|
|
|
|
check('function', 'void operator not_eq()', {2: "nev"})
|
|
|
|
check('function', 'void operator<()', {1: "lt-operator", 2: "ltv"})
|
|
|
|
check('function', 'void operator>()', {1: "gt-operator", 2: "gtv"})
|
|
|
|
check('function', 'void operator<=()', {1: "lte-operator", 2: "lev"})
|
|
|
|
check('function', 'void operator>=()', {1: "gte-operator", 2: "gev"})
|
2022-04-17 10:27:30 -05:00
|
|
|
check('function', 'void operator<=>()', {2: "ssv"})
|
2020-03-24 11:26:02 -05:00
|
|
|
check('function', 'void operator!()', {1: "not-operator", 2: "ntv"})
|
|
|
|
check('function', 'void operator not()', {2: "ntv"})
|
|
|
|
check('function', 'void operator&&()', {1: "sand-operator", 2: "aav"})
|
|
|
|
check('function', 'void operator and()', {2: "aav"})
|
|
|
|
check('function', 'void operator||()', {1: "sor-operator", 2: "oov"})
|
|
|
|
check('function', 'void operator or()', {2: "oov"})
|
|
|
|
check('function', 'void operator++()', {1: "inc-operator", 2: "ppv"})
|
|
|
|
check('function', 'void operator--()', {1: "dec-operator", 2: "mmv"})
|
|
|
|
check('function', 'void operator,()', {1: "comma-operator", 2: "cmv"})
|
|
|
|
check('function', 'void operator->*()', {1: "pointer-by-pointer-operator", 2: "pmv"})
|
|
|
|
check('function', 'void operator->()', {1: "pointer-operator", 2: "ptv"})
|
|
|
|
check('function', 'void operator()()', {1: "call-operator", 2: "clv"})
|
|
|
|
check('function', 'void operator[]()', {1: "subscript-operator", 2: "ixv"})
|
2015-12-02 13:00:28 -06:00
|
|
|
|
|
|
|
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_ast_nested_name():
|
2020-05-16 04:52:42 -05:00
|
|
|
check('class', '{key}::A', {1: "A", 2: "1A"})
|
|
|
|
check('class', '{key}::A::B', {1: "A::B", 2: "N1A1BE"})
|
|
|
|
check('function', 'void f(::A a)', {1: "f__A", 2: "1f1A"})
|
|
|
|
check('function', 'void f(::A::B a)', {1: "f__A::B", 2: "1fN1A1BE"})
|
|
|
|
|
|
|
|
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_ast_class_definitions():
|
2020-05-16 04:52:42 -05:00
|
|
|
check('class', 'public A', {1: "A", 2: "1A"}, output='{key}A')
|
|
|
|
check('class', 'private {key}A', {1: "A", 2: "1A"})
|
|
|
|
check('class', '{key}A final', {1: 'A', 2: '1A'})
|
2015-12-02 13:00:28 -06:00
|
|
|
|
|
|
|
# test bases
|
2020-05-16 04:52:42 -05:00
|
|
|
check('class', '{key}A', {1: "A", 2: "1A"})
|
|
|
|
check('class', '{key}A::B::C', {1: "A::B::C", 2: "N1A1B1CE"})
|
|
|
|
check('class', '{key}A : B', {1: "A", 2: "1A"})
|
|
|
|
check('class', '{key}A : private B', {1: "A", 2: "1A"})
|
|
|
|
check('class', '{key}A : public B', {1: "A", 2: "1A"})
|
|
|
|
check('class', '{key}A : B, C', {1: "A", 2: "1A"})
|
|
|
|
check('class', '{key}A : B, protected C, D', {1: "A", 2: "1A"})
|
|
|
|
check('class', 'A : virtual private B', {1: 'A', 2: '1A'}, output='{key}A : private virtual B')
|
|
|
|
check('class', '{key}A : private virtual B', {1: 'A', 2: '1A'})
|
|
|
|
check('class', '{key}A : B, virtual C', {1: 'A', 2: '1A'})
|
|
|
|
check('class', '{key}A : public virtual B', {1: 'A', 2: '1A'})
|
|
|
|
check('class', '{key}A : B, C...', {1: 'A', 2: '1A'})
|
|
|
|
check('class', '{key}A : B..., C', {1: 'A', 2: '1A'})
|
2015-02-06 18:26:35 -06:00
|
|
|
|
2017-11-26 14:41:15 -06:00
|
|
|
# from #4094
|
2020-05-16 04:52:42 -05:00
|
|
|
check('class', 'template<class, class = std::void_t<>> {key}has_var', {2: 'I00E7has_var'})
|
|
|
|
check('class', 'template<class T> {key}has_var<T, std::void_t<decltype(&T::var)>>',
|
2017-12-23 06:20:32 -06:00
|
|
|
{2: 'I0E7has_varI1TNSt6void_tIDTadN1T3varEEEEE'})
|
2017-11-26 14:41:15 -06:00
|
|
|
|
2020-05-16 04:52:42 -05:00
|
|
|
check('class', 'template<typename ...Ts> {key}T<int (*)(Ts)...>',
|
2020-03-25 07:08:09 -05:00
|
|
|
{2: 'IDpE1TIJPFi2TsEEE'})
|
2020-05-16 04:52:42 -05:00
|
|
|
check('class', 'template<int... Is> {key}T<(Is)...>',
|
2020-03-25 07:08:09 -05:00
|
|
|
{2: 'I_DpiE1TIJX(Is)EEE', 3: 'I_DpiE1TIJX2IsEEE'})
|
|
|
|
|
|
|
|
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_ast_union_definitions():
|
2020-05-16 04:52:42 -05:00
|
|
|
check('union', '{key}A', {2: "1A"})
|
2018-05-26 13:03:25 -05:00
|
|
|
|
|
|
|
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_ast_enum_definitions():
|
2020-05-16 04:52:42 -05:00
|
|
|
check('enum', '{key}A', {2: "1A"})
|
|
|
|
check('enum', '{key}A : std::underlying_type<B>::type', {2: "1A"})
|
|
|
|
check('enum', '{key}A : unsigned int', {2: "1A"})
|
|
|
|
check('enum', 'public A', {2: "1A"}, output='{key}A')
|
|
|
|
check('enum', 'private {key}A', {2: "1A"})
|
2015-02-06 18:26:35 -06:00
|
|
|
|
2020-05-16 04:52:42 -05:00
|
|
|
check('enumerator', '{key}A', {2: "1A"})
|
|
|
|
check('enumerator', '{key}A = std::numeric_limits<unsigned long>::max()', {2: "1A"})
|
2014-07-18 11:09:25 -05:00
|
|
|
|
2015-09-13 05:33:57 -05:00
|
|
|
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_ast_anon_definitions():
|
2020-05-16 04:52:42 -05:00
|
|
|
check('class', '@a', {3: "Ut1_a"}, asTextOutput='class [anonymous]')
|
|
|
|
check('union', '@a', {3: "Ut1_a"}, asTextOutput='union [anonymous]')
|
|
|
|
check('enum', '@a', {3: "Ut1_a"}, asTextOutput='enum [anonymous]')
|
|
|
|
check('class', '@1', {3: "Ut1_1"}, asTextOutput='class [anonymous]')
|
|
|
|
check('class', '@a::A', {3: "NUt1_a1AE"}, asTextOutput='class [anonymous]::A')
|
2018-06-09 05:24:34 -05:00
|
|
|
|
2021-03-16 14:02:26 -05:00
|
|
|
check('function', 'int f(int @a)', {1: 'f__i', 2: '1fi'},
|
|
|
|
asTextOutput='int f(int [anonymous])')
|
|
|
|
|
2018-06-09 05:24:34 -05:00
|
|
|
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_ast_templates():
|
2020-05-16 04:52:42 -05:00
|
|
|
check('class', "A<T>", {2: "IE1AI1TE"}, output="template<> {key}A<T>")
|
2015-03-02 13:27:37 -06:00
|
|
|
# first just check which objects support templating
|
2020-05-16 04:52:42 -05:00
|
|
|
check('class', "template<> {key}A", {2: "IE1A"})
|
2019-01-05 11:43:36 -06:00
|
|
|
check('function', "template<> void A()", {2: "IE1Av", 4: "IE1Avv"})
|
2017-12-23 06:20:32 -06:00
|
|
|
check('member', "template<> A a", {2: "IE1a"})
|
2020-05-16 04:52:42 -05:00
|
|
|
check('type', "template<> {key}a = A", {2: "IE1a"}, key='using')
|
2017-01-05 09:46:42 -06:00
|
|
|
with pytest.raises(DefinitionError):
|
|
|
|
parse('enum', "template<> A")
|
|
|
|
with pytest.raises(DefinitionError):
|
|
|
|
parse('enumerator', "template<> A")
|
2015-03-02 13:27:37 -06:00
|
|
|
# then all the real tests
|
2020-05-16 04:52:42 -05:00
|
|
|
check('class', "template<typename T1, typename T2> {key}A", {2: "I00E1A"})
|
|
|
|
check('type', "template<> {key}a", {2: "IE1a"}, key='using')
|
2017-03-21 06:10:41 -05:00
|
|
|
|
2020-05-16 04:52:42 -05:00
|
|
|
check('class', "template<typename T> {key}A", {2: "I0E1A"})
|
|
|
|
check('class', "template<class T> {key}A", {2: "I0E1A"})
|
|
|
|
check('class', "template<typename ...T> {key}A", {2: "IDpE1A"})
|
|
|
|
check('class', "template<typename...> {key}A", {2: "IDpE1A"})
|
|
|
|
check('class', "template<typename = Test> {key}A", {2: "I0E1A"})
|
|
|
|
check('class', "template<typename T = Test> {key}A", {2: "I0E1A"})
|
2017-03-21 06:10:41 -05:00
|
|
|
|
2020-05-16 04:52:42 -05:00
|
|
|
check('class', "template<template<typename> typename T> {key}A", {2: "II0E0E1A"})
|
2020-08-02 03:34:51 -05:00
|
|
|
check('class', "template<template<typename> class T> {key}A", {2: "II0E0E1A"})
|
2020-05-16 04:52:42 -05:00
|
|
|
check('class', "template<template<typename> typename> {key}A", {2: "II0E0E1A"})
|
|
|
|
check('class', "template<template<typename> typename ...T> {key}A", {2: "II0EDpE1A"})
|
|
|
|
check('class', "template<template<typename> typename...> {key}A", {2: "II0EDpE1A"})
|
2020-08-13 10:08:39 -05:00
|
|
|
check('class', "template<typename T, template<typename> typename...> {key}A", {2: "I0I0EDpE1A"})
|
2017-11-30 16:06:30 -06:00
|
|
|
|
2020-05-16 04:52:42 -05:00
|
|
|
check('class', "template<int> {key}A", {2: "I_iE1A"})
|
|
|
|
check('class', "template<int T> {key}A", {2: "I_iE1A"})
|
|
|
|
check('class', "template<int... T> {key}A", {2: "I_DpiE1A"})
|
|
|
|
check('class', "template<int T = 42> {key}A", {2: "I_iE1A"})
|
|
|
|
check('class', "template<int = 42> {key}A", {2: "I_iE1A"})
|
2015-03-02 13:27:37 -06:00
|
|
|
|
2020-08-02 03:34:51 -05:00
|
|
|
check('class', "template<typename A<B>::C> {key}A", {2: "I_N1AI1BE1CEE1A"})
|
|
|
|
check('class', "template<typename A<B>::C = 42> {key}A", {2: "I_N1AI1BE1CEE1A"})
|
|
|
|
# from #7944
|
|
|
|
check('function', "template<typename T, "
|
|
|
|
"typename std::enable_if<!has_overloaded_addressof<T>::value, bool>::type = false"
|
|
|
|
"> constexpr T *static_addressof(T &ref)",
|
|
|
|
{2: "I0_NSt9enable_ifIX!has_overloaded_addressof<T>::valueEbE4typeEE16static_addressofR1T",
|
|
|
|
3: "I0_NSt9enable_ifIXntN24has_overloaded_addressofI1TE5valueEEbE4typeEE16static_addressofR1T",
|
|
|
|
4: "I0_NSt9enable_ifIXntN24has_overloaded_addressofI1TE5valueEEbE4typeEE16static_addressofP1TR1T"})
|
|
|
|
|
2020-05-16 04:52:42 -05:00
|
|
|
check('class', "template<> {key}A<NS::B<>>", {2: "IE1AIN2NS1BIEEE"})
|
2017-09-28 13:46:34 -05:00
|
|
|
|
2015-10-12 07:06:45 -05:00
|
|
|
# from #2058
|
|
|
|
check('function',
|
|
|
|
"template<typename Char, typename Traits> "
|
|
|
|
"inline std::basic_ostream<Char, Traits> &operator<<("
|
|
|
|
"std::basic_ostream<Char, Traits> &os, "
|
|
|
|
"const c_string_view_base<const Char, Traits> &str)",
|
2017-12-23 06:20:32 -06:00
|
|
|
{2: "I00ElsRNSt13basic_ostreamI4Char6TraitsEE"
|
2019-01-05 11:43:36 -06:00
|
|
|
"RK18c_string_view_baseIK4Char6TraitsE",
|
|
|
|
4: "I00Els"
|
|
|
|
"RNSt13basic_ostreamI4Char6TraitsEE"
|
|
|
|
"RNSt13basic_ostreamI4Char6TraitsEE"
|
2017-12-23 06:20:32 -06:00
|
|
|
"RK18c_string_view_baseIK4Char6TraitsE"})
|
2015-10-12 07:06:45 -05:00
|
|
|
|
2016-05-28 08:00:13 -05:00
|
|
|
# template introductions
|
2017-01-05 09:46:42 -06:00
|
|
|
with pytest.raises(DefinitionError):
|
|
|
|
parse('enum', 'abc::ns::foo{id_0, id_1, id_2} A')
|
|
|
|
with pytest.raises(DefinitionError):
|
|
|
|
parse('enumerator', 'abc::ns::foo{id_0, id_1, id_2} A')
|
2020-05-16 04:52:42 -05:00
|
|
|
check('class', 'abc::ns::foo{{id_0, id_1, id_2}} {key}xyz::bar',
|
2017-12-23 06:20:32 -06:00
|
|
|
{2: 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barE'})
|
2020-05-16 04:52:42 -05:00
|
|
|
check('class', 'abc::ns::foo{{id_0, id_1, ...id_2}} {key}xyz::bar',
|
2017-12-23 06:20:32 -06:00
|
|
|
{2: 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barE'})
|
2020-05-16 04:52:42 -05:00
|
|
|
check('class', 'abc::ns::foo{{id_0, id_1, id_2}} {key}xyz::bar<id_0, id_1, id_2>',
|
2022-03-11 08:51:30 -06:00
|
|
|
{2: 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barE'})
|
2020-05-16 04:52:42 -05:00
|
|
|
check('class', 'abc::ns::foo{{id_0, id_1, ...id_2}} {key}xyz::bar<id_0, id_1, id_2...>',
|
2022-03-11 08:51:30 -06:00
|
|
|
{2: 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barE'})
|
2016-05-28 08:00:13 -05:00
|
|
|
|
2020-05-16 04:52:42 -05:00
|
|
|
check('class', 'template<> Concept{{U}} {key}A<int>::B', {2: 'IEI0EX7ConceptI1UEEN1AIiE1BE'})
|
2016-05-28 08:00:13 -05:00
|
|
|
|
2020-05-16 04:52:42 -05:00
|
|
|
check('type', 'abc::ns::foo{{id_0, id_1, id_2}} {key}xyz::bar = ghi::qux',
|
|
|
|
{2: 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barE'}, key='using')
|
|
|
|
check('type', 'abc::ns::foo{{id_0, id_1, ...id_2}} {key}xyz::bar = ghi::qux',
|
|
|
|
{2: 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barE'}, key='using')
|
2016-05-28 08:00:13 -05:00
|
|
|
check('function', 'abc::ns::foo{id_0, id_1, id_2} void xyz::bar()',
|
2019-01-05 11:43:36 -06:00
|
|
|
{2: 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barEv',
|
|
|
|
4: 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barEvv'})
|
2016-05-28 08:00:13 -05:00
|
|
|
check('function', 'abc::ns::foo{id_0, id_1, ...id_2} void xyz::bar()',
|
2019-01-05 11:43:36 -06:00
|
|
|
{2: 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barEv',
|
|
|
|
4: 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barEvv'})
|
2016-05-28 08:00:13 -05:00
|
|
|
check('member', 'abc::ns::foo{id_0, id_1, id_2} ghi::qux xyz::bar',
|
2017-12-23 06:20:32 -06:00
|
|
|
{2: 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barE'})
|
2016-05-28 08:00:13 -05:00
|
|
|
check('member', 'abc::ns::foo{id_0, id_1, ...id_2} ghi::qux xyz::bar',
|
2017-12-23 06:20:32 -06:00
|
|
|
{2: 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barE'})
|
2020-05-16 04:52:42 -05:00
|
|
|
check('concept', 'Iterator{{T, U}} {key}Another', {2: 'I00EX8IteratorI1T1UEE7Another'})
|
|
|
|
check('concept', 'template<typename ...Pack> {key}Numerics = (... && Numeric<Pack>)',
|
2017-12-23 06:20:32 -06:00
|
|
|
{2: 'IDpE8Numerics'})
|
2016-05-28 08:00:13 -05:00
|
|
|
|
2017-12-04 02:44:29 -06:00
|
|
|
# explicit specializations of members
|
2017-12-23 06:20:32 -06:00
|
|
|
check('member', 'template<> int A<int>::a', {2: 'IEN1AIiE1aE'})
|
2017-12-04 02:44:29 -06:00
|
|
|
check('member', 'template int A<int>::a', {2: 'IEN1AIiE1aE'},
|
|
|
|
output='template<> int A<int>::a') # same as above
|
2017-12-23 06:20:32 -06:00
|
|
|
check('member', 'template<> template<> int A<int>::B<int>::b', {2: 'IEIEN1AIiE1BIiE1bE'})
|
2017-12-04 02:44:29 -06:00
|
|
|
check('member', 'template int A<int>::B<int>::b', {2: 'IEIEN1AIiE1BIiE1bE'},
|
|
|
|
output='template<> template<> int A<int>::B<int>::b') # same as above
|
2017-03-19 22:19:48 -05:00
|
|
|
|
2017-12-20 02:05:34 -06:00
|
|
|
# defaulted constrained type parameters
|
2020-05-16 04:52:42 -05:00
|
|
|
check('type', 'template<C T = int&> {key}A', {2: 'I_1CE1A'}, key='using')
|
2017-12-20 02:05:34 -06:00
|
|
|
|
2022-07-29 10:49:01 -05:00
|
|
|
# pack expansion after non-type template parameter
|
|
|
|
check('type', 'template<int (X::*)(bool)...> {key}A', {2: 'I_DpM1XFibEE1A'}, key='using')
|
|
|
|
|
2017-05-09 07:57:36 -05:00
|
|
|
|
2021-06-24 15:32:23 -05:00
|
|
|
def test_domain_cpp_ast_placeholder_types():
|
|
|
|
check('function', 'void f(Sortable auto &v)', {1: 'f__SortableR', 2: '1fR8Sortable'})
|
|
|
|
check('function', 'void f(const Sortable auto &v)', {1: 'f__SortableCR', 2: '1fRK8Sortable'})
|
|
|
|
check('function', 'void f(Sortable decltype(auto) &v)', {1: 'f__SortableR', 2: '1fR8Sortable'})
|
|
|
|
check('function', 'void f(const Sortable decltype(auto) &v)', {1: 'f__SortableCR', 2: '1fRK8Sortable'})
|
|
|
|
check('function', 'void f(Sortable decltype ( auto ) &v)', {1: 'f__SortableR', 2: '1fR8Sortable'},
|
|
|
|
output='void f(Sortable decltype(auto) &v)')
|
|
|
|
|
|
|
|
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_ast_requires_clauses():
|
2020-05-16 02:52:47 -05:00
|
|
|
check('function', 'template<typename T> requires A auto f() -> void requires B',
|
|
|
|
{4: 'I0EIQaa1A1BE1fvv'})
|
|
|
|
check('function', 'template<typename T> requires A || B or C void f()',
|
|
|
|
{4: 'I0EIQoo1Aoo1B1CE1fvv'})
|
2022-03-27 13:08:21 -05:00
|
|
|
check('function', 'void f() requires A || B || C',
|
|
|
|
{4: 'IQoo1Aoo1B1CE1fv'})
|
2022-03-27 13:02:27 -05:00
|
|
|
check('function', 'Foo() requires A || B || C',
|
|
|
|
{4: 'IQoo1Aoo1B1CE3Foov'})
|
2020-05-16 02:52:47 -05:00
|
|
|
check('function', 'template<typename T> requires A && B || C and D void f()',
|
|
|
|
{4: 'I0EIQooaa1A1Baa1C1DE1fvv'})
|
[C++] Support requires-clause in more places
Previously a C++20 requires-clause was only supported on `function`
declarations. However, the C++ standard allows a require-clause on
class/union templates, alias templates, and variable templates, and
also allows a requires clause after each template parameter list, not
just the final one.
This moves the requiresClause to be a property of `ASTTemplateParams`
rather than `ASTDeclaration` to better match the C++ grammar and
allows requires clauses in many places that are supported by C++20 but
were not previously allowed by Sphinx, namely:
- On class templates, alias templates, and variable templates
- After each template parameter list, not just the last one.
- After the template parameter list in template template parameters.
When encoding the id, the requires clause of the last template
parameter list is treated specially in order to preserve compatibility
with existing v4 ids.
2022-03-21 19:28:20 -05:00
|
|
|
check('function',
|
|
|
|
'template<typename T> requires R<T> ' +
|
|
|
|
'template<typename U> requires S<T> ' +
|
|
|
|
'void A<T>::f() requires B',
|
2022-03-11 08:51:30 -06:00
|
|
|
{4: 'I0EIQ1RI1TEEI0EIQaa1SI1TE1BEN1A1fEvv'})
|
[C++] Support requires-clause in more places
Previously a C++20 requires-clause was only supported on `function`
declarations. However, the C++ standard allows a require-clause on
class/union templates, alias templates, and variable templates, and
also allows a requires clause after each template parameter list, not
just the final one.
This moves the requiresClause to be a property of `ASTTemplateParams`
rather than `ASTDeclaration` to better match the C++ grammar and
allows requires clauses in many places that are supported by C++20 but
were not previously allowed by Sphinx, namely:
- On class templates, alias templates, and variable templates
- After each template parameter list, not just the last one.
- After the template parameter list in template template parameters.
When encoding the id, the requires clause of the last template
parameter list is treated specially in order to preserve compatibility
with existing v4 ids.
2022-03-21 19:28:20 -05:00
|
|
|
check('function',
|
|
|
|
'template<template<typename T> requires R<T> typename X> ' +
|
|
|
|
'void f()',
|
|
|
|
{2: 'II0EIQ1RI1TEE0E1fv', 4: 'II0EIQ1RI1TEE0E1fvv'})
|
|
|
|
check('type',
|
|
|
|
'template<typename T> requires IsValid<T> {key}T = true_type',
|
|
|
|
{4: 'I0EIQ7IsValidI1TEE1T'}, key='using')
|
|
|
|
check('class',
|
|
|
|
'template<typename T> requires IsValid<T> {key}T : Base',
|
|
|
|
{4: 'I0EIQ7IsValidI1TEE1T'}, key='class')
|
2022-03-27 13:03:30 -05:00
|
|
|
check('union',
|
|
|
|
'template<typename T> requires IsValid<T> {key}T',
|
|
|
|
{4: 'I0EIQ7IsValidI1TEE1T'}, key='union')
|
[C++] Support requires-clause in more places
Previously a C++20 requires-clause was only supported on `function`
declarations. However, the C++ standard allows a require-clause on
class/union templates, alias templates, and variable templates, and
also allows a requires clause after each template parameter list, not
just the final one.
This moves the requiresClause to be a property of `ASTTemplateParams`
rather than `ASTDeclaration` to better match the C++ grammar and
allows requires clauses in many places that are supported by C++20 but
were not previously allowed by Sphinx, namely:
- On class templates, alias templates, and variable templates
- After each template parameter list, not just the last one.
- After the template parameter list in template template parameters.
When encoding the id, the requires clause of the last template
parameter list is treated specially in order to preserve compatibility
with existing v4 ids.
2022-03-21 19:28:20 -05:00
|
|
|
check('member',
|
|
|
|
'template<typename T> requires IsValid<T> int Val = 7',
|
|
|
|
{4: 'I0EIQ7IsValidI1TEE3Val'})
|
2020-05-16 02:52:47 -05:00
|
|
|
|
2017-05-09 07:57:36 -05:00
|
|
|
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_ast_template_args():
|
2017-03-12 00:03:20 -06:00
|
|
|
# from breathe#218
|
|
|
|
check('function',
|
|
|
|
"template<typename F> "
|
2017-03-19 22:19:48 -05:00
|
|
|
"void allow(F *f, typename func<F, B, G != 1>::type tt)",
|
2017-12-23 06:20:32 -06:00
|
|
|
{2: "I0E5allowP1FN4funcI1F1BXG != 1EE4typeE",
|
2019-01-05 11:43:36 -06:00
|
|
|
3: "I0E5allowP1FN4funcI1F1BXne1GL1EEE4typeE",
|
|
|
|
4: "I0E5allowvP1FN4funcI1F1BXne1GL1EEE4typeE"})
|
2017-03-12 00:03:20 -06:00
|
|
|
# from #3542
|
2020-05-16 04:52:42 -05:00
|
|
|
check('type', "template<typename T> {key}"
|
2017-03-12 00:03:20 -06:00
|
|
|
"enable_if_not_array_t = std::enable_if_t<!is_array<T>::value, int>",
|
2020-05-16 04:52:42 -05:00
|
|
|
{2: "I0E21enable_if_not_array_t"},
|
|
|
|
key='using')
|
2017-03-19 22:19:48 -05:00
|
|
|
|
2017-05-09 07:57:36 -05:00
|
|
|
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_ast_initializers():
|
2019-06-30 00:55:22 -05:00
|
|
|
idsMember = {1: 'v__T', 2: '1v'}
|
2019-03-16 11:29:53 -05:00
|
|
|
idsFunction = {1: 'f__T', 2: '1f1T'}
|
|
|
|
idsTemplate = {2: 'I_1TE1fv', 4: 'I_1TE1fvv'}
|
|
|
|
# no init
|
|
|
|
check('member', 'T v', idsMember)
|
|
|
|
check('function', 'void f(T v)', idsFunction)
|
|
|
|
check('function', 'template<T v> void f()', idsTemplate)
|
|
|
|
# with '=', assignment-expression
|
|
|
|
check('member', 'T v = 42', idsMember)
|
|
|
|
check('function', 'void f(T v = 42)', idsFunction)
|
|
|
|
check('function', 'template<T v = 42> void f()', idsTemplate)
|
|
|
|
# with '=', braced-init
|
|
|
|
check('member', 'T v = {}', idsMember)
|
|
|
|
check('function', 'void f(T v = {})', idsFunction)
|
|
|
|
check('function', 'template<T v = {}> void f()', idsTemplate)
|
|
|
|
check('member', 'T v = {42, 42, 42}', idsMember)
|
|
|
|
check('function', 'void f(T v = {42, 42, 42})', idsFunction)
|
|
|
|
check('function', 'template<T v = {42, 42, 42}> void f()', idsTemplate)
|
|
|
|
check('member', 'T v = {42, 42, 42,}', idsMember)
|
|
|
|
check('function', 'void f(T v = {42, 42, 42,})', idsFunction)
|
|
|
|
check('function', 'template<T v = {42, 42, 42,}> void f()', idsTemplate)
|
|
|
|
check('member', 'T v = {42, 42, args...}', idsMember)
|
|
|
|
check('function', 'void f(T v = {42, 42, args...})', idsFunction)
|
|
|
|
check('function', 'template<T v = {42, 42, args...}> void f()', idsTemplate)
|
|
|
|
# without '=', braced-init
|
|
|
|
check('member', 'T v{}', idsMember)
|
|
|
|
check('member', 'T v{42, 42, 42}', idsMember)
|
|
|
|
check('member', 'T v{42, 42, 42,}', idsMember)
|
|
|
|
check('member', 'T v{42, 42, args...}', idsMember)
|
|
|
|
# other
|
|
|
|
check('member', 'T v = T{}', idsMember)
|
|
|
|
|
|
|
|
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_ast_attributes():
|
2016-08-05 17:08:02 -05:00
|
|
|
# style: C++
|
2017-12-23 06:20:32 -06:00
|
|
|
check('member', '[[]] int f', {1: 'f__i', 2: '1f'})
|
|
|
|
check('member', '[ [ ] ] int f', {1: 'f__i', 2: '1f'},
|
2016-08-05 17:08:02 -05:00
|
|
|
# this will fail when the proper grammar is implemented
|
|
|
|
output='[[ ]] int f')
|
2017-12-23 06:20:32 -06:00
|
|
|
check('member', '[[a]] int f', {1: 'f__i', 2: '1f'})
|
2016-06-26 03:00:54 -05:00
|
|
|
# style: GNU
|
2017-12-23 06:20:32 -06:00
|
|
|
check('member', '__attribute__(()) int f', {1: 'f__i', 2: '1f'})
|
|
|
|
check('member', '__attribute__((a)) int f', {1: 'f__i', 2: '1f'})
|
|
|
|
check('member', '__attribute__((a, b)) int f', {1: 'f__i', 2: '1f'})
|
2020-06-20 02:55:35 -05:00
|
|
|
check('member', '__attribute__((optimize(3))) int f', {1: 'f__i', 2: '1f'})
|
|
|
|
check('member', '__attribute__((format(printf, 1, 2))) int f', {1: 'f__i', 2: '1f'})
|
2016-08-05 17:08:02 -05:00
|
|
|
# style: user-defined id
|
2017-12-23 06:20:32 -06:00
|
|
|
check('member', 'id_attr int f', {1: 'f__i', 2: '1f'})
|
2016-08-05 17:08:02 -05:00
|
|
|
# style: user-defined paren
|
2017-12-23 06:20:32 -06:00
|
|
|
check('member', 'paren_attr() int f', {1: 'f__i', 2: '1f'})
|
|
|
|
check('member', 'paren_attr(a) int f', {1: 'f__i', 2: '1f'})
|
|
|
|
check('member', 'paren_attr("") int f', {1: 'f__i', 2: '1f'})
|
|
|
|
check('member', 'paren_attr(()[{}][]{}) int f', {1: 'f__i', 2: '1f'})
|
2017-01-05 09:46:42 -06:00
|
|
|
with pytest.raises(DefinitionError):
|
|
|
|
parse('member', 'paren_attr(() int f')
|
|
|
|
with pytest.raises(DefinitionError):
|
|
|
|
parse('member', 'paren_attr([) int f')
|
|
|
|
with pytest.raises(DefinitionError):
|
|
|
|
parse('member', 'paren_attr({) int f')
|
|
|
|
with pytest.raises(DefinitionError):
|
|
|
|
parse('member', 'paren_attr([)]) int f')
|
|
|
|
with pytest.raises(DefinitionError):
|
|
|
|
parse('member', 'paren_attr((])) int f')
|
|
|
|
with pytest.raises(DefinitionError):
|
|
|
|
parse('member', 'paren_attr({]}) int f')
|
2016-06-26 03:00:54 -05:00
|
|
|
|
|
|
|
# position: decl specs
|
|
|
|
check('function', 'static inline __attribute__(()) void f()',
|
2017-12-23 06:20:32 -06:00
|
|
|
{1: 'f', 2: '1fv'},
|
2016-06-26 03:00:54 -05:00
|
|
|
output='__attribute__(()) static inline void f()')
|
2020-08-13 11:39:28 -05:00
|
|
|
check('function', '[[attr1]] [[attr2]] void f()', {1: 'f', 2: '1fv'})
|
2018-08-11 09:39:27 -05:00
|
|
|
# position: declarator
|
2022-04-17 10:17:19 -05:00
|
|
|
check('member', 'int *[[attr1]] [[attr2]] i', {1: 'i__iP', 2: '1i'})
|
|
|
|
check('member', 'int *const [[attr1]] [[attr2]] volatile i', {1: 'i__iPVC', 2: '1i'},
|
|
|
|
output='int *[[attr1]] [[attr2]] volatile const i')
|
|
|
|
check('member', 'int &[[attr1]] [[attr2]] i', {1: 'i__iR', 2: '1i'})
|
|
|
|
check('member', 'int *[[attr1]] [[attr2]] *i', {1: 'i__iPP', 2: '1i'})
|
2020-08-13 11:39:28 -05:00
|
|
|
# position: parameters and qualifiers
|
|
|
|
check('function', 'void f() [[attr1]] [[attr2]]', {1: 'f', 2: '1fv'})
|
2016-06-26 03:00:54 -05:00
|
|
|
|
2022-03-12 13:05:26 -06:00
|
|
|
# position: class, union, enum
|
2022-04-17 10:17:19 -05:00
|
|
|
check('class', '{key}[[attr1]] [[attr2]] Foo', {1: 'Foo', 2: '3Foo'}, key='class')
|
2022-04-17 10:27:30 -05:00
|
|
|
check('union', '{key}[[attr1]] [[attr2]] Foo', {2: '3Foo'}, key='union')
|
|
|
|
check('enum', '{key}[[attr1]] [[attr2]] Foo', {2: '3Foo'}, key='enum')
|
|
|
|
# position: enumerator
|
|
|
|
check('enumerator', '{key}Foo [[attr1]] [[attr2]]', {2: '3Foo'})
|
|
|
|
check('enumerator', '{key}Foo [[attr1]] [[attr2]] = 42', {2: '3Foo'})
|
2022-03-11 00:03:42 -06:00
|
|
|
|
2016-06-26 03:00:54 -05:00
|
|
|
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_ast_xref_parsing():
|
2019-03-30 07:42:55 -05:00
|
|
|
def check(target):
|
|
|
|
class Config:
|
|
|
|
cpp_id_attributes = ["id_attr"]
|
|
|
|
cpp_paren_attributes = ["paren_attr"]
|
2020-03-17 06:56:09 -05:00
|
|
|
parser = DefinitionParser(target, location=None,
|
|
|
|
config=Config())
|
2019-03-30 07:42:55 -05:00
|
|
|
ast, isShorthand = parser.parse_xref_object()
|
|
|
|
parser.assert_end()
|
|
|
|
check('f')
|
|
|
|
check('f()')
|
|
|
|
check('void f()')
|
|
|
|
check('T f()')
|
|
|
|
|
|
|
|
|
2022-07-29 11:21:34 -05:00
|
|
|
@pytest.mark.parametrize(
|
2023-07-28 01:02:40 -05:00
|
|
|
("param", "is_pack"),
|
2022-07-29 11:21:34 -05:00
|
|
|
[('typename', False),
|
|
|
|
('typename T', False),
|
|
|
|
('typename...', True),
|
|
|
|
('typename... T', True),
|
|
|
|
('int', False),
|
|
|
|
('int N', False),
|
|
|
|
('int* N', False),
|
|
|
|
('int& N', False),
|
|
|
|
('int&... N', True),
|
|
|
|
('int*... N', True),
|
|
|
|
('int...', True),
|
|
|
|
('int... N', True),
|
|
|
|
('auto', False),
|
|
|
|
('auto...', True),
|
|
|
|
('int X::*', False),
|
|
|
|
('int X::*...', True),
|
|
|
|
('int (X::*)(bool)', False),
|
|
|
|
('int (X::*x)(bool)', False),
|
|
|
|
('int (X::*)(bool)...', True),
|
|
|
|
('template<typename> class', False),
|
|
|
|
('template<typename> class...', True),
|
|
|
|
])
|
|
|
|
def test_domain_cpp_template_parameters_is_pack(param: str, is_pack: bool):
|
|
|
|
def parse_template_parameter(param: str):
|
|
|
|
ast = parse('type', 'template<' + param + '> X')
|
|
|
|
return ast.templatePrefix.templates[0].params[0]
|
|
|
|
ast = parse_template_parameter(param)
|
|
|
|
assert ast.isPack == is_pack
|
|
|
|
|
|
|
|
|
2016-06-11 10:00:52 -05:00
|
|
|
# def test_print():
|
|
|
|
# # used for getting all the ids out for checking
|
|
|
|
# for a in ids:
|
|
|
|
# print(a)
|
2023-08-13 14:07:28 -05:00
|
|
|
# raise DefinitionError
|
2015-12-27 01:29:07 -06:00
|
|
|
|
|
|
|
|
2020-01-20 12:20:35 -06:00
|
|
|
def filter_warnings(warning, file):
|
2020-04-14 17:10:13 -05:00
|
|
|
lines = warning.getvalue().split("\n")
|
2022-10-17 09:54:59 -05:00
|
|
|
res = [l for l in lines if "domain-cpp" in l and f"{file}.rst" in l and
|
2020-01-20 12:20:35 -06:00
|
|
|
"WARNING: document isn't included in any toctree" not in l]
|
2022-10-17 09:54:59 -05:00
|
|
|
print(f"Filtered warnings for file '{file}':")
|
2020-01-20 12:20:35 -06:00
|
|
|
for w in res:
|
|
|
|
print(w)
|
|
|
|
return res
|
|
|
|
|
|
|
|
|
2020-01-24 16:18:48 -06:00
|
|
|
@pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'nitpicky': True})
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_build_multi_decl_lookup(app, status, warning):
|
2020-01-24 15:24:36 -06:00
|
|
|
app.builder.build_all()
|
|
|
|
ws = filter_warnings(warning, "lookup-key-overload")
|
|
|
|
assert len(ws) == 0
|
|
|
|
|
2020-01-24 16:18:48 -06:00
|
|
|
ws = filter_warnings(warning, "multi-decl-lookup")
|
|
|
|
assert len(ws) == 0
|
|
|
|
|
2020-01-24 15:24:36 -06:00
|
|
|
|
2020-01-26 07:19:14 -06:00
|
|
|
@pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'nitpicky': True})
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_build_warn_template_param_qualified_name(app, status, warning):
|
2020-01-26 07:19:14 -06:00
|
|
|
app.builder.build_all()
|
|
|
|
ws = filter_warnings(warning, "warn-template-param-qualified-name")
|
|
|
|
assert len(ws) == 2
|
|
|
|
assert "WARNING: cpp:type reference target not found: T::typeWarn" in ws[0]
|
|
|
|
assert "WARNING: cpp:type reference target not found: T::U::typeWarn" in ws[1]
|
|
|
|
|
|
|
|
|
2020-03-20 06:55:42 -05:00
|
|
|
@pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'nitpicky': True})
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_build_backslash_ok_true(app, status, warning):
|
2020-03-20 06:55:42 -05:00
|
|
|
app.builder.build_all()
|
|
|
|
ws = filter_warnings(warning, "backslash")
|
|
|
|
assert len(ws) == 0
|
|
|
|
|
|
|
|
|
2020-04-24 03:57:23 -05:00
|
|
|
@pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'nitpicky': True})
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_build_semicolon(app, status, warning):
|
2020-04-24 03:57:23 -05:00
|
|
|
app.builder.build_all()
|
|
|
|
ws = filter_warnings(warning, "semicolon")
|
|
|
|
assert len(ws) == 0
|
|
|
|
|
|
|
|
|
2020-03-20 06:55:42 -05:00
|
|
|
@pytest.mark.sphinx(testroot='domain-cpp',
|
|
|
|
confoverrides={'nitpicky': True, 'strip_signature_backslash': True})
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_build_backslash_ok_false(app, status, warning):
|
2020-03-20 06:55:42 -05:00
|
|
|
app.builder.build_all()
|
|
|
|
ws = filter_warnings(warning, "backslash")
|
|
|
|
assert len(ws) == 1
|
|
|
|
assert "WARNING: Parsing of expression failed. Using fallback parser." in ws[0]
|
|
|
|
|
|
|
|
|
2020-03-25 14:07:16 -05:00
|
|
|
@pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'nitpicky': True})
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_build_anon_dup_decl(app, status, warning):
|
2020-03-25 14:07:16 -05:00
|
|
|
app.builder.build_all()
|
|
|
|
ws = filter_warnings(warning, "anon-dup-decl")
|
|
|
|
assert len(ws) == 2
|
|
|
|
assert "WARNING: cpp:identifier reference target not found: @a" in ws[0]
|
|
|
|
assert "WARNING: cpp:identifier reference target not found: @b" in ws[1]
|
|
|
|
|
|
|
|
|
2017-10-03 07:35:10 -05:00
|
|
|
@pytest.mark.sphinx(testroot='domain-cpp')
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_build_misuse_of_roles(app, status, warning):
|
2017-10-03 07:35:10 -05:00
|
|
|
app.builder.build_all()
|
2020-01-20 12:20:35 -06:00
|
|
|
ws = filter_warnings(warning, "roles-targets-ok")
|
|
|
|
assert len(ws) == 0
|
|
|
|
|
|
|
|
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']),
|
|
|
|
('functionParam', ['member', 'var']),
|
2021-01-11 13:27:53 -06:00
|
|
|
('templateParam', ['class', 'struct', 'union', 'member', 'var', 'type']),
|
2020-01-20 12:20:35 -06:00
|
|
|
]
|
|
|
|
warn = []
|
|
|
|
for targetType, roles in ok:
|
|
|
|
txtTargetType = "function" if targetType == "func" else targetType
|
|
|
|
for r in allRoles:
|
|
|
|
if r not in roles:
|
2022-10-17 09:54:59 -05:00
|
|
|
warn.append(f"WARNING: cpp:{r} targets a {txtTargetType} (")
|
2021-01-11 13:27:53 -06:00
|
|
|
if targetType == 'templateParam':
|
2022-10-17 09:54:59 -05:00
|
|
|
warn.append(f"WARNING: cpp:{r} targets a {txtTargetType} (")
|
|
|
|
warn.append(f"WARNING: cpp:{r} targets a {txtTargetType} (")
|
2022-01-09 10:52:03 -06:00
|
|
|
warn = sorted(warn)
|
2020-01-20 12:20:35 -06:00
|
|
|
for w in ws:
|
|
|
|
assert "targets a" in w
|
|
|
|
ws = [w[w.index("WARNING:"):] for w in ws]
|
2022-01-09 10:52:03 -06:00
|
|
|
ws = sorted(ws)
|
2020-01-20 12:20:35 -06:00
|
|
|
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)
|
2017-10-03 07:35:10 -05:00
|
|
|
|
|
|
|
|
2017-01-05 10:14:47 -06:00
|
|
|
@pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'add_function_parentheses': True})
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_build_with_add_function_parentheses_is_True(app, status, warning):
|
2015-12-27 01:29:07 -06:00
|
|
|
app.builder.build_all()
|
|
|
|
|
2016-01-27 22:19:23 -06:00
|
|
|
def check(spec, text, file):
|
2019-01-02 10:05:16 -06:00
|
|
|
pattern = '<li><p>%s<a .*?><code .*?><span .*?>%s</span></code></a></p></li>' % spec
|
2016-01-27 22:19:23 -06:00
|
|
|
res = re.search(pattern, text)
|
|
|
|
if not res:
|
2023-01-01 18:01:14 -06:00
|
|
|
print(f"Pattern\n\t{pattern}\nnot found in {file}")
|
2023-07-28 01:05:56 -05:00
|
|
|
raise AssertionError
|
2016-01-27 22:19:23 -06:00
|
|
|
rolePatterns = [
|
|
|
|
('', 'Sphinx'),
|
|
|
|
('', 'Sphinx::version'),
|
|
|
|
('', 'version'),
|
|
|
|
('', 'List'),
|
2023-02-17 16:11:14 -06:00
|
|
|
('', 'MyEnum'),
|
2016-01-27 22:19:23 -06:00
|
|
|
]
|
|
|
|
parenPatterns = [
|
2017-02-12 11:02:51 -06:00
|
|
|
('ref function without parens ', r'paren_1\(\)'),
|
|
|
|
('ref function with parens ', r'paren_2\(\)'),
|
2016-01-27 22:19:23 -06:00
|
|
|
('ref function without parens, explicit title ', 'paren_3_title'),
|
2017-01-14 23:36:29 -06:00
|
|
|
('ref function with parens, explicit title ', 'paren_4_title'),
|
2017-02-12 11:02:51 -06:00
|
|
|
('ref op call without parens ', r'paren_5::operator\(\)\(\)'),
|
|
|
|
('ref op call with parens ', r'paren_6::operator\(\)\(\)'),
|
2017-01-14 23:36:29 -06:00
|
|
|
('ref op call without parens, explicit title ', 'paren_7_title'),
|
2023-02-17 16:11:14 -06:00
|
|
|
('ref op call with parens, explicit title ', 'paren_8_title'),
|
2016-01-27 22:19:23 -06:00
|
|
|
]
|
|
|
|
|
|
|
|
f = 'roles.html'
|
2022-04-26 21:04:19 -05:00
|
|
|
t = (app.outdir / f).read_text(encoding='utf8')
|
2016-01-27 22:19:23 -06:00
|
|
|
for s in rolePatterns:
|
|
|
|
check(s, t, f)
|
|
|
|
for s in parenPatterns:
|
|
|
|
check(s, t, f)
|
|
|
|
|
|
|
|
f = 'any-role.html'
|
2022-04-26 21:04:19 -05:00
|
|
|
t = (app.outdir / f).read_text(encoding='utf8')
|
2016-01-27 22:19:23 -06:00
|
|
|
for s in parenPatterns:
|
|
|
|
check(s, t, f)
|
2015-12-27 01:29:07 -06:00
|
|
|
|
|
|
|
|
2019-01-02 10:05:16 -06:00
|
|
|
@pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'add_function_parentheses': False})
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_build_with_add_function_parentheses_is_False(app, status, warning):
|
2015-12-27 01:29:07 -06:00
|
|
|
app.builder.build_all()
|
|
|
|
|
2016-01-27 22:19:23 -06:00
|
|
|
def check(spec, text, file):
|
2019-01-02 10:05:16 -06:00
|
|
|
pattern = '<li><p>%s<a .*?><code .*?><span .*?>%s</span></code></a></p></li>' % spec
|
2016-01-27 22:19:23 -06:00
|
|
|
res = re.search(pattern, text)
|
|
|
|
if not res:
|
2023-01-01 18:01:14 -06:00
|
|
|
print(f"Pattern\n\t{pattern}\nnot found in {file}")
|
2023-07-28 01:05:56 -05:00
|
|
|
raise AssertionError
|
2016-01-27 22:19:23 -06:00
|
|
|
rolePatterns = [
|
|
|
|
('', 'Sphinx'),
|
|
|
|
('', 'Sphinx::version'),
|
|
|
|
('', 'version'),
|
|
|
|
('', 'List'),
|
2023-02-17 16:11:14 -06:00
|
|
|
('', 'MyEnum'),
|
2016-01-27 22:19:23 -06:00
|
|
|
]
|
|
|
|
parenPatterns = [
|
|
|
|
('ref function without parens ', 'paren_1'),
|
|
|
|
('ref function with parens ', 'paren_2'),
|
|
|
|
('ref function without parens, explicit title ', 'paren_3_title'),
|
2017-01-14 23:36:29 -06:00
|
|
|
('ref function with parens, explicit title ', 'paren_4_title'),
|
2017-02-12 11:02:51 -06:00
|
|
|
('ref op call without parens ', r'paren_5::operator\(\)'),
|
|
|
|
('ref op call with parens ', r'paren_6::operator\(\)'),
|
2017-01-14 23:36:29 -06:00
|
|
|
('ref op call without parens, explicit title ', 'paren_7_title'),
|
2023-02-17 16:11:14 -06:00
|
|
|
('ref op call with parens, explicit title ', 'paren_8_title'),
|
2016-01-27 22:19:23 -06:00
|
|
|
]
|
|
|
|
|
|
|
|
f = 'roles.html'
|
2022-04-26 21:04:19 -05:00
|
|
|
t = (app.outdir / f).read_text(encoding='utf8')
|
2016-01-27 22:19:23 -06:00
|
|
|
for s in rolePatterns:
|
|
|
|
check(s, t, f)
|
|
|
|
for s in parenPatterns:
|
|
|
|
check(s, t, f)
|
|
|
|
|
|
|
|
f = 'any-role.html'
|
2022-04-26 21:04:19 -05:00
|
|
|
t = (app.outdir / f).read_text(encoding='utf8')
|
2016-01-27 22:19:23 -06:00
|
|
|
for s in parenPatterns:
|
|
|
|
check(s, t, f)
|
2018-05-26 10:25:41 -05:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.sphinx(testroot='domain-cpp')
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_build_xref_consistency(app, status, warning):
|
2018-05-26 10:25:41 -05:00
|
|
|
app.builder.build_all()
|
|
|
|
|
|
|
|
test = 'xref_consistency.html'
|
2022-04-26 21:04:19 -05:00
|
|
|
output = (app.outdir / test).read_text(encoding='utf8')
|
2018-05-26 10:25:41 -05:00
|
|
|
|
|
|
|
def classes(role, tag):
|
2023-01-01 18:01:14 -06:00
|
|
|
pattern = (fr'{role}-role:.*?'
|
|
|
|
fr'<(?P<tag>{tag}) .*?class=["\'](?P<classes>.*?)["\'].*?>'
|
2018-07-28 06:19:30 -05:00
|
|
|
r'.*'
|
2023-01-01 18:01:14 -06:00
|
|
|
r'</(?P=tag)>')
|
2018-05-26 10:25:41 -05:00
|
|
|
result = re.search(pattern, output)
|
2023-01-01 18:01:14 -06:00
|
|
|
expect = f'''\
|
2018-05-26 10:25:41 -05:00
|
|
|
Pattern for role `{role}` with tag `{tag}`
|
|
|
|
\t{pattern}
|
|
|
|
not found in `{test}`
|
2023-01-01 18:01:14 -06:00
|
|
|
'''
|
2018-05-26 10:25:41 -05:00
|
|
|
assert result, expect
|
|
|
|
return set(result.group('classes').split())
|
|
|
|
|
2018-09-11 08:48:35 -05:00
|
|
|
class RoleClasses:
|
2018-05-26 10:25:41 -05:00
|
|
|
"""Collect the classes from the layout that was generated for a given role."""
|
|
|
|
|
|
|
|
def __init__(self, role, root, contents):
|
|
|
|
self.name = role
|
|
|
|
self.classes = classes(role, root)
|
2022-06-26 08:43:05 -05:00
|
|
|
self.content_classes = {}
|
2018-05-26 10:25:41 -05:00
|
|
|
for tag in contents:
|
|
|
|
self.content_classes[tag] = classes(role, tag)
|
|
|
|
|
|
|
|
# not actually used as a reference point
|
2018-07-28 06:19:30 -05:00
|
|
|
# code_role = RoleClasses('code', 'code', [])
|
2018-05-26 10:25:41 -05:00
|
|
|
any_role = RoleClasses('any', 'a', ['code'])
|
|
|
|
cpp_any_role = RoleClasses('cpp-any', 'a', ['code'])
|
|
|
|
# NYI: consistent looks
|
2018-07-28 06:19:30 -05:00
|
|
|
# texpr_role = RoleClasses('cpp-texpr', 'span', ['a', 'code'])
|
2021-03-20 13:27:13 -05:00
|
|
|
expr_role = RoleClasses('cpp-expr', 'span', ['a'])
|
2018-05-26 10:25:41 -05:00
|
|
|
texpr_role = RoleClasses('cpp-texpr', 'span', ['a', 'span'])
|
|
|
|
|
|
|
|
# XRefRole-style classes
|
|
|
|
|
2018-07-28 06:19:30 -05:00
|
|
|
# any and cpp:any do not put these classes at the root
|
2018-05-26 10:25:41 -05:00
|
|
|
|
|
|
|
# n.b. the generic any machinery finds the specific 'cpp-class' object type
|
|
|
|
expect = 'any uses XRefRole classes'
|
|
|
|
assert {'xref', 'any', 'cpp', 'cpp-class'} <= any_role.content_classes['code'], expect
|
|
|
|
|
|
|
|
expect = 'cpp:any uses XRefRole classes'
|
|
|
|
assert {'xref', 'cpp-any', 'cpp'} <= cpp_any_role.content_classes['code'], expect
|
|
|
|
|
|
|
|
for role in (expr_role, texpr_role):
|
|
|
|
name = role.name
|
2022-10-17 09:54:59 -05:00
|
|
|
expect = f'`{name}` puts the domain and role classes at its root'
|
2021-03-20 13:27:13 -05:00
|
|
|
assert {'sig', 'sig-inline', 'cpp', name} <= role.classes, expect
|
2018-05-26 10:25:41 -05:00
|
|
|
|
|
|
|
# reference classes
|
|
|
|
|
|
|
|
expect = 'the xref roles use the same reference classes'
|
|
|
|
assert any_role.classes == cpp_any_role.classes, expect
|
|
|
|
assert any_role.classes == expr_role.content_classes['a'], expect
|
|
|
|
assert any_role.classes == texpr_role.content_classes['a'], expect
|
2020-07-04 13:16:04 -05:00
|
|
|
|
|
|
|
|
2021-06-03 09:45:13 -05:00
|
|
|
@pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'nitpicky': True})
|
2021-06-03 12:45:44 -05:00
|
|
|
def test_domain_cpp_build_field_role(app, status, warning):
|
2021-06-03 09:45:13 -05:00
|
|
|
app.builder.build_all()
|
|
|
|
ws = filter_warnings(warning, "field-role")
|
|
|
|
assert len(ws) == 0
|
|
|
|
|
|
|
|
|
2021-01-11 13:27:53 -06:00
|
|
|
@pytest.mark.sphinx(testroot='domain-cpp-intersphinx', confoverrides={'nitpicky': True})
|
2023-07-27 18:39:12 -05:00
|
|
|
def test_domain_cpp_build_intersphinx(tmp_path, app, status, warning):
|
2021-01-11 13:27:53 -06:00
|
|
|
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<typename T> _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<typename TParam> void _templateParam()
|
2022-12-15 11:22:07 -06:00
|
|
|
""" # noqa: F841
|
2023-07-27 18:39:12 -05:00
|
|
|
inv_file = tmp_path / 'inventory'
|
2021-01-11 13:27:53 -06:00
|
|
|
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$ -
|
2022-12-15 11:22:07 -06:00
|
|
|
''')) # noqa: W291
|
2021-01-11 13:27:53 -06:00
|
|
|
app.config.intersphinx_mapping = {
|
2023-07-27 18:39:12 -05:00
|
|
|
'https://localhost/intersphinx/cpp/': str(inv_file),
|
2021-01-11 13:27:53 -06:00
|
|
|
}
|
|
|
|
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
|
2021-06-03 12:45:44 -05:00
|
|
|
|
|
|
|
|
2023-07-28 16:30:26 -05:00
|
|
|
def test_domain_cpp_parse_no_index_entry(app):
|
2021-06-03 12:45:44 -05:00
|
|
|
text = (".. cpp:function:: void f()\n"
|
|
|
|
".. cpp:function:: void g()\n"
|
2023-07-28 16:30:26 -05:00
|
|
|
" :no-index-entry:\n")
|
2021-06-03 12:45:44 -05:00
|
|
|
doctree = restructuredtext.parse(app, text)
|
|
|
|
assert_node(doctree, (addnodes.index, desc, addnodes.index, desc))
|
|
|
|
assert_node(doctree[0], addnodes.index, entries=[('single', 'f (C++ function)', '_CPPv41fv', '', None)])
|
|
|
|
assert_node(doctree[2], addnodes.index, entries=[])
|
|
|
|
|
|
|
|
|
|
|
|
def test_domain_cpp_parse_mix_decl_duplicate(app, warning):
|
|
|
|
# Issue 8270
|
|
|
|
text = (".. cpp:struct:: A\n"
|
|
|
|
".. cpp:function:: void A()\n"
|
|
|
|
".. cpp:struct:: A\n")
|
|
|
|
restructuredtext.parse(app, text)
|
|
|
|
ws = warning.getvalue().split("\n")
|
|
|
|
assert len(ws) == 5
|
|
|
|
assert "index.rst:2: WARNING: Duplicate C++ declaration, also defined at index:1." in ws[0]
|
|
|
|
assert "Declaration is '.. cpp:function:: void A()'." in ws[1]
|
|
|
|
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] == ""
|
2022-03-11 08:51:30 -06:00
|
|
|
|
|
|
|
|
|
|
|
# For some reason, using the default testroot of "root" leads to the contents of
|
|
|
|
# `test-root/objects.txt` polluting the symbol table depending on the test
|
|
|
|
# execution order. Using a testroot of "config" seems to avoid that problem.
|
|
|
|
@pytest.mark.sphinx(testroot='config')
|
|
|
|
def test_domain_cpp_normalize_unspecialized_template_args(make_app, app_params):
|
|
|
|
args, kwargs = app_params
|
|
|
|
|
|
|
|
text1 = (".. cpp:class:: template <typename T> A\n")
|
|
|
|
text2 = (".. cpp:class:: template <typename T> template <typename U> A<T>::B\n")
|
|
|
|
|
|
|
|
app1 = make_app(*args, **kwargs)
|
|
|
|
restructuredtext.parse(app=app1, text=text1, docname='text1')
|
|
|
|
root1 = app1.env.domaindata['cpp']['root_symbol']
|
|
|
|
|
|
|
|
assert root1.dump(1) == (
|
|
|
|
' ::\n'
|
|
|
|
' template<typename T> \n'
|
2022-07-29 10:22:14 -05:00
|
|
|
' A: {class} template<typename T> A\t(text1)\n'
|
|
|
|
' T: {templateParam} typename T\t(text1)\n'
|
2022-03-11 08:51:30 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
app2 = make_app(*args, **kwargs)
|
|
|
|
restructuredtext.parse(app=app2, text=text2, docname='text2')
|
|
|
|
root2 = app2.env.domaindata['cpp']['root_symbol']
|
|
|
|
|
|
|
|
assert root2.dump(1) == (
|
|
|
|
' ::\n'
|
|
|
|
' template<typename T> \n'
|
|
|
|
' A\n'
|
|
|
|
' T\n'
|
|
|
|
' template<typename U> \n'
|
2022-07-29 10:22:14 -05:00
|
|
|
' B: {class} template<typename T> template<typename U> A<T>::B\t(text2)\n'
|
|
|
|
' U: {templateParam} typename U\t(text2)\n'
|
2022-03-11 08:51:30 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
root2.merge_with(root1, ['text1'], app2.env)
|
|
|
|
|
|
|
|
assert root2.dump(1) == (
|
|
|
|
' ::\n'
|
|
|
|
' template<typename T> \n'
|
2022-07-29 10:22:14 -05:00
|
|
|
' A: {class} template<typename T> A\t(text1)\n'
|
|
|
|
' T: {templateParam} typename T\t(text1)\n'
|
2022-03-11 08:51:30 -06:00
|
|
|
' template<typename U> \n'
|
2022-07-29 10:22:14 -05:00
|
|
|
' B: {class} template<typename T> template<typename U> A<T>::B\t(text2)\n'
|
|
|
|
' U: {templateParam} typename U\t(text2)\n'
|
2022-03-11 08:51:30 -06:00
|
|
|
)
|
|
|
|
warning = app2._warning.getvalue()
|
|
|
|
assert 'Internal C++ domain error during symbol merging' not in warning
|
2023-05-11 08:28:57 -05:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.sphinx('html', confoverrides={
|
|
|
|
'cpp_maximum_signature_line_length': len('str hello(str name)'),
|
|
|
|
})
|
|
|
|
def test_cpp_function_signature_with_cpp_maximum_signature_line_length_equal(app):
|
|
|
|
text = '.. cpp:function:: str hello(str name)'
|
|
|
|
doctree = restructuredtext.parse(app, text)
|
|
|
|
assert_node(doctree, (
|
|
|
|
addnodes.index,
|
|
|
|
[desc, (
|
|
|
|
[desc_signature, (
|
|
|
|
[desc_signature_line, (
|
|
|
|
pending_xref,
|
|
|
|
desc_sig_space,
|
|
|
|
[desc_name, [desc_sig_name, 'hello']],
|
|
|
|
desc_parameterlist,
|
|
|
|
)],
|
|
|
|
)],
|
|
|
|
desc_content,
|
|
|
|
)],
|
|
|
|
))
|
|
|
|
assert_node(doctree[1], addnodes.desc, desctype='function',
|
2023-07-28 16:30:26 -05:00
|
|
|
domain='cpp', objtype='function', no_index=False)
|
2023-05-11 08:28:57 -05:00
|
|
|
assert_node(doctree[1][0][0][3], [desc_parameterlist, desc_parameter, (
|
|
|
|
[pending_xref, [desc_sig_name, 'str']],
|
|
|
|
desc_sig_space,
|
|
|
|
[desc_sig_name, 'name'],
|
|
|
|
)])
|
|
|
|
assert_node(doctree[1][0][0][3], desc_parameterlist, multi_line_parameter_list=False)
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.sphinx('html', confoverrides={
|
|
|
|
'cpp_maximum_signature_line_length': len('str hello(str name)'),
|
|
|
|
})
|
|
|
|
def test_cpp_function_signature_with_cpp_maximum_signature_line_length_force_single(app):
|
|
|
|
text = ('.. cpp:function:: str hello(str names)\n'
|
|
|
|
' :single-line-parameter-list:')
|
|
|
|
doctree = restructuredtext.parse(app, text)
|
|
|
|
assert_node(doctree, (
|
|
|
|
addnodes.index,
|
|
|
|
[desc, (
|
|
|
|
[desc_signature, (
|
|
|
|
[desc_signature_line, (
|
|
|
|
pending_xref,
|
|
|
|
desc_sig_space,
|
|
|
|
[desc_name, [desc_sig_name, 'hello']],
|
|
|
|
desc_parameterlist,
|
|
|
|
)],
|
|
|
|
)],
|
|
|
|
desc_content,
|
|
|
|
)],
|
|
|
|
))
|
|
|
|
assert_node(doctree[1], addnodes.desc, desctype='function',
|
2023-07-28 16:30:26 -05:00
|
|
|
domain='cpp', objtype='function', no_index=False)
|
2023-05-11 08:28:57 -05:00
|
|
|
assert_node(doctree[1][0][0][3], [desc_parameterlist, desc_parameter, (
|
|
|
|
[pending_xref, [desc_sig_name, 'str']],
|
|
|
|
desc_sig_space,
|
|
|
|
[desc_sig_name, 'names']),
|
|
|
|
])
|
|
|
|
assert_node(doctree[1][0][0][3], desc_parameterlist, multi_line_parameter_list=False)
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.sphinx('html', confoverrides={
|
|
|
|
'cpp_maximum_signature_line_length': len("str hello(str name)"),
|
|
|
|
})
|
|
|
|
def test_cpp_function_signature_with_cpp_maximum_signature_line_length_break(app):
|
|
|
|
text = '.. cpp:function:: str hello(str names)'
|
|
|
|
doctree = restructuredtext.parse(app, text)
|
|
|
|
assert_node(doctree, (
|
|
|
|
addnodes.index,
|
|
|
|
[desc, (
|
|
|
|
[desc_signature, (
|
|
|
|
[desc_signature_line, (
|
|
|
|
pending_xref,
|
|
|
|
desc_sig_space,
|
|
|
|
[desc_name, [desc_sig_name, 'hello']],
|
|
|
|
desc_parameterlist,
|
|
|
|
)],
|
|
|
|
)],
|
|
|
|
desc_content,
|
|
|
|
)],
|
|
|
|
))
|
|
|
|
assert_node(doctree[1], addnodes.desc, desctype='function',
|
2023-07-28 16:30:26 -05:00
|
|
|
domain='cpp', objtype='function', no_index=False)
|
2023-05-11 08:28:57 -05:00
|
|
|
assert_node(doctree[1][0][0][3], [desc_parameterlist, desc_parameter, (
|
|
|
|
[pending_xref, [desc_sig_name, 'str']],
|
|
|
|
desc_sig_space,
|
|
|
|
[desc_sig_name, 'names']),
|
|
|
|
])
|
|
|
|
assert_node(doctree[1][0][0][3], desc_parameterlist, multi_line_parameter_list=True)
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.sphinx('html', confoverrides={
|
|
|
|
'maximum_signature_line_length': len('str hello(str name)'),
|
|
|
|
})
|
|
|
|
def test_cpp_function_signature_with_maximum_signature_line_length_equal(app):
|
|
|
|
text = '.. cpp:function:: str hello(str name)'
|
|
|
|
doctree = restructuredtext.parse(app, text)
|
|
|
|
assert_node(doctree, (
|
|
|
|
addnodes.index,
|
|
|
|
[desc, (
|
|
|
|
[desc_signature, (
|
|
|
|
[desc_signature_line, (
|
|
|
|
pending_xref,
|
|
|
|
desc_sig_space,
|
|
|
|
[desc_name, [desc_sig_name, 'hello']],
|
|
|
|
desc_parameterlist,
|
|
|
|
)],
|
|
|
|
)],
|
|
|
|
desc_content,
|
|
|
|
)],
|
|
|
|
))
|
|
|
|
assert_node(doctree[1], addnodes.desc, desctype='function',
|
2023-07-28 16:30:26 -05:00
|
|
|
domain='cpp', objtype='function', no_index=False)
|
2023-05-11 08:28:57 -05:00
|
|
|
assert_node(doctree[1][0][0][3], [desc_parameterlist, desc_parameter, (
|
|
|
|
[pending_xref, [desc_sig_name, 'str']],
|
|
|
|
desc_sig_space,
|
|
|
|
[desc_sig_name, 'name'],
|
|
|
|
)])
|
|
|
|
assert_node(doctree[1][0][0][3], desc_parameterlist, multi_line_parameter_list=False)
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.sphinx('html', confoverrides={
|
|
|
|
'maximum_signature_line_length': len('str hello(str name)'),
|
|
|
|
})
|
|
|
|
def test_cpp_function_signature_with_maximum_signature_line_length_force_single(app):
|
|
|
|
text = ('.. cpp:function:: str hello(str names)\n'
|
|
|
|
' :single-line-parameter-list:')
|
|
|
|
doctree = restructuredtext.parse(app, text)
|
|
|
|
assert_node(doctree, (
|
|
|
|
addnodes.index,
|
|
|
|
[desc, (
|
|
|
|
[desc_signature, (
|
|
|
|
[desc_signature_line, (
|
|
|
|
pending_xref,
|
|
|
|
desc_sig_space,
|
|
|
|
[desc_name, [desc_sig_name, 'hello']],
|
|
|
|
desc_parameterlist,
|
|
|
|
)],
|
|
|
|
)],
|
|
|
|
desc_content,
|
|
|
|
)],
|
|
|
|
))
|
|
|
|
assert_node(doctree[1], addnodes.desc, desctype='function',
|
2023-07-28 16:30:26 -05:00
|
|
|
domain='cpp', objtype='function', no_index=False)
|
2023-05-11 08:28:57 -05:00
|
|
|
assert_node(doctree[1][0][0][3], [desc_parameterlist, desc_parameter, (
|
|
|
|
[pending_xref, [desc_sig_name, 'str']],
|
|
|
|
desc_sig_space,
|
|
|
|
[desc_sig_name, 'names']),
|
|
|
|
])
|
|
|
|
assert_node(doctree[1][0][0][3], desc_parameterlist, multi_line_parameter_list=False)
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.sphinx('html', confoverrides={
|
|
|
|
'maximum_signature_line_length': len("str hello(str name)"),
|
|
|
|
})
|
|
|
|
def test_cpp_function_signature_with_maximum_signature_line_length_break(app):
|
|
|
|
text = '.. cpp:function:: str hello(str names)'
|
|
|
|
doctree = restructuredtext.parse(app, text)
|
|
|
|
assert_node(doctree, (
|
|
|
|
addnodes.index,
|
|
|
|
[desc, (
|
|
|
|
[desc_signature, (
|
|
|
|
[desc_signature_line, (
|
|
|
|
pending_xref,
|
|
|
|
desc_sig_space,
|
|
|
|
[desc_name, [desc_sig_name, 'hello']],
|
|
|
|
desc_parameterlist,
|
|
|
|
)],
|
|
|
|
)],
|
|
|
|
desc_content,
|
|
|
|
)],
|
|
|
|
))
|
|
|
|
assert_node(doctree[1], addnodes.desc, desctype='function',
|
2023-07-28 16:30:26 -05:00
|
|
|
domain='cpp', objtype='function', no_index=False)
|
2023-05-11 08:28:57 -05:00
|
|
|
assert_node(doctree[1][0][0][3], [desc_parameterlist, desc_parameter, (
|
|
|
|
[pending_xref, [desc_sig_name, 'str']],
|
|
|
|
desc_sig_space,
|
|
|
|
[desc_sig_name, 'names']),
|
|
|
|
])
|
|
|
|
assert_node(doctree[1][0][0][3], desc_parameterlist, multi_line_parameter_list=True)
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.sphinx('html', confoverrides={
|
|
|
|
'cpp_maximum_signature_line_length': len('str hello(str name)'),
|
|
|
|
'maximum_signature_line_length': 1,
|
|
|
|
})
|
|
|
|
def test_cpp_maximum_signature_line_length_overrides_global(app):
|
|
|
|
text = '.. cpp:function:: str hello(str name)'
|
|
|
|
doctree = restructuredtext.parse(app, text)
|
|
|
|
assert_node(doctree, (
|
|
|
|
addnodes.index,
|
|
|
|
[desc, ([desc_signature, ([desc_signature_line, (pending_xref,
|
|
|
|
desc_sig_space,
|
|
|
|
[desc_name, [desc_sig_name, "hello"]],
|
|
|
|
desc_parameterlist)])],
|
|
|
|
desc_content)],
|
|
|
|
))
|
|
|
|
assert_node(doctree[1], addnodes.desc, desctype='function',
|
2023-07-28 16:30:26 -05:00
|
|
|
domain='cpp', objtype='function', no_index=False)
|
2023-05-11 08:28:57 -05:00
|
|
|
assert_node(doctree[1][0][0][3], [desc_parameterlist, desc_parameter, (
|
|
|
|
[pending_xref, [desc_sig_name, 'str']],
|
|
|
|
desc_sig_space,
|
|
|
|
[desc_sig_name, 'name'],
|
|
|
|
)])
|
|
|
|
assert_node(doctree[1][0][0][3], desc_parameterlist, multi_line_parameter_list=False)
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.sphinx('html', testroot='domain-cpp-cpp_maximum_signature_line_length')
|
|
|
|
def test_domain_cpp_cpp_maximum_signature_line_length_in_html(app, status, warning):
|
|
|
|
app.build()
|
|
|
|
content = (app.outdir / 'index.html').read_text(encoding='utf-8')
|
|
|
|
expected = """\
|
|
|
|
|
|
|
|
<dl>
|
|
|
|
<dd>\
|
|
|
|
<span class="n"><span class="pre">str</span></span>\
|
|
|
|
<span class="w"> </span>\
|
|
|
|
<span class="n sig-param"><span class="pre">name</span></span>,\
|
|
|
|
</dd>
|
|
|
|
</dl>
|
|
|
|
|
|
|
|
<span class="sig-paren">)</span>\
|
|
|
|
<a class="headerlink" href=\
|
|
|
|
"""
|
|
|
|
assert expected in content
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.sphinx(
|
|
|
|
'text', testroot='domain-cpp-cpp_maximum_signature_line_length',
|
|
|
|
)
|
|
|
|
def test_domain_cpp_cpp_maximum_signature_line_length_in_text(app, status, warning):
|
|
|
|
app.build()
|
|
|
|
content = (app.outdir / 'index.txt').read_text(encoding='utf8')
|
|
|
|
param_line_fmt = STDINDENT * " " + "{}\n"
|
|
|
|
|
|
|
|
expected_parameter_list_hello = "(\n{})".format(param_line_fmt.format("str name,"))
|
|
|
|
|
|
|
|
assert expected_parameter_list_hello in content
|