Skip to content

Commit bcf9c6b

Browse files
committed
C, intersphinx delegation
1 parent a635156 commit bcf9c6b

File tree

2 files changed

+97
-11
lines changed

2 files changed

+97
-11
lines changed

sphinx/domains/c/__init__.py

Lines changed: 74 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from __future__ import annotations
44

5-
from typing import TYPE_CHECKING, Any, ClassVar
5+
from typing import TYPE_CHECKING, Any, ClassVar, cast
66

77
from docutils import nodes
88
from docutils.parsers.rst import directives
@@ -13,6 +13,7 @@
1313
from sphinx.domains.c._ast import (
1414
ASTDeclaration,
1515
ASTIdentifier,
16+
ASTIntersphinx_v2,
1617
ASTNestedName,
1718
)
1819
from sphinx.domains.c._ids import _macroKeywords, _max_id
@@ -666,6 +667,10 @@ class CDomain(Domain):
666667
'objects': {}, # fullname -> docname, node_id, objtype
667668
}
668669

670+
initial_intersphinx_inventory = {
671+
'root_symbol': Symbol(None, None, None, None, None),
672+
}
673+
669674
def clear_doc(self, docname: str) -> None:
670675
if Symbol.debug_show_tree:
671676
logger.debug("clear_doc: %s", docname)
@@ -712,9 +717,10 @@ def merge_domaindata(self, docnames: list[str], otherdata: dict[str, Any]) -> No
712717
ourObjects[fullname] = (fn, id_, objtype)
713718
# no need to warn on duplicates, the symbol merge already does that
714719

715-
def _resolve_xref_inner(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
716-
typ: str, target: str, node: pending_xref,
717-
contnode: Element) -> tuple[Element | None, str | None]:
720+
def _resolve_xref_in_tree(self, env: BuildEnvironment, root: Symbol,
721+
softParent: bool,
722+
typ: str, target: str,
723+
node: pending_xref) -> tuple[Symbol, ASTNestedName]:
718724
parser = DefinitionParser(target, location=node, config=env.config)
719725
try:
720726
name = parser.parse_xref_object()
@@ -723,20 +729,32 @@ def _resolve_xref_inner(self, env: BuildEnvironment, fromdocname: str, builder:
723729
location=node)
724730
return None, None
725731
parentKey: LookupKey = node.get("c:parent_key", None)
726-
rootSymbol = self.data['root_symbol']
727732
if parentKey:
728-
parentSymbol: Symbol = rootSymbol.direct_lookup(parentKey)
733+
parentSymbol: Symbol = root.direct_lookup(parentKey)
729734
if not parentSymbol:
730-
logger.debug("Target: %s", target)
731-
logger.debug("ParentKey: %s", parentKey)
732-
logger.debug(rootSymbol.dump(1))
733-
assert parentSymbol # should be there
735+
if softParent:
736+
parentSymbol = root
737+
else:
738+
msg = f"Target: {target}\nParentKey: {parentKey}\n{root.dump(1)}\n"
739+
raise AssertionError(msg)
734740
else:
735-
parentSymbol = rootSymbol
741+
parentSymbol = root
736742
s = parentSymbol.find_declaration(name, typ,
737743
matchSelf=True, recurseInAnon=True)
738744
if s is None or s.declaration is None:
739745
return None, None
746+
# TODO: conditionally warn about xrefs with incorrect tagging?
747+
return s, name
748+
749+
def _resolve_xref_inner(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
750+
typ: str, target: str, node: pending_xref,
751+
contnode: Element) -> tuple[Element, str]:
752+
if Symbol.debug_lookup:
753+
Symbol.debug_print("C._resolve_xref_inner(type={}, target={})".format(typ, target))
754+
s, name = self._resolve_xref_in_tree(env, self.data['root_symbol'],
755+
False, typ, target, node)
756+
if s is None:
757+
return None, None
740758

741759
# TODO: check role type vs. object type
742760

@@ -779,6 +797,51 @@ def get_objects(self) -> Iterator[tuple[str, str, str, str, str, int]]:
779797
newestId = symbol.declaration.get_newest_id()
780798
yield (name, dispname, objectType, docname, newestId, 1)
781799

800+
def intersphinx_add_entries_v2(self, store: dict,
801+
data: dict[str, dict[str, Any]]) -> None:
802+
root = store['root_symbol'] # type: Symbol
803+
for object_type, per_type_data in data.items():
804+
for object_name, item_set in per_type_data.items():
805+
parser = DefinitionParser(
806+
object_name, location=('intersphinx', 0), config=self.env.config)
807+
try:
808+
ast = parser._parse_nested_name()
809+
except DefinitionError as e:
810+
logger.warning("Error in C entry in intersphinx inventory:\n" + str(e))
811+
continue
812+
decl = ASTDeclaration(object_type, 'intersphinx',
813+
ASTIntersphinx_v2(ast, item_set))
814+
root.add_declaration(decl, docname="$FakeIntersphinxDoc", line=0)
815+
816+
def _intersphinx_resolve_xref_inner(self, env: "BuildEnvironment", store: dict,
817+
target: str,
818+
node: pending_xref,
819+
typ: str) -> Any | None:
820+
if Symbol.debug_lookup:
821+
Symbol.debug_print(
822+
f"C._intersphinx_resolve_xref_inner(type={typ}, target={target})")
823+
s, name = self._resolve_xref_in_tree(env, store['root_symbol'],
824+
True, typ, target, node)
825+
if s is None:
826+
return None
827+
assert s.declaration is not None
828+
decl = cast(ASTIntersphinx_v2, s.declaration.declaration)
829+
return decl.data
830+
831+
def intersphinx_resolve_xref(self, env: "BuildEnvironment",
832+
store: Any,
833+
typ: str, target: str,
834+
disabled_object_types: list[str],
835+
node: pending_xref, contnode: Element
836+
) -> Any | None:
837+
if typ == 'any':
838+
with logging.suppress_logging():
839+
return self._intersphinx_resolve_xref_inner(
840+
env, store, target, node, typ)
841+
else:
842+
return self._intersphinx_resolve_xref_inner(
843+
env, store, target, node, typ)
844+
782845

783846
def setup(app: Sphinx) -> ExtensionMetadata:
784847
app.add_domain(CDomain)

sphinx/domains/c/_ast.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
DeclarationType = Union[
2626
"ASTStruct", "ASTUnion", "ASTEnum", "ASTEnumerator",
2727
"ASTType", "ASTTypeWithInit", "ASTMacro",
28+
"ASTIntersphinx_v2",
2829
]
2930

3031

@@ -1329,6 +1330,28 @@ def describe_signature(self, signode: TextElement, mode: str,
13291330
self.init.describe_signature(signode, 'markType', env, symbol)
13301331

13311332

1333+
class ASTIntersphinx_v2(ASTBaseBase):
1334+
def __init__(self, name: ASTNestedName, data: Any) -> None:
1335+
self.name = name
1336+
self.data = data
1337+
1338+
def _stringify(self, transform: StringifyTransform) -> str:
1339+
return transform(self.name) + " (has data)"
1340+
1341+
def get_id(self, version: int, objectType: str, symbol: "Symbol") -> str:
1342+
return symbol.get_full_nested_name().get_id(version)
1343+
1344+
def describe_signature(self, signode: TextElement, mode: str,
1345+
env: "BuildEnvironment", symbol: "Symbol") -> None:
1346+
raise AssertionError # should not happen
1347+
1348+
@property
1349+
def function_params(self) -> list[ASTFunctionParameter] | None:
1350+
# the v2 data does not contain actual declarations, but just names
1351+
# so return nothing here
1352+
return None
1353+
1354+
13321355
class ASTDeclaration(ASTBaseBase):
13331356
def __init__(self, objectType: str, directiveType: str | None,
13341357
declaration: DeclarationType | ASTFunctionParameter,

0 commit comments

Comments
 (0)