Skip to content

Commit 77eea15

Browse files
authored
Python: Populate declaring type on function declarations from ty-types descriptors (#7221)
1 parent 9f84dc2 commit 77eea15

2 files changed

Lines changed: 49 additions & 1 deletion

File tree

rewrite-python/rewrite/src/rewrite/python/type_mapping.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -781,7 +781,7 @@ def _method_from_function_descriptor(
781781

782782
return JavaType.Method(
783783
_flags_bit_map=0,
784-
_declaring_type=None,
784+
_declaring_type=self._get_declaration_declaring_type(descriptor),
785785
_name=name,
786786
_return_type=return_type,
787787
_parameter_names=param_names if param_names else None,
@@ -1266,3 +1266,20 @@ def _get_node_text(self, node: ast.expr) -> str:
12661266
def module_to_fqn(module_path: str) -> str:
12671267
"""Convert a Python module path to a fully qualified name."""
12681268
return module_path
1269+
1270+
def _get_declaration_declaring_type(self, descriptor: Dict[str, Any]) -> Optional[JavaType.FullyQualified]:
1271+
"""Get the declaring type for a function declaration.
1272+
1273+
Mirrors the invocation-side logic from _get_declaring_type() to ensure
1274+
declarations and invocations produce matching FQNs.
1275+
"""
1276+
class_name = descriptor.get('className')
1277+
if class_name:
1278+
module_name = descriptor.get('moduleName')
1279+
if module_name and module_name != 'builtins':
1280+
return self._create_class_type(f"{module_name}.{class_name}")
1281+
return self._create_class_type(class_name)
1282+
module_name = descriptor.get('moduleName')
1283+
if module_name and module_name != 'builtins':
1284+
return self._create_class_type(module_name)
1285+
return None

rewrite-python/rewrite/tests/python/test_type_attribution.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1846,3 +1846,34 @@ def test_known_instance_typevar_resolves_to_class(self):
18461846
assert 'typing' in result._fully_qualified_name
18471847
finally:
18481848
_cleanup_mapping(mapping, tmpdir, client)
1849+
1850+
1851+
class TestDeclarationDeclaringType:
1852+
"""Tests for declaring type on function declarations."""
1853+
1854+
def test_declaration_declaring_type_no_ty_types(self):
1855+
"""Without ty-types, declaring type remains None."""
1856+
source = 'def greet(name: str) -> str:\n return name\n'
1857+
tree = ast.parse(source)
1858+
mapping = PythonTypeMapping(source)
1859+
func_node = tree.body[0]
1860+
result = mapping.method_declaration_type(func_node)
1861+
assert result is not None
1862+
assert result._declaring_type is None
1863+
1864+
@requires_ty_types_cli
1865+
def test_declaration_declaring_type_with_ty_types(self):
1866+
"""With ty-types, a function declaration should get a declaring type from the descriptor."""
1867+
source = 'def greet(name: str) -> str:\n return name\n'
1868+
mapping, tree, tmpdir, client = _make_mapping(source)
1869+
try:
1870+
func_node = tree.body[0]
1871+
result = mapping.method_declaration_type(func_node)
1872+
assert result is not None
1873+
assert isinstance(result, JavaType.Method)
1874+
assert result._declaring_type is not None, \
1875+
"Declaration should have a declaring type, not None"
1876+
assert isinstance(result._declaring_type, JavaType.Class)
1877+
assert result._declaring_type._fully_qualified_name != "<unknown>"
1878+
finally:
1879+
_cleanup_mapping(mapping, tmpdir, client)

0 commit comments

Comments
 (0)