mirror of
https://github.com/safishamsi/graphify.git
synced 2026-10-13 15:40:05 +00:00
fix(solidity): link enum values with case_of instead of contains
A Solidity enum value is a discriminant case, not a declared member, so it
should hang off its enum with a case_of edge like every other language that
has enums (Java #1719, C#, Swift, Rust, VB.NET). Solidity was the lone
remaining outlier, routing enum values through the same contains path used
for struct fields.
The relation is not cosmetic: case_of targets are excluded from constructor
binding, so an enum value named like a type could previously be mistaken for
one. Struct fields keep contains, since a field is a real declaration.
Add a regression test asserting enum values get case_of (and not contains)
while a struct field keeps contains.
(cherry picked from commit fdd99502d7)
This commit is contained in:
1 parent
b57cf9108e
commit
4f0eb679bf
2 files changed
+41
-1
No files matched your search
@@ -291,7 +291,13 @@ def extract_solidity(path: Path) -> dict:
|
||||
value_name = _read_text(value, source)
|
||||
value_id = _make_id(enum_id, value_name)
|
||||
add_node(value_id, value_name, value, kind="enum_value")
|
||||
add_edge(enum_id, value_id, "contains", value)
|
||||
# An enum value is a discriminant case, not a declared
|
||||
# field, so it gets `case_of` like every other language
|
||||
# with enums (Java #1719, C#, Swift, Rust, VB.NET). The
|
||||
# relation also matters to resolution: `case_of` targets
|
||||
# are excluded from constructor binding, so an enum value
|
||||
# named like a type can no longer be mistaken for one.
|
||||
add_edge(enum_id, value_id, "case_of", value)
|
||||
continue
|
||||
|
||||
simple_kinds = {
|
||||
|
||||
@@ -119,6 +119,40 @@ def test_solidity_types_imports_inheritance_overloads_and_modifiers(tmp_path):
|
||||
assert len([edge for edge in result["edges"] if edge["relation"] == "imports_from"]) == 2
|
||||
|
||||
|
||||
def test_solidity_enum_values_emit_case_of_not_contains(tmp_path):
|
||||
"""A Solidity enum value is a discriminant case, so it must get a `case_of`
|
||||
edge like every other language with enums (Java #1719, C#, Swift, Rust,
|
||||
VB.NET), not the `contains` edge used for real declared members. Solidity
|
||||
was routing enum values through the same `contains` path as struct fields.
|
||||
The relation also matters to resolution: `case_of` targets are excluded
|
||||
from constructor binding, so an enum value named like a type can no longer
|
||||
be mistaken for one.
|
||||
"""
|
||||
source = tmp_path / "Status.sol"
|
||||
source.write_text(
|
||||
"pragma solidity ^0.8.0;\n"
|
||||
"contract Order {\n"
|
||||
" enum Status { Pending, Shipped, Delivered }\n"
|
||||
" struct Point { uint x; uint y; }\n"
|
||||
" Status public status;\n"
|
||||
"}\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
result = extract([source], cache_root=tmp_path)
|
||||
|
||||
case_of = _edge_labels(result, "case_of")
|
||||
contains = _edge_labels(result, "contains")
|
||||
# Each enum value hangs off its enum via case_of, not contains.
|
||||
assert ("Status", "Pending") in case_of
|
||||
assert ("Status", "Shipped") in case_of
|
||||
assert ("Status", "Delivered") in case_of
|
||||
assert ("Status", "Pending") not in contains
|
||||
# A real struct field is a declaration, not a case: it keeps `contains`.
|
||||
assert ("Point", "x") in contains
|
||||
assert ("Point", "x") not in case_of
|
||||
|
||||
|
||||
def test_solidity_fixture_uses_normal_extract_path(tmp_path):
|
||||
result = extract([FIXTURE], cache_root=tmp_path)
|
||||
|
||||
|
||||
Reference in new issue
Block a user