Version / commit
v8 @ 35adf43 (v0.9.76)
What happens
A Solidity enum links its values to the enum with a contains edge, the same relation used for real declared members (struct fields, state variables). Every other language that has enums emits a case_of edge per value — Java (#1719), C#, Swift, Rust, and VB.NET (#4054, the previous outlier that was fixed). Solidity is now the last extractor still using contains for enum values.
Minimal reproduction
// Status.sol
pragma solidity ^0.8.0;
contract Order {
enum Status { Pending, Shipped, Delivered }
struct Point { uint x; uint y; }
}
from graphify.extract import extract
res = extract(["Status.sol"])
for e in res["edges"]:
if e["relation"] in ("case_of", "contains"):
print(e["relation"], e["source"], "->", e["target"])
Expected
Status -> Pending/Shipped/Delivered as case_of (struct field Point.x stays contains).
Actual
Status -> Pending/Shipped/Delivered as contains, indistinguishable from a struct field.
Why it matters
This is not cosmetic. case_of targets are deliberately excluded from constructor binding (_member_nids in extract.py), so an enum value whose name collides with a type can currently be mistaken for a constructable member. It also breaks the cross-language invariant that downstream consumers rely on to tell enum cases apart from declared fields.
Version / commit
v8 @ 35adf43 (v0.9.76)
What happens
A Solidity enum links its values to the enum with a
containsedge, the same relation used for real declared members (struct fields, state variables). Every other language that has enums emits acase_ofedge per value — Java (#1719), C#, Swift, Rust, and VB.NET (#4054, the previous outlier that was fixed). Solidity is now the last extractor still usingcontainsfor enum values.Minimal reproduction
Expected
Status -> Pending/Shipped/Deliveredascase_of(struct fieldPoint.xstayscontains).Actual
Status -> Pending/Shipped/Deliveredascontains, indistinguishable from a struct field.Why it matters
This is not cosmetic.
case_oftargets are deliberately excluded from constructor binding (_member_nidsinextract.py), so an enum value whose name collides with a type can currently be mistaken for a constructable member. It also breaks the cross-language invariant that downstream consumers rely on to tell enum cases apart from declared fields.