Merge branch '3.2.x' into 3.x

This commit is contained in:
Takeshi KOMIYA
2020-11-01 20:31:49 +09:00
6 changed files with 103 additions and 77 deletions

View File

@@ -97,6 +97,9 @@ Deprecated
Features added
--------------
- C and C++, show line numbers for previous declarations when duplicates are
detected.
Bugs fixed
----------

View File

@@ -227,6 +227,7 @@ class CheckExternalLinksBuilder(Builder):
if rex.match(uri):
return 'ignored', '', 0
else:
self.broken[uri] = ''
return 'broken', '', 0
elif uri in self.good:
return 'working', 'old', 0

View File

@@ -1475,7 +1475,7 @@ class Symbol:
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)
return Symbol(None, None, None, None, None)
@staticmethod
def debug_print(*args: Any) -> None:
@@ -1498,7 +1498,7 @@ class Symbol:
return super().__setattr__(key, value)
def __init__(self, parent: "Symbol", ident: ASTIdentifier,
declaration: ASTDeclaration, docname: str) -> None:
declaration: ASTDeclaration, docname: str, line: int) -> None:
self.parent = parent
# declarations in a single directive are linked together
self.siblingAbove = None # type: Symbol
@@ -1506,6 +1506,7 @@ class Symbol:
self.ident = ident
self.declaration = declaration
self.docname = docname
self.line = line
self.isRedeclaration = False
self._assert_invariants()
@@ -1521,12 +1522,14 @@ class Symbol:
# Do symbol addition after self._children has been initialised.
self._add_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
@@ -1553,7 +1556,7 @@ class Symbol:
decl = ASTDeclaration('functionParam', None, p)
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
@@ -1570,6 +1573,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:
@@ -1763,7 +1767,7 @@ class Symbol:
return SymbolLookupResult(symbols, parentSymbol, ident)
def _add_symbols(self, nestedName: ASTNestedName,
declaration: ASTDeclaration, docname: str) -> "Symbol":
declaration: ASTDeclaration, docname: str, line: int) -> "Symbol":
# TODO: further simplification from C++ to C
# Used for adding a whole path of symbols, where the last may or may not
# be an actual declaration.
@@ -1772,9 +1776,9 @@ class Symbol:
Symbol.debug_indent += 1
Symbol.debug_print("_add_symbols:")
Symbol.debug_indent += 1
Symbol.debug_print("nn: ", nestedName)
Symbol.debug_print("decl: ", declaration)
Symbol.debug_print("doc: ", docname)
Symbol.debug_print("nn: ", nestedName)
Symbol.debug_print("decl: ", declaration)
Symbol.debug_print("location: {}:{}".format(docname, line))
def onMissingQualifiedSymbol(parentSymbol: "Symbol", ident: ASTIdentifier) -> "Symbol":
if Symbol.debug_lookup:
@@ -1784,7 +1788,7 @@ class Symbol:
Symbol.debug_print("ident: ", ident)
Symbol.debug_indent -= 2
return Symbol(parent=parentSymbol, ident=ident,
declaration=None, docname=None)
declaration=None, docname=None, line=None)
lookupResult = self._symbol_lookup(nestedName,
onMissingQualifiedSymbol,
@@ -1800,12 +1804,12 @@ class Symbol:
Symbol.debug_indent += 1
Symbol.debug_print("ident: ", lookupResult.ident)
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,
ident=lookupResult.ident,
declaration=declaration,
docname=docname)
docname=docname, line=line)
if Symbol.debug_lookup:
Symbol.debug_indent -= 2
return symbol
@@ -1853,7 +1857,7 @@ class Symbol:
symbol = Symbol(parent=lookupResult.parentSymbol,
ident=lookupResult.ident,
declaration=declaration,
docname=docname)
docname=docname, line=line)
if Symbol.debug_lookup:
Symbol.debug_print("end: creating candidate symbol")
return symbol
@@ -1919,7 +1923,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],
@@ -1940,13 +1944,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 C 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 '.. c:%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
@@ -1960,19 +1966,21 @@ class Symbol:
if Symbol.debug_lookup:
Symbol.debug_indent += 1
Symbol.debug_print("add_name:")
res = self._add_symbols(nestedName, declaration=None, docname=None)
res = self._add_symbols(nestedName, 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
res = self._add_symbols(nestedName, declaration, docname)
res = self._add_symbols(nestedName, declaration, docname, line)
if Symbol.debug_lookup:
Symbol.debug_indent -= 1
return res
@@ -3149,7 +3157,7 @@ class CObject(ObjectDescription):
declClone.enumeratorScopedSymbol = symbol
Symbol(parent=targetSymbol, ident=symbol.ident,
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:
@@ -3252,7 +3260,8 @@ class CObject(ObjectDescription):
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
@@ -3265,9 +3274,9 @@ class CObject(ObjectDescription):
# Assume we are actually in the old symbol,
# instead of the newly created duplicate.
self.env.temp_data['c:last_symbol'] = e.symbol
msg = __("Duplicate C declaration, also defined in '%s'.\n"
"Declaration is '%s'.")
msg = msg % (e.symbol.docname, sig)
msg = __("Duplicate C declaration, also defined at %s:%s.\n"
"Declaration is '.. c:%s:: %s'.")
msg = msg % (e.symbol.docname, e.symbol.line, self.display_object_type, sig)
logger.warning(msg, location=signode)
if ast.objectType == 'enumerator':
@@ -3694,7 +3703,7 @@ class CDomain(Domain):
'texpr': CExprRole(asCode=False)
}
initial_data = {
'root_symbol': Symbol(None, None, None, None),
'root_symbol': Symbol(None, None, None, None, None),
'objects': {}, # fullname -> docname, node_id, objtype
} # type: Dict[str, Union[Symbol, Dict[str, Tuple[str, str, str]]]]

View File

@@ -3798,7 +3798,7 @@ class Symbol:
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)
return Symbol(None, None, None, None, None, None, None)
@staticmethod
def debug_print(*args: Any) -> None:
@@ -3825,7 +3825,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
@@ -3835,6 +3836,7 @@ class Symbol:
self.templateArgs = templateArgs # identifier<templateArgs>
self.declaration = declaration
self.docname = docname
self.line = line
self.isRedeclaration = False
self._assert_invariants()
@@ -3850,15 +3852,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()
@@ -3882,7 +3887,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:
@@ -3895,7 +3900,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
@@ -3913,6 +3918,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:
@@ -4223,7 +4229,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.
@@ -4232,9 +4238,9 @@ class Symbol:
Symbol.debug_print("_add_symbols:")
Symbol.debug_indent += 1
Symbol.debug_print("tdecls:", ",".join(str(t) for t in templateDecls))
Symbol.debug_print("nn: ", nestedName)
Symbol.debug_print("decl: ", declaration)
Symbol.debug_print("doc: ", docname)
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],
@@ -4251,7 +4257,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,
@@ -4272,14 +4278,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
@@ -4328,7 +4334,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
@@ -4400,7 +4406,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],
@@ -4479,13 +4485,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 C++ 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
@@ -4509,23 +4517,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
@@ -4720,7 +4730,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:
@@ -6726,7 +6737,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:
@@ -6840,7 +6851,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:
@@ -6856,7 +6867,8 @@ class CPPObject(ObjectDescription):
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
@@ -6869,9 +6881,10 @@ 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
msg = __("Duplicate C++ declaration, also defined in '%s'.\n"
"Declaration is '%s'.")
msg = msg % (e.symbol.docname, sig)
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':
@@ -7290,7 +7303,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
}

View File

@@ -54,8 +54,8 @@ def _check(name, input, idDict, output, key, asTextOutput):
print("Result: ", res)
print("Expected: ", outputAst)
raise DefinitionError("")
rootSymbol = Symbol(None, None, None, None)
symbol = rootSymbol.add_declaration(ast, docname="TestDoc")
rootSymbol = Symbol(None, None, None, None, None)
symbol = rootSymbol.add_declaration(ast, docname="TestDoc", line=42)
parentNode = addnodes.desc()
signode = addnodes.desc_signature(input, '')
parentNode += signode

View File

@@ -60,8 +60,8 @@ def _check(name, input, idDict, output, key, asTextOutput):
print("Result: ", res)
print("Expected: ", outputAst)
raise DefinitionError("")
rootSymbol = Symbol(None, None, None, None, None, None)
symbol = rootSymbol.add_declaration(ast, docname="TestDoc")
rootSymbol = Symbol(None, None, None, None, None, None, None)
symbol = rootSymbol.add_declaration(ast, docname="TestDoc", line=42)
parentNode = addnodes.desc()
signode = addnodes.desc_signature(input, '')
parentNode += signode
@@ -1246,8 +1246,8 @@ def test_mix_decl_duplicate(app, warning):
restructuredtext.parse(app, text)
ws = warning.getvalue().split("\n")
assert len(ws) == 5
assert "index.rst:2: WARNING: Duplicate C++ declaration, also defined in 'index'." in ws[0]
assert "Declaration is 'void A()'." in ws[1]
assert "index.rst:3: WARNING: Duplicate C++ declaration, also defined in 'index'." in ws[2]
assert "Declaration is 'A'." in ws[3]
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] == ""