diff --git a/graphify/extract.py b/graphify/extract.py index 9b51db18..6e8ab996 100644 --- a/graphify/extract.py +++ b/graphify/extract.py @@ -6637,7 +6637,11 @@ def _augment_systemverilog_semantics( body, flags=re.DOTALL, ) - for field in re.finditer(r"^\s*([A-Za-z_]\w*(?:\s*#\s*\([^;]+?\))?)\s+\w+\s*;", body_without_functions, re.MULTILINE): + # Optional leading class-property qualifiers (rand/local/protected/etc.) + # must be consumed: otherwise a qualified field like `rand Config x;` + # (three tokens) fails the ` ;` shape and its type reference + # is silently dropped. + for field in re.finditer(r"^\s*(?:(?:rand|randc|local|protected|static|const|automatic|var)\s+)*([A-Za-z_]\w*(?:\s*#\s*\([^;]+?\))?)\s+\w+\s*;", body_without_functions, re.MULTILINE): # Count to the start of the type token (group 1), not the match # start: `^\s*` consumes the leading newline(s), so field.start() # would resolve to the class's line instead of the field's. diff --git a/tests/fixtures/sample.sv b/tests/fixtures/sample.sv index ad8ce4e9..2bdaa8a6 100644 --- a/tests/fixtures/sample.sv +++ b/tests/fixtures/sample.sv @@ -10,12 +10,17 @@ endclass class Payload; endclass +class Config; +endclass + class Result #(type T = Payload); T value; endclass class DataProcessor extends BaseProcessor implements Processor; Result #(Payload) current; + rand Config m_cfg; + protected BaseProcessor m_parent; function Result #(Payload) build(Payload input); return current; diff --git a/tests/test_languages.py b/tests/test_languages.py index 28775a79..941fcac8 100644 --- a/tests/test_languages.py +++ b/tests/test_languages.py @@ -2651,6 +2651,18 @@ def test_systemverilog_field_parameter_return_and_generic_contexts(): assert ("build", "Payload") in _edge_labels(r, "references", "generic_arg") +def test_systemverilog_qualified_field_references(): + """Class properties with leading qualifiers (rand/local/protected/etc.) must + still emit `references` field edges. The field regex only matched unqualified + ` ;` declarations, so `rand Config x;` (three tokens) failed to + match and its type reference was silently dropped. + """ + r = extract_verilog(FIXTURES / "sample.sv") + field_refs = _edge_labels(r, "references", "field") + assert ("DataProcessor", "Config") in field_refs, "rand-qualified field dropped" + assert ("DataProcessor", "BaseProcessor") in field_refs, "protected-qualified field dropped" + + def test_systemverilog_does_not_emit_type_parameter_refs(): r = extract_verilog(FIXTURES / "sample.sv") assert ("Result", "T") not in _edge_labels(r, "references", "field")