Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions graphify/extractors/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -969,7 +969,8 @@ def _scala_collect_type_refs(node, source: bytes, generic: bool, out: list[tuple
_scala_collect_type_refs(arg, source, True, out)
return

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall. Could you briefly explain why True is passed here instead of using the existing generic variable? It would help future readers understand the intent.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is pre-existing and only appears as context in this diff. It’s where the walker descends into the children of a type_arguments node, so everything below that point is in generic-argument position regardless of the outer generic value. Wrapper nodes instead pass generic through unchanged since they don't change that context.

if t in ("compound_type", "infix_type", "function_type", "tuple_type",
"annotated_type", "projected_type"):
"annotated_type", "projected_type", "match_type",
"type_case_clause"):
for c in node.children:
if c.is_named:
_scala_collect_type_refs(c, source, generic, out)
Expand Down Expand Up @@ -3074,8 +3075,11 @@ def _emit_java_parent_type(type_node, rel: str, at_line: int) -> None:
type_table[prop_name] = prop_type
return

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change seems reasonable. Would adding a short comment above this condition make the special handling for Scala type references easier to understand?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. There’s already a comment just inside the condition explaining the type_definition handling, but I agree it would be clearer above the condition. I’ll move it there.


# type_definition covers plain aliases (`type Alias = List[Int]`),
# `opaque type`, and match types — the right-hand side sits under the
# same `type` field a val/var annotation uses, so the walk is shared.
if (config.ts_module == "tree_sitter_scala"
and t in ("val_definition", "var_definition")
and t in ("val_definition", "var_definition", "type_definition")
and parent_class_nid):
type_node = node.child_by_field_name("type")
if type_node is not None:
Expand Down
9 changes: 9 additions & 0 deletions tests/fixtures/sample.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,12 @@ object HttpClientFactory {
new HttpClient(Config(baseUrl, 30))
}
}

class TypeAliases {
type Routes = Map[String, HttpClient]
opaque type ClientId = Long
type Unwrap[X] = X match {
case Option[t] => t
case ListBuffer[t] => t
}
}
18 changes: 18 additions & 0 deletions tests/test_languages.py
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,24 @@ def test_scala_method_return_type_context():
assert ("create", "HttpClient") in _edge_labels(r, "references", "return_type")


def test_scala_type_alias_rhs_references():
r = extract_scala(FIXTURES / "sample.scala")
assert ("TypeAliases", "Map") in _edge_labels(r, "references", "field")
assert ("TypeAliases", "HttpClient") in _edge_labels(r, "references", "generic_arg")


def test_scala_opaque_type_rhs_references():
r = extract_scala(FIXTURES / "sample.scala")
assert ("TypeAliases", "Long") in _edge_labels(r, "references", "field")


def test_scala_match_type_case_references():
r = extract_scala(FIXTURES / "sample.scala")
labels = _edge_labels(r, "references", "field")
assert ("TypeAliases", "Option") in labels
assert ("TypeAliases", "ListBuffer") in labels


Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice improvement. Have you tested this against nested or more complex Scala type definitions to ensure there are no regressions?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. The committed fixture covers nested type arguments with Map[String, HttpClient] and match-type cases with type-variable binding. I also tested deeper nesting locally with Map[String, List[Option[HttpClient]]] and a match type over Either[Throwable, Vector[Int]]; references resolved correctly at each depth. The full relevant test suite also passes with 324 passed and 13 skipped. Happy to add the deeper-nesting case to the fixture if you'd like it covered explicitly.

def test_scala_call_edges_have_call_context():
r = extract_scala(FIXTURES / "sample.scala")
call_edges = _edges_with_relation(r, "calls")
Expand Down
Loading