summaryrefslogtreecommitdiff
path: root/sphinx/domains/cpp.py
diff options
context:
space:
mode:
authorTakeshi KOMIYA <i.tkomiya@gmail.com>2021-01-24 16:34:47 +0900
committerTakeshi KOMIYA <i.tkomiya@gmail.com>2021-01-24 16:34:47 +0900
commit51d500833e391c182f536e83a5d62d5e90ce8ca9 (patch)
treefb854309b759773feb83e7e4bbc91e3ed3cb2b00 /sphinx/domains/cpp.py
parent375fb52fe402d46d633e321ce8f20c1aa61c49b9 (diff)
parent41ee2d6e6595d0eefb4a2b752fd79a3451382d5a (diff)
downloadsphinx-git-51d500833e391c182f536e83a5d62d5e90ce8ca9.tar.gz
Merge branch '3.x' into 7774_remove_develop.rst
Diffstat (limited to 'sphinx/domains/cpp.py')
-rw-r--r--sphinx/domains/cpp.py397
1 files changed, 234 insertions, 163 deletions
diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py
index 1783db491..25e6f1421 100644
--- a/sphinx/domains/cpp.py
+++ b/sphinx/domains/cpp.py
@@ -4,14 +4,13 @@
The C++ language domain.
- :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS.
+ :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import re
-from typing import (
- Any, Callable, Dict, Generator, Iterator, List, Tuple, Type, TypeVar, Union, Optional
-)
+from typing import (Any, Callable, Dict, Generator, Iterator, List, Optional, Tuple, Type,
+ TypeVar, Union)
from docutils import nodes
from docutils.nodes import Element, Node, TextElement, system_message
@@ -30,19 +29,17 @@ from sphinx.roles import SphinxRole, XRefRole
from sphinx.transforms import SphinxTransform
from sphinx.transforms.post_transforms import ReferencesResolver
from sphinx.util import logging
-from sphinx.util.cfamily import (
- NoOldIdError, ASTBaseBase, ASTAttribute, verify_description_mode, StringifyTransform,
- BaseParser, DefinitionError, UnsupportedMultiCharacterCharLiteral,
- identifier_re, anon_identifier_re, integer_literal_re, octal_literal_re,
- hex_literal_re, binary_literal_re, integers_literal_suffix_re,
- float_literal_re, float_literal_suffix_re,
- char_literal_re
-)
+from sphinx.util.cfamily import (ASTAttribute, ASTBaseBase, ASTBaseParenExprList, BaseParser,
+ DefinitionError, NoOldIdError, StringifyTransform,
+ UnsupportedMultiCharacterCharLiteral, anon_identifier_re,
+ binary_literal_re, char_literal_re, float_literal_re,
+ float_literal_suffix_re, hex_literal_re, identifier_re,
+ integer_literal_re, integers_literal_suffix_re,
+ octal_literal_re, verify_description_mode)
from sphinx.util.docfields import Field, GroupedField
from sphinx.util.docutils import SphinxDirective
from sphinx.util.nodes import make_refnode
-
logger = logging.getLogger(__name__)
T = TypeVar('T')
@@ -140,7 +137,7 @@ T = TypeVar('T')
visibility storage-class-specifier function-specifier "friend"
"constexpr" "volatile" "const" trailing-type-specifier
# where trailing-type-specifier can no be cv-qualifier
- # Inside e.g., template paramters a strict subset is used
+ # Inside e.g., template parameters a strict subset is used
# (see type-specifier-seq)
trailing-type-specifier ->
simple-type-specifier ->
@@ -1595,6 +1592,15 @@ class ASTOperator(ASTBase):
identifier = str(self)
if mode == 'lastIsName':
signode += addnodes.desc_name(identifier, identifier)
+ elif mode == 'markType':
+ targetText = prefix + identifier + templateArgs
+ pnode = addnodes.pending_xref('', refdomain='cpp',
+ reftype='identifier',
+ reftarget=targetText, modname=None,
+ classname=None)
+ pnode['cpp:parent_key'] = symbol.get_lookup_key()
+ pnode += nodes.Text(identifier)
+ signode += pnode
else:
signode += addnodes.desc_addname(identifier, identifier)
@@ -1835,7 +1841,7 @@ class ASTFunctionParameter(ASTBase):
# this is not part of the normal name mangling in C++
if symbol:
# the anchor will be our parent
- return symbol.parent.declaration.get_id(version, prefixed=None)
+ return symbol.parent.declaration.get_id(version, prefixed=False)
# else, do the usual
if self.ellipsis:
return 'z'
@@ -1878,7 +1884,8 @@ class ASTNoexceptSpec(ASTBase):
class ASTParametersQualifiers(ASTBase):
def __init__(self, args: List[ASTFunctionParameter], volatile: bool, const: bool,
refQual: str, exceptionSpec: ASTNoexceptSpec, trailingReturn: "ASTType",
- override: bool, final: bool, initializer: str) -> None:
+ override: bool, final: bool, attrs: List[ASTAttribute],
+ initializer: str) -> None:
self.args = args
self.volatile = volatile
self.const = const
@@ -1887,6 +1894,7 @@ class ASTParametersQualifiers(ASTBase):
self.trailingReturn = trailingReturn
self.override = override
self.final = final
+ self.attrs = attrs
self.initializer = initializer
@property
@@ -1946,6 +1954,9 @@ class ASTParametersQualifiers(ASTBase):
res.append(' final')
if self.override:
res.append(' override')
+ for attr in self.attrs:
+ res.append(' ')
+ res.append(transform(attr))
if self.initializer:
res.append(' = ')
res.append(self.initializer)
@@ -1987,6 +1998,9 @@ class ASTParametersQualifiers(ASTBase):
_add_anno(signode, 'final')
if self.override:
_add_anno(signode, 'override')
+ for attr in self.attrs:
+ signode += nodes.Text(' ')
+ attr.describe_signature(signode)
if self.initializer:
_add_text(signode, '= ' + str(self.initializer))
@@ -2742,7 +2756,7 @@ class ASTPackExpansionExpr(ASTExpression):
signode += nodes.Text('...')
-class ASTParenExprList(ASTBase):
+class ASTParenExprList(ASTBaseParenExprList):
def __init__(self, exprs: List[Union[ASTExpression, ASTBracedInitList]]) -> None:
self.exprs = exprs
@@ -3781,6 +3795,16 @@ class Symbol:
debug_lookup = False # overridden by the corresponding config value
debug_show_tree = False # overridden by the corresponding config value
+ def __copy__(self):
+ assert False # shouldn't happen
+
+ def __deepcopy__(self, memo):
+ if self.parent:
+ assert False # shouldn't happen
+ else:
+ # the domain base class makes a copy of the initial data, which is fine
+ return Symbol(None, None, None, None, None, None, None)
+
@staticmethod
def debug_print(*args: Any) -> None:
print(Symbol.debug_indent_string * Symbol.debug_indent, end="")
@@ -3806,7 +3830,8 @@ class Symbol:
def __init__(self, parent: "Symbol", identOrOp: Union[ASTIdentifier, ASTOperator],
templateParams: Union[ASTTemplateParams, ASTTemplateIntroduction],
- templateArgs: Any, declaration: ASTDeclaration, docname: str) -> None:
+ templateArgs: Any, declaration: ASTDeclaration,
+ docname: str, line: int) -> None:
self.parent = parent
# declarations in a single directive are linked together
self.siblingAbove = None # type: Symbol
@@ -3816,6 +3841,7 @@ class Symbol:
self.templateArgs = templateArgs # identifier<templateArgs>
self.declaration = declaration
self.docname = docname
+ self.line = line
self.isRedeclaration = False
self._assert_invariants()
@@ -3831,15 +3857,18 @@ class Symbol:
# Do symbol addition after self._children has been initialised.
self._add_template_and_function_params()
- def _fill_empty(self, declaration: ASTDeclaration, docname: str) -> None:
+ def _fill_empty(self, declaration: ASTDeclaration, docname: str, line: int) -> None:
self._assert_invariants()
- assert not self.declaration
- assert not self.docname
- assert declaration
- assert docname
+ assert self.declaration is None
+ assert self.docname is None
+ assert self.line is None
+ assert declaration is not None
+ assert docname is not None
+ assert line is not None
self.declaration = declaration
self.declaration.symbol = self
self.docname = docname
+ self.line = line
self._assert_invariants()
# and symbol addition should be done as well
self._add_template_and_function_params()
@@ -3863,7 +3892,7 @@ class Symbol:
decl = None
nne = ASTNestedNameElement(tp.get_identifier(), None)
nn = ASTNestedName([nne], [False], rooted=False)
- self._add_symbols(nn, [], decl, self.docname)
+ self._add_symbols(nn, [], decl, self.docname, self.line)
# add symbols for function parameters, if any
if self.declaration is not None and self.declaration.function_params is not None:
for fp in self.declaration.function_params:
@@ -3876,7 +3905,7 @@ class Symbol:
decl = ASTDeclaration('functionParam', None, None, None, None, fp, None)
assert not nn.rooted
assert len(nn.names) == 1
- self._add_symbols(nn, [], decl, self.docname)
+ self._add_symbols(nn, [], decl, self.docname, self.line)
if Symbol.debug_lookup:
Symbol.debug_indent -= 1
@@ -3894,6 +3923,7 @@ class Symbol:
if sChild.declaration and sChild.docname == docname:
sChild.declaration = None
sChild.docname = None
+ sChild.line = None
if sChild.siblingAbove is not None:
sChild.siblingAbove.siblingBelow = sChild.siblingBelow
if sChild.siblingBelow is not None:
@@ -3906,8 +3936,7 @@ class Symbol:
def get_all_symbols(self) -> Iterator[Any]:
yield self
for sChild in self._children:
- for s in sChild.get_all_symbols():
- yield s
+ yield from sChild.get_all_symbols()
@property
def children_recurse_anon(self) -> Generator["Symbol", None, None]:
@@ -4088,7 +4117,7 @@ class Symbol:
Symbol.debug_print("self:")
print(self.to_string(Symbol.debug_indent + 1), end="")
Symbol.debug_print("nestedName: ", nestedName)
- Symbol.debug_print("templateDecls: ", templateDecls)
+ Symbol.debug_print("templateDecls: ", ",".join(str(t) for t in templateDecls))
Symbol.debug_print("strictTemplateParamArgLists:", strictTemplateParamArgLists)
Symbol.debug_print("ancestorLookupType:", ancestorLookupType)
Symbol.debug_print("templateShorthand: ", templateShorthand)
@@ -4204,7 +4233,7 @@ class Symbol:
identOrOp, templateParams, templateArgs)
def _add_symbols(self, nestedName: ASTNestedName, templateDecls: List[Any],
- declaration: ASTDeclaration, docname: str) -> "Symbol":
+ declaration: ASTDeclaration, docname: str, line: int) -> "Symbol":
# Used for adding a whole path of symbols, where the last may or may not
# be an actual declaration.
@@ -4212,10 +4241,10 @@ class Symbol:
Symbol.debug_indent += 1
Symbol.debug_print("_add_symbols:")
Symbol.debug_indent += 1
- Symbol.debug_print("tdecls:", templateDecls)
- Symbol.debug_print("nn: ", nestedName)
- Symbol.debug_print("decl: ", declaration)
- Symbol.debug_print("doc: ", docname)
+ Symbol.debug_print("tdecls:", ",".join(str(t) for t in templateDecls))
+ Symbol.debug_print("nn: ", nestedName)
+ Symbol.debug_print("decl: ", declaration)
+ Symbol.debug_print("location: {}:{}".format(docname, line))
def onMissingQualifiedSymbol(parentSymbol: "Symbol",
identOrOp: Union[ASTIdentifier, ASTOperator],
@@ -4232,7 +4261,7 @@ class Symbol:
return Symbol(parent=parentSymbol, identOrOp=identOrOp,
templateParams=templateParams,
templateArgs=templateArgs, declaration=None,
- docname=None)
+ docname=None, line=None)
lookupResult = self._symbol_lookup(nestedName, templateDecls,
onMissingQualifiedSymbol,
@@ -4253,14 +4282,14 @@ class Symbol:
Symbol.debug_print("identOrOp: ", lookupResult.identOrOp)
Symbol.debug_print("templateArgs: ", lookupResult.templateArgs)
Symbol.debug_print("declaration: ", declaration)
- Symbol.debug_print("docname: ", docname)
+ Symbol.debug_print("location: {}:{}".format(docname, line))
Symbol.debug_indent -= 1
symbol = Symbol(parent=lookupResult.parentSymbol,
identOrOp=lookupResult.identOrOp,
templateParams=lookupResult.templateParams,
templateArgs=lookupResult.templateArgs,
declaration=declaration,
- docname=docname)
+ docname=docname, line=line)
if Symbol.debug_lookup:
Symbol.debug_indent -= 2
return symbol
@@ -4273,7 +4302,7 @@ class Symbol:
if not declaration:
if Symbol.debug_lookup:
- Symbol.debug_print("no delcaration")
+ Symbol.debug_print("no declaration")
Symbol.debug_indent -= 2
# good, just a scope creation
# TODO: what if we have more than one symbol?
@@ -4309,7 +4338,7 @@ class Symbol:
templateParams=lookupResult.templateParams,
templateArgs=lookupResult.templateArgs,
declaration=declaration,
- docname=docname)
+ docname=docname, line=line)
if Symbol.debug_lookup:
Symbol.debug_print("end: creating candidate symbol")
return symbol
@@ -4341,6 +4370,11 @@ class Symbol:
if Symbol.debug_lookup:
Symbol.debug_print("candId:", candId)
for symbol in withDecl:
+ # but all existing must be functions as well,
+ # otherwise we declare it to be a duplicate
+ if symbol.declaration.objectType != 'function':
+ handleDuplicateDeclaration(symbol, candSymbol)
+ # (not reachable)
oldId = symbol.declaration.get_newest_id()
if Symbol.debug_lookup:
Symbol.debug_print("oldId: ", oldId)
@@ -4351,7 +4385,11 @@ class Symbol:
# if there is an empty symbol, fill that one
if len(noDecl) == 0:
if Symbol.debug_lookup:
- Symbol.debug_print("no match, no empty, candSybmol is not None?:", candSymbol is not None) # NOQA
+ Symbol.debug_print("no match, no empty")
+ if candSymbol is not None:
+ Symbol.debug_print("result is already created candSymbol")
+ else:
+ Symbol.debug_print("result is makeCandSymbol()")
Symbol.debug_indent -= 2
if candSymbol is not None:
return candSymbol
@@ -4372,7 +4410,7 @@ class Symbol:
# .. namespace:: Test
# .. namespace:: nullptr
# .. class:: Test
- symbol._fill_empty(declaration, docname)
+ symbol._fill_empty(declaration, docname, line)
return symbol
def merge_with(self, other: "Symbol", docnames: List[str],
@@ -4451,13 +4489,15 @@ class Symbol:
continue
if otherChild.declaration and otherChild.docname in docnames:
if not ourChild.declaration:
- ourChild._fill_empty(otherChild.declaration, otherChild.docname)
+ ourChild._fill_empty(otherChild.declaration,
+ otherChild.docname, otherChild.line)
elif ourChild.docname != otherChild.docname:
name = str(ourChild.declaration)
- msg = __("Duplicate declaration, also defined in '%s'.\n"
- "Declaration is '%s'.")
- msg = msg % (ourChild.docname, name)
- logger.warning(msg, location=otherChild.docname)
+ msg = __("Duplicate C++ declaration, also defined at %s:%s.\n"
+ "Declaration is '.. cpp:%s:: %s'.")
+ msg = msg % (ourChild.docname, ourChild.line,
+ ourChild.declaration.directiveType, name)
+ logger.warning(msg, location=(otherChild.docname, otherChild.line))
else:
# Both have declarations, and in the same docname.
# This can apparently happen, it should be safe to
@@ -4481,23 +4521,25 @@ class Symbol:
else:
templateDecls = []
res = self._add_symbols(nestedName, templateDecls,
- declaration=None, docname=None)
+ declaration=None, docname=None, line=None)
if Symbol.debug_lookup:
Symbol.debug_indent -= 1
return res
- def add_declaration(self, declaration: ASTDeclaration, docname: str) -> "Symbol":
+ def add_declaration(self, declaration: ASTDeclaration,
+ docname: str, line: int) -> "Symbol":
if Symbol.debug_lookup:
Symbol.debug_indent += 1
Symbol.debug_print("add_declaration:")
- assert declaration
- assert docname
+ assert declaration is not None
+ assert docname is not None
+ assert line is not None
nestedName = declaration.name
if declaration.templatePrefix:
templateDecls = declaration.templatePrefix.templates
else:
templateDecls = []
- res = self._add_symbols(nestedName, templateDecls, declaration, docname)
+ res = self._add_symbols(nestedName, templateDecls, declaration, docname, line)
if Symbol.debug_lookup:
Symbol.debug_indent -= 1
return res
@@ -4692,7 +4734,8 @@ class Symbol:
templateParams=lookupResult.templateParams,
templateArgs=lookupResult.templateArgs,
declaration=declaration,
- docname='fakeDocnameForQuery')
+ docname='fakeDocnameForQuery',
+ line=42)
queryId = declaration.get_newest_id()
for symbol in symbols:
if symbol.declaration is None:
@@ -4882,7 +4925,7 @@ class DefinitionParser(BaseParser):
raise self._make_multi_error([
(eFold, "If fold expression"),
(eExpr, "If parenthesized expression")
- ], "Error in fold expression or parenthesized expression.")
+ ], "Error in fold expression or parenthesized expression.") from eExpr
return ASTParenExpr(res)
# now it definitely is a fold expression
if self.skip_string(')'):
@@ -5066,7 +5109,7 @@ class DefinitionParser(BaseParser):
errors = []
errors.append((eType, "If type"))
errors.append((eExpr, "If expression"))
- raise self._make_multi_error(errors, header)
+ raise self._make_multi_error(errors, header) from eExpr
else: # a primary expression or a type
pos = self.pos
try:
@@ -5093,7 +5136,7 @@ class DefinitionParser(BaseParser):
errors = []
errors.append((eOuter, "If primary expression"))
errors.append((eInner, "If type"))
- raise self._make_multi_error(errors, header)
+ raise self._make_multi_error(errors, header) from eInner
# and now parse postfixes
postFixes = [] # type: List[ASTPostfixOp]
@@ -5253,7 +5296,8 @@ class DefinitionParser(BaseParser):
errs = []
errs.append((exCast, "If type cast expression"))
errs.append((exUnary, "If unary expression"))
- raise self._make_multi_error(errs, "Error in cast expression.")
+ raise self._make_multi_error(errs,
+ "Error in cast expression.") from exUnary
else:
return self._parse_unary_expression()
@@ -5504,7 +5548,7 @@ class DefinitionParser(BaseParser):
self.pos = pos
prevErrors.append((e, "If non-type argument"))
header = "Error in parsing template argument list."
- raise self._make_multi_error(prevErrors, header)
+ raise self._make_multi_error(prevErrors, header) from e
if parsedEnd:
assert not parsedComma
break
@@ -5697,6 +5741,13 @@ class DefinitionParser(BaseParser):
override = self.skip_word_and_ws(
'override') # they can be permuted
+ attrs = []
+ while True:
+ attr = self._parse_attribute()
+ if attr is None:
+ break
+ attrs.append(attr)
+
self.skip_ws()
initializer = None
if self.skip_string('='):
@@ -5713,7 +5764,7 @@ class DefinitionParser(BaseParser):
return ASTParametersQualifiers(
args, volatile, const, refQual, exceptionSpec, trailingReturn,
- override, final, initializer)
+ override, final, attrs, initializer)
def _parse_decl_specs_simple(self, outer: str, typed: bool) -> ASTDeclSpecsSimple:
"""Just parse the simple ones."""
@@ -5949,7 +6000,7 @@ class DefinitionParser(BaseParser):
self.pos = pos
prevErrors.append((exNoPtrParen, "If parenthesis in noptr-declarator"))
header = "Error in declarator"
- raise self._make_multi_error(prevErrors, header)
+ raise self._make_multi_error(prevErrors, header) from exNoPtrParen
if typed: # pointer to member
pos = self.pos
try:
@@ -5988,7 +6039,7 @@ class DefinitionParser(BaseParser):
self.pos = pos
prevErrors.append((e, "If declarator-id"))
header = "Error in declarator or parameters-and-qualifiers"
- raise self._make_multi_error(prevErrors, header)
+ raise self._make_multi_error(prevErrors, header) from e
def _parse_initializer(self, outer: str = None, allowFallback: bool = True
) -> ASTInitializer:
@@ -6096,7 +6147,7 @@ class DefinitionParser(BaseParser):
header = "Error when parsing function declaration."
else:
assert False
- raise self._make_multi_error(prevErrors, header)
+ raise self._make_multi_error(prevErrors, header) from exTyped
else:
# For testing purposes.
# do it again to get the proper traceback (how do you
@@ -6163,7 +6214,7 @@ class DefinitionParser(BaseParser):
errs.append((eType, "If default template argument is a type"))
msg = "Error in non-type template parameter"
msg += " or constrained template parameter."
- raise self._make_multi_error(errs, msg)
+ raise self._make_multi_error(errs, msg) from eType
def _parse_type_using(self) -> ASTTypeUsing:
name = self._parse_nested_name()
@@ -6238,23 +6289,19 @@ class DefinitionParser(BaseParser):
# ==========================================================================
- def _parse_template_parameter_list(self) -> ASTTemplateParams:
- # only: '<' parameter-list '>'
- # we assume that 'template' has just been parsed
- templateParams = [] # type: List[ASTTemplateParam]
+ def _parse_template_paramter(self) -> ASTTemplateParam:
self.skip_ws()
- if not self.skip_string("<"):
- self.fail("Expected '<' after 'template'")
- prevErrors = []
- while 1:
- self.skip_ws()
- if self.skip_word('template'):
- # declare a tenplate template parameter
- nestedParams = self._parse_template_parameter_list()
- else:
- nestedParams = None
- self.skip_ws()
+ if self.skip_word('template'):
+ # declare a tenplate template parameter
+ nestedParams = self._parse_template_parameter_list()
+ else:
+ nestedParams = None
+
+ pos = self.pos
+ try:
+ # Unconstrained type parameter or template type parameter
key = None
+ self.skip_ws()
if self.skip_word_and_ws('typename'):
key = 'typename'
elif self.skip_word_and_ws('class'):
@@ -6262,52 +6309,79 @@ class DefinitionParser(BaseParser):
elif nestedParams:
self.fail("Expected 'typename' or 'class' after "
"template template parameter list.")
- if key:
- # declare a type or template type parameter
- self.skip_ws()
- parameterPack = self.skip_string('...')
- self.skip_ws()
- if self.match(identifier_re):
- identifier = ASTIdentifier(self.matched_text)
- else:
- identifier = None
- self.skip_ws()
- if not parameterPack and self.skip_string('='):
- default = self._parse_type(named=False, outer=None)
- else:
- default = None
- data = ASTTemplateKeyParamPackIdDefault(key, identifier,
- parameterPack, default)
- if nestedParams:
- # template type
- templateParams.append(
- ASTTemplateParamTemplateType(nestedParams, data))
- else:
- # type
- templateParams.append(ASTTemplateParamType(data))
else:
- # declare a non-type parameter, or constrained type parameter
- pos = self.pos
- try:
- param = self._parse_type_with_init('maybe', 'templateParam')
- templateParams.append(ASTTemplateParamNonType(param))
- except DefinitionError as e:
- msg = "If non-type template parameter or constrained template parameter"
- prevErrors.append((e, msg))
- self.pos = pos
+ self.fail("Expected 'typename' or 'class' in tbe "
+ "beginning of template type parameter.")
+ self.skip_ws()
+ parameterPack = self.skip_string('...')
+ self.skip_ws()
+ if self.match(identifier_re):
+ identifier = ASTIdentifier(self.matched_text)
+ else:
+ identifier = None
+ self.skip_ws()
+ if not parameterPack and self.skip_string('='):
+ default = self._parse_type(named=False, outer=None)
+ else:
+ default = None
+ if self.current_char not in ',>':
+ self.fail('Expected "," or ">" after (template) type parameter.')
+ data = ASTTemplateKeyParamPackIdDefault(key, identifier,
+ parameterPack, default)
+ if nestedParams:
+ return ASTTemplateParamTemplateType(nestedParams, data)
+ else:
+ return ASTTemplateParamType(data)
+ except DefinitionError as eType:
+ if nestedParams:
+ raise
+ try:
+ # non-type parameter or constrained type parameter
+ self.pos = pos
+ param = self._parse_type_with_init('maybe', 'templateParam')
+ return ASTTemplateParamNonType(param)
+ except DefinitionError as eNonType:
+ self.pos = pos
+ header = "Error when parsing template parameter."
+ errs = []
+ errs.append(
+ (eType, "If unconstrained type parameter or template type parameter"))
+ errs.append(
+ (eNonType, "If constrained type parameter or non-type parameter"))
+ raise self._make_multi_error(errs, header)
+
+ def _parse_template_parameter_list(self) -> ASTTemplateParams:
+ # only: '<' parameter-list '>'
+ # we assume that 'template' has just been parsed
+ templateParams = [] # type: List[ASTTemplateParam]
+ self.skip_ws()
+ if not self.skip_string("<"):
+ self.fail("Expected '<' after 'template'")
+ while 1:
+ pos = self.pos
+ err = None
+ try:
+ param = self._parse_template_paramter()
+ templateParams.append(param)
+ except DefinitionError as eParam:
+ self.pos = pos
+ err = eParam
self.skip_ws()
if self.skip_string('>'):
return ASTTemplateParams(templateParams)
elif self.skip_string(','):
- prevErrors = []
continue
else:
header = "Error in template parameter list."
+ errs = []
+ if err:
+ errs.append((err, "If parameter"))
try:
- self.fail('Expected "=", ",", or ">".')
+ self.fail('Expected "," or ">".')
except DefinitionError as e:
- prevErrors.append((e, ""))
- raise self._make_multi_error(prevErrors, header)
+ errs.append((e, "If no parameter"))
+ print(errs)
+ raise self._make_multi_error(errs, header)
def _parse_template_introduction(self) -> ASTTemplateIntroduction:
pos = self.pos
@@ -6510,7 +6584,7 @@ class DefinitionParser(BaseParser):
self.pos = pos
prevErrors.append((e, "If type alias or template alias"))
header = "Error in type declaration."
- raise self._make_multi_error(prevErrors, header)
+ raise self._make_multi_error(prevErrors, header) from e
elif objectType == 'concept':
declaration = self._parse_concept()
elif objectType == 'member':
@@ -6576,7 +6650,7 @@ class DefinitionParser(BaseParser):
errs.append((e1, "If shorthand ref"))
errs.append((e2, "If full function ref"))
msg = "Error in cross-reference."
- raise self._make_multi_error(errs, msg)
+ raise self._make_multi_error(errs, msg) from e2
def parse_expression(self) -> Union[ASTExpression, ASTType]:
pos = self.pos
@@ -6597,7 +6671,7 @@ class DefinitionParser(BaseParser):
errs = []
errs.append((exExpr, "If expression"))
errs.append((exType, "If type"))
- raise self._make_multi_error(errs, header)
+ raise self._make_multi_error(errs, header) from exType
def _make_phony_error_name() -> ASTNestedName:
@@ -6605,7 +6679,7 @@ def _make_phony_error_name() -> ASTNestedName:
return ASTNestedName([nne], [False], rooted=False)
-class CPPObject(ObjectDescription):
+class CPPObject(ObjectDescription[ASTDeclaration]):
"""Description of a C++ language object."""
doc_field_types = [
@@ -6622,8 +6696,10 @@ class CPPObject(ObjectDescription):
names=('returns', 'return')),
]
- option_spec = dict(ObjectDescription.option_spec)
- option_spec['tparam-line-spec'] = directives.flag
+ option_spec = {
+ 'noindexentry': directives.flag,
+ 'tparam-line-spec': directives.flag,
+ }
def _add_enumerator_to_parent(self, ast: ASTDeclaration) -> None:
assert ast.objectType == 'enumerator'
@@ -6665,7 +6741,7 @@ class CPPObject(ObjectDescription):
Symbol(parent=targetSymbol, identOrOp=symbol.identOrOp,
templateParams=None, templateArgs=None,
declaration=declClone,
- docname=self.env.docname)
+ docname=self.env.docname, line=self.get_source_info()[1])
def add_target_and_index(self, ast: ASTDeclaration, sig: str,
signode: TextElement) -> None:
@@ -6698,7 +6774,7 @@ class CPPObject(ObjectDescription):
if decl.objectType == 'concept':
isInConcept = True
break
- if not isInConcept:
+ if not isInConcept and 'noindexentry' not in self.options:
strippedName = name
for prefix in self.env.config.cpp_index_common_prefix:
if name.startswith(prefix):
@@ -6762,10 +6838,12 @@ class CPPObject(ObjectDescription):
parentSymbol = env.temp_data['cpp:parent_symbol']
parentDecl = parentSymbol.declaration
if parentDecl is not None and parentDecl.objectType == 'function':
- logger.warning("C++ declarations inside functions are not supported." +
- " Parent function is " +
- str(parentSymbol.get_full_nested_name()),
- location=self.get_source_info())
+ msg = "C++ declarations inside functions are not supported." \
+ " Parent function: {}\nDirective name: {}\nDirective arg: {}"
+ logger.warning(msg.format(
+ str(parentSymbol.get_full_nested_name()),
+ self.name, self.arguments[0]
+ ), location=self.get_source_info())
name = _make_phony_error_name()
symbol = parentSymbol.add_name(name)
env.temp_data['cpp:last_symbol'] = symbol
@@ -6777,7 +6855,7 @@ class CPPObject(ObjectDescription):
return super().run()
def handle_signature(self, sig: str, signode: desc_signature) -> ASTDeclaration:
- parentSymbol = self.env.temp_data['cpp:parent_symbol']
+ parentSymbol = self.env.temp_data['cpp:parent_symbol'] # type: Symbol
parser = DefinitionParser(sig, location=signode, config=self.env.config)
try:
@@ -6790,10 +6868,11 @@ class CPPObject(ObjectDescription):
name = _make_phony_error_name()
symbol = parentSymbol.add_name(name)
self.env.temp_data['cpp:last_symbol'] = symbol
- raise ValueError
+ raise ValueError from e
try:
- symbol = parentSymbol.add_declaration(ast, docname=self.env.docname)
+ symbol = parentSymbol.add_declaration(
+ ast, docname=self.env.docname, line=self.get_source_info()[1])
# append the new declaration to the sibling list
assert symbol.siblingAbove is None
assert symbol.siblingBelow is None
@@ -6806,7 +6885,11 @@ class CPPObject(ObjectDescription):
# Assume we are actually in the old symbol,
# instead of the newly created duplicate.
self.env.temp_data['cpp:last_symbol'] = e.symbol
- logger.warning("Duplicate declaration, %s", sig, location=signode)
+ msg = __("Duplicate C++ declaration, also defined at %s:%s.\n"
+ "Declaration is '.. cpp:%s:: %s'.")
+ msg = msg % (e.symbol.docname, e.symbol.line,
+ self.display_object_type, sig)
+ logger.warning(msg, location=signode)
if ast.objectType == 'enumerator':
self._add_enumerator_to_parent(ast)
@@ -6976,8 +7059,8 @@ class AliasNode(nodes.Element):
assert parentKey is not None
self.parentKey = parentKey
- def copy(self: T) -> T:
- return self.__class__(self.sig, env=None, parentKey=self.parentKey) # type: ignore
+ def copy(self) -> 'AliasNode':
+ return self.__class__(self.sig, env=None, parentKey=self.parentKey)
class AliasTransform(SphinxTransform):
@@ -7081,7 +7164,6 @@ class CPPAliasObject(ObjectDescription):
node['domain'] = self.domain
# 'desctype' is a backwards compatible attribute
node['objtype'] = node['desctype'] = self.objtype
- node['noindex'] = True
self.names = [] # type: List[str]
signatures = self.get_signatures()
@@ -7178,14 +7260,18 @@ class CPPDomain(Domain):
name = 'cpp'
label = 'C++'
object_types = {
- 'class': ObjType(_('class'), 'class', 'type', 'identifier'),
- 'union': ObjType(_('union'), 'union', 'type', 'identifier'),
- 'function': ObjType(_('function'), 'function', 'func', 'type', 'identifier'),
- 'member': ObjType(_('member'), 'member', 'var'),
- 'type': ObjType(_('type'), 'type', 'identifier'),
- 'concept': ObjType(_('concept'), 'concept', 'identifier'),
- 'enum': ObjType(_('enum'), 'enum', 'type', 'identifier'),
- 'enumerator': ObjType(_('enumerator'), 'enumerator')
+ 'class': ObjType(_('class'), 'class', 'struct', 'identifier', 'type'),
+ 'union': ObjType(_('union'), 'union', 'identifier', 'type'),
+ 'function': ObjType(_('function'), 'func', 'identifier', 'type'),
+ 'member': ObjType(_('member'), 'member', 'var', 'identifier'),
+ 'type': ObjType(_('type'), 'identifier', 'type'),
+ 'concept': ObjType(_('concept'), 'concept', 'identifier'),
+ 'enum': ObjType(_('enum'), 'enum', 'identifier', 'type'),
+ 'enumerator': ObjType(_('enumerator'), 'enumerator', 'identifier'),
+ # generated object types
+ 'functionParam': ObjType(_('function parameter'), 'identifier', 'member', 'var'), # noqa
+ 'templateParam': ObjType(_('template parameter'),
+ 'identifier', 'class', 'struct', 'union', 'member', 'var', 'type'), # noqa
}
directives = {
@@ -7225,7 +7311,7 @@ class CPPDomain(Domain):
'texpr': CPPExprRole(asCode=False)
}
initial_data = {
- 'root_symbol': Symbol(None, None, None, None, None, None),
+ 'root_symbol': Symbol(None, None, None, None, None, None, None),
'names': {} # full name for indexing -> docname
}
@@ -7273,13 +7359,9 @@ class CPPDomain(Domain):
ourNames = self.data['names']
for name, docname in otherdata['names'].items():
if docname in docnames:
- if name in ourNames:
- msg = __("Duplicate declaration, also defined in '%s'.\n"
- "Name of declaration is '%s'.")
- msg = msg % (ourNames[name], name)
- logger.warning(msg, location=docname)
- else:
+ if name not in ourNames:
ourNames[name] = docname
+ # no need to warn on duplicates, the symbol merge already does that
if Symbol.debug_show_tree:
print("\tresult:")
print(self.data['root_symbol'].dump(1))
@@ -7366,30 +7448,19 @@ class CPPDomain(Domain):
if typ.startswith('cpp:'):
typ = typ[4:]
- origTyp = typ
- if typ == 'func':
- typ = 'function'
- if typ == 'struct':
- typ = 'class'
declTyp = s.declaration.objectType
def checkType() -> bool:
- if typ == 'any' or typ == 'identifier':
+ if typ == 'any':
return True
- if declTyp == 'templateParam':
- # TODO: perhaps this should be strengthened one day
- return True
- if declTyp == 'functionParam':
- if typ == 'var' or typ == 'member':
- return True
objtypes = self.objtypes_for_role(typ)
if objtypes:
return declTyp in objtypes
- print("Type is %s (originally: %s), declType is %s" % (typ, origTyp, declTyp))
+ print("Type is %s, declaration type is %s" % (typ, declTyp))
assert False
if not checkType():
logger.warning("cpp:%s targets a %s (%s).",
- origTyp, s.declaration.objectType,
+ typ, s.declaration.objectType,
s.get_full_nested_name(),
location=node)
@@ -7419,10 +7490,10 @@ class CPPDomain(Domain):
if env.config.add_function_parentheses and typ == 'any':
addParen += 1
# and now this stuff for operator()
- if (env.config.add_function_parentheses and typ == 'function' and
+ if (env.config.add_function_parentheses and typ == 'func' and
title.endswith('operator()')):
addParen += 1
- if ((typ == 'any' or typ == 'function') and
+ if ((typ == 'any' or typ == 'func') and
title.endswith('operator') and
displayName.endswith('operator()')):
addParen += 1
@@ -7431,7 +7502,7 @@ class CPPDomain(Domain):
if env.config.add_function_parentheses:
if typ == 'any' and displayName.endswith('()'):
addParen += 1
- elif typ == 'function':
+ elif typ == 'func':
if title.endswith('()') and not displayName.endswith('()'):
title = title[:-2]
else: