Skip to content

Commit

Permalink
C, intersphinx delegation
Browse files Browse the repository at this point in the history
  • Loading branch information
jakobandersen committed Mar 23, 2021
1 parent bd6aee0 commit af5828f
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 16 deletions.
8 changes: 4 additions & 4 deletions sphinx/domains/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@

import copy
from abc import ABC, abstractmethod
from typing import (TYPE_CHECKING, Any, Callable, Dict, Iterable, List, NamedTuple,
Optional, Tuple, Type, Union, cast)
from typing import (TYPE_CHECKING, Any, Callable, Dict, Iterable, List, NamedTuple, Optional,
Tuple, Type, Union, cast)

from docutils import nodes
from docutils.nodes import Element, Node, TextElement, system_message
Expand Down Expand Up @@ -409,7 +409,7 @@ def get_full_qualified_name(self, node: Element) -> str:
"""Return full qualified name for given node."""
return None

def intersphinx_add_entries_v2(self, store: Any,
def intersphinx_add_entries_v2(self, store: Dict,
data: Dict[Tuple[str, str], InventoryItemSet]) -> None:
"""Store the given *data* for later intersphinx reference resolution.
Expand Down Expand Up @@ -512,7 +512,7 @@ def intersphinx_resolve_xref(self, env: "BuildEnvironment", store: Any,
return None
return self._intersphinx_resolve_xref_1(store, target, node, contnode, objtypes)

def intersphinx_resolve_any_xref(self, env: "BuildEnvironment", store: Any,
def intersphinx_resolve_any_xref(self, env: "BuildEnvironment", store: Dict,
target: str, node: pending_xref,
contnode: TextElement) -> Optional[Element]:
"""Resolve the pending_xref *node* with the given *typ* and *target* via intersphinx.
Expand Down
108 changes: 96 additions & 12 deletions sphinx/domains/c.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
"""

import re
from typing import (Any, Callable, Dict, Generator, Iterator, List, Tuple, Type, TypeVar,
Union, cast)
from typing import (Any, Callable, Dict, Generator, Iterator, List, Optional, Tuple, Type,
TypeVar, Union, cast)

from docutils import nodes
from docutils.nodes import Element, Node, TextElement, system_message
Expand Down Expand Up @@ -38,6 +38,7 @@
octal_literal_re, verify_description_mode)
from sphinx.util.docfields import Field, TypedField
from sphinx.util.docutils import SphinxDirective
from sphinx.util.inventory import InventoryItemSet
from sphinx.util.nodes import make_refnode
from sphinx.util.typing import OptionSpec

Expand All @@ -47,6 +48,7 @@
DeclarationType = Union[
"ASTStruct", "ASTUnion", "ASTEnum", "ASTEnumerator",
"ASTType", "ASTTypeWithInit", "ASTMacro",
"ASTIntersphinx_v2",
]

# https://en.cppreference.com/w/c/keyword
Expand Down Expand Up @@ -1360,6 +1362,28 @@ def describe_signature(self, signode: TextElement, mode: str,
self.init.describe_signature(signode, 'markType', env, symbol)


class ASTIntersphinx_v2(ASTBaseBase):
def __init__(self, name: ASTNestedName, data: InventoryItemSet):
self.name = name
self.data = data

def _stringify(self, transform: StringifyTransform) -> str:
return transform(self.name) + " (has data)"

def get_id(self, version: int, objectType: str, symbol: "Symbol") -> str:
return symbol.get_full_nested_name().get_id(version)

def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
assert False # Should not happen

@property
def function_params(self):
# the v2 data does not contain actual declarations, but just names
# so return nothing here
return None


class ASTDeclaration(ASTBaseBase):
def __init__(self, objectType: str, directiveType: str,
declaration: Union[DeclarationType, ASTFunctionParameter],
Expand Down Expand Up @@ -3745,6 +3769,10 @@ class CDomain(Domain):
'objects': {}, # fullname -> docname, node_id, objtype
}

initial_intersphinx_inventory = {
'root_symbol': Symbol(None, None, None, None, None),
}

def clear_doc(self, docname: str) -> None:
if Symbol.debug_show_tree:
print("clear_doc:", docname)
Expand Down Expand Up @@ -3791,9 +3819,10 @@ def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None:
ourObjects[fullname] = (fn, id_, objtype)
# no need to warn on duplicates, the symbol merge already does that

def _resolve_xref_inner(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
typ: str, target: str, node: pending_xref,
contnode: Element) -> Tuple[Element, str]:
def _resolve_xref_in_tree(self, env: BuildEnvironment, root: Symbol,
softParent: bool,
typ: str, target: str, node: pending_xref,
contnode: Element) -> Tuple[Symbol, ASTNestedName]:
parser = DefinitionParser(target, location=node, config=env.config)
try:
name = parser.parse_xref_object()
Expand All @@ -3802,20 +3831,34 @@ def _resolve_xref_inner(self, env: BuildEnvironment, fromdocname: str, builder:
location=node)
return None, None
parentKey: LookupKey = node.get("c:parent_key", None)
rootSymbol = self.data['root_symbol']
if parentKey:
parentSymbol: Symbol = rootSymbol.direct_lookup(parentKey)
parentSymbol: Symbol = root.direct_lookup(parentKey)
if not parentSymbol:
print("Target: ", target)
print("ParentKey: ", parentKey)
print(rootSymbol.dump(1))
assert parentSymbol # should be there
if softParent:
parentSymbol = root
else:
print("Target: ", target)
print("ParentKey: ", parentKey)
print(root.dump(1))
assert False
else:
parentSymbol = rootSymbol
parentSymbol = root
s = parentSymbol.find_declaration(name, typ,
matchSelf=True, recurseInAnon=True)
if s is None or s.declaration is None:
return None, None
# TODO: conditionally warn about xrefs with incorrect tagging?
return s, name

def _resolve_xref_inner(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
typ: str, target: str, node: pending_xref,
contnode: Element) -> Tuple[Element, str]:
if Symbol.debug_lookup:
print("C._resolve_xref_inner(type={}, target={})".format(typ, target))
s, name = self._resolve_xref_in_tree(env, self.data['root_symbol'],
False, typ, target, node, contnode)
if s is None:
return None, None

# TODO: check role type vs. object type

Expand Down Expand Up @@ -3858,6 +3901,47 @@ def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]:
newestId = symbol.declaration.get_newest_id()
yield (name, dispname, objectType, docname, newestId, 1)

def intersphinx_add_entries_v2(self, store: Dict,
data: Dict[Tuple[str, str], InventoryItemSet]) -> None:
root = store['root_symbol'] # type: Symbol
for k, v in data.items():
object_name, object_type = k
parser = DefinitionParser(
object_name, location=('intersphinx', 0), config=self.env.config)
try:
ast = parser._parse_nested_name()
except DefinitionError as e:
logger.warning("Error in C entry in intersphinx inventory:\n" + str(e))
continue
decl = ASTDeclaration(object_type, 'intersphinx', ASTIntersphinx_v2(ast, v))
root.add_declaration(decl, docname="$FakeIntersphinxDoc", line=0)

def _intersphinx_resolve_xref_inner(self, env: "BuildEnvironment", store: Dict,
target: str,
node: pending_xref, contnode: TextElement,
typ: str) -> Optional[Element]:
if Symbol.debug_lookup:
print("C._intersphinx_resolve_xref_inner(type={}, target={})".format(typ, target))
s, name = self._resolve_xref_in_tree(env, store['root_symbol'],
True, typ, target, node, contnode)
if s is None:
return None
assert s.declaration is not None
decl = cast(ASTIntersphinx_v2, s.declaration.declaration)
return decl.data.make_refnode(self.name, target, node, contnode)

def intersphinx_resolve_xref(self, env: "BuildEnvironment", store: Dict,
typ: str, target: str, node: pending_xref,
contnode: TextElement) -> Optional[Element]:
return self._intersphinx_resolve_xref_inner(env, store, target, node, contnode, typ)

def intersphinx_resolve_any_xref(self, env: "BuildEnvironment", store: Dict,
target: str, node: pending_xref,
contnode: TextElement) -> Optional[Element]:
with logging.suppress_logging():
return self._intersphinx_resolve_xref_inner(
env, store, target, node, contnode, 'any')


def setup(app: Sphinx) -> Dict[str, Any]:
app.add_domain(CDomain)
Expand Down

0 comments on commit af5828f

Please sign in to comment.