Skip to content

Commit 4ec61ee

Browse files
committed
Fix Scala case class and inner class mapping to source files
1 parent a522fab commit 4ec61ee

5 files changed

Lines changed: 37 additions & 31 deletions

File tree

scanpipe/pipes/d2d.py

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -168,24 +168,28 @@ def _map_jvm_to_class_resource(
168168
normalized_path = jvm_lang.get_normalized_path(
169169
path=to_resource.path, extension=extension
170170
)
171+
171172
match = pathmap.find_paths(path=normalized_path, index=from_classes_index)
172-
if not match:
173-
if jvm_lang.name == "scala":
174-
package_path = str(Path(normalized_path).parent)
175-
potential_sources = from_resources.filter(
176-
path__startswith=package_path,
177-
extension__in=jvm_lang.source_extensions
173+
174+
if not match and jvm_lang.name == "scala":
175+
package_path = str(Path(to_resource.path).parent)
176+
potential_sources = from_resources.filter(
177+
path__startswith=package_path.replace("to/", "from/"),
178+
extension__in=jvm_lang.source_extensions,
179+
)
180+
for from_resource in potential_sources:
181+
from_source_root_parts = from_resource.path.strip("/").split("/")
182+
from_source_root = "/".join(from_source_root_parts[:-1])
183+
pipes.make_relation(
184+
from_resource=from_resource,
185+
to_resource=to_resource,
186+
map_type=jvm_lang.binary_map_type,
187+
extra_data={"from_source_root": f"{from_source_root}/"},
178188
)
179-
for from_resource in potential_sources:
180-
from_source_root_parts = from_resource.path.strip("/").split("/")
181-
from_source_root = "/".join(from_source_root_parts[:-1])
182-
pipes.make_relation(
183-
from_resource=from_resource,
184-
to_resource=to_resource,
185-
map_type=jvm_lang.binary_map_type,
186-
extra_data={"from_source_root": f"{from_source_root}/"},
187-
)
188-
return
189+
continue
190+
191+
if not match:
192+
continue
189193

190194
for resource_id in match.resource_ids:
191195
from_resource = from_resources.get(id=resource_id)

scanpipe/pipes/jvm.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,12 +186,12 @@ def get_normalized_path(cls, path, extension):
186186
)
187187
path_obj = Path(path.strip("/"))
188188
class_name = path_obj.name
189-
189+
190190
if "$" in class_name:
191191
class_name, _, _ = class_name.partition("$")
192192
else:
193193
class_name, _, _ = class_name.partition(".")
194-
194+
195195
return str(path_obj.parent / f"{class_name}{extension}")
196196

197197

scanpipe/pipes/resolve.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ def get_data_from_manifests(project, package_registry, manifest_resources, model
108108
if "pypi" in manifests_by_type:
109109
pypi_resources = manifests_by_type["pypi"]
110110
pypi_locations = [resource.location for resource in pypi_resources]
111-
111+
112112
resolver = package_registry.get("pypi")
113113
if resolver:
114114
try:
@@ -117,7 +117,7 @@ def get_data_from_manifests(project, package_registry, manifest_resources, model
117117
for package_data in packages:
118118
package_data["codebase_resources"] = pypi_resources
119119
resolved_packages.extend(packages)
120-
120+
121121
for resource in pypi_resources:
122122
if headers := get_manifest_headers(resource):
123123
sboms_headers[resource.name] = headers
@@ -135,7 +135,7 @@ def get_data_from_manifests(project, package_registry, manifest_resources, model
135135
model=model,
136136
object_instance=resource,
137137
)
138-
138+
139139
del manifests_by_type["pypi"]
140140

141141
for package_type, resources in manifests_by_type.items():
@@ -267,13 +267,14 @@ def get_manifest_resources(project):
267267
def resolve_pypi_packages(input_location=None, input_locations=None):
268268
"""
269269
Resolve the PyPI packages from requirement file(s).
270-
270+
271271
Args:
272272
input_location: Single requirement file path (for backward compatibility)
273273
input_locations: List of requirement file paths (for batch processing)
274-
274+
275275
Returns:
276276
List of resolved package data dictionaries
277+
277278
"""
278279
# Handle both single file and multiple files
279280
if input_locations:
@@ -282,7 +283,7 @@ def resolve_pypi_packages(input_location=None, input_locations=None):
282283
requirement_files = [input_location]
283284
else:
284285
raise ValueError("Either input_location or input_locations must be provided")
285-
286+
286287
python_version = f"{sys.version_info.major}{sys.version_info.minor}"
287288
operating_system = "linux"
288289

scanpipe/tests/pipes/test_d2d.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,6 @@ def test_scanpipe_pipes_d2d_map_scala_case_classes_to_source(self):
649649
self.assertEqual(from1, relation.from_resource)
650650
self.assertEqual("scala_to_class", relation.map_type)
651651

652-
653652
def test_scanpipe_pipes_d2d_map_jar_to_kotlin_source(self):
654653
from1 = make_resource_file(
655654
self.project1,

scanpipe/tests/pipes/test_resolve.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -390,19 +390,22 @@ def test_scanpipe_pipes_resolve_pypi_packages_multiple_files(self, mock_resolve)
390390

391391
req_files = ["requirements1.txt", "requirements2.txt"]
392392
packages = resolve.resolve_pypi_packages(input_locations=req_files)
393-
393+
394394
mock_resolve.assert_called_once()
395395
call_args = mock_resolve.call_args
396396
self.assertEqual(req_files, call_args.kwargs["requirement_files"])
397-
397+
398398
self.assertEqual(2, len(packages))
399399
self.assertEqual("pip", packages[0]["name"])
400400

401401
@mock.patch("scanpipe.pipes.resolve.python_inspector.resolve_dependencies")
402402
def test_scanpipe_pipes_resolve_pypi_packages_backward_compatibility(
403403
self, mock_resolve
404404
):
405-
"""Test that resolve_pypi_packages still works with single file (backward compatibility)."""
405+
"""
406+
Test that resolve_pypi_packages still works with single file
407+
(backward compatibility).
408+
"""
406409
inspector_output_location = (
407410
self.data / "resolve" / "python_inspector_resolve_dependencies.json"
408411
)
@@ -412,10 +415,9 @@ def test_scanpipe_pipes_resolve_pypi_packages_backward_compatibility(
412415
mock_resolve.return_value = mock.Mock(packages=inspector_output["packages"])
413416

414417
packages = resolve.resolve_pypi_packages(input_location="requirements.txt")
415-
418+
416419
mock_resolve.assert_called_once()
417420
call_args = mock_resolve.call_args
418421
self.assertEqual(["requirements.txt"], call_args.kwargs["requirement_files"])
419-
420-
self.assertEqual(2, len(packages))
421422

423+
self.assertEqual(2, len(packages))

0 commit comments

Comments
 (0)