Skip to content

port-name-suffix: handle ref direction and all-underscore names - #2534

Open
EylonKrause wants to merge 2 commits into
chipsalliance:masterfrom
EylonKrause:fix/port-name-suffix-ref-underscore
Open

port-name-suffix: handle ref direction and all-underscore names#2534
EylonKrause wants to merge 2 commits into
chipsalliance:masterfrom
EylonKrause:fix/port-name-suffix-ref-underscore

Conversation

@EylonKrause

Copy link
Copy Markdown
Contributor

Problem

PortNameSuffixRule crashes the linter on two kinds of valid SystemVerilog:

  1. A ref port direction throws std::out_of_range (uncaught → linter abort).
  2. An all-underscore port name (e.g. _) dereferences an empty vector (UB).

Details

1. ref directionIsSuffixCorrect does suffixes.at(direction), where suffixes only has keys {input, output, inout}. The grammar's port_direction : dir | TK_ref allows ref, so a port like module m(ref logic data_x); endmodule reaches suffixes.at("ref"), which throws. HandleSymbol runs without a surrounding try/catch, so the linter terminates. (The comment claiming the direction "is guaranteed" to be a known key is incorrect.)

2. all-underscore namename_parts = absl::StrSplit(name, '_', absl::SkipEmpty()). For a name that is only underscores (_, __), every token is empty and SkipEmpty drops them all, leaving name_parts empty. The if (name_parts.size() < 2) block reports a violation but does not return, so name_parts.back() on the next line dereferences an empty vector (UB).

Fix

  1. Look the direction up with find() and treat an unknown direction (e.g. ref) as "correct" — no violation — matching Violation(), which already ignores non-input/output/inout directions.
  2. return after the size() < 2 violation (a name with fewer than two underscore-delimited parts has no suffix to check). This also removes a redundant duplicate Violation insert for no-underscore names.

Tests

port-name-suffix-rule_test.cc: a ref port is accepted (no violation, no crash); an all-underscore _ port reports a single suffix violation instead of crashing.

PortNameSuffixRule crashed the linter on two valid inputs:

- A `ref` port direction: IsSuffixCorrect did suffixes.at(direction) on a map
  keyed only by input/output/inout, so a `ref` port (allowed by the grammar)
  threw std::out_of_range, uncaught, aborting the linter. Look the direction
  up with find() and treat an unknown direction as correct (no violation),
  matching Violation() which already ignores non-input/output/inout.

- An all-underscore name (e.g. "_"): absl::StrSplit with SkipEmpty yields an
  empty parts list, and the size()<2 branch did not return, so name_parts.back()
  dereferenced an empty vector (UB). Return after reporting the violation; this
  also drops a redundant duplicate Violation for no-underscore names.

Adds regression tests: a `ref` port is accepted, and an all-underscore port
reports a single suffix violation instead of crashing.

Signed-off-by: Eylon Krause <eylon1909@gmail.com>
@linux-foundation-easycla

linux-foundation-easycla Bot commented Jul 6, 2026

Copy link
Copy Markdown

CLA Signed
The committers listed above are authorized under a signed CLA.

  • ✅ login: EylonKrause / name: Eylon Krause (94d48b9)

@EylonKrause

Copy link
Copy Markdown
Contributor Author

Disclosure: this contribution was authored with an AI coding assistant (Claude) and reviewed before submission.

// safely and treat an unknown direction as "correct" (no violation),
// consistent with Violation() which also ignores non-input/output/inout
// directions. Using std::map::at() here would throw on e.g. "ref".
const auto it = suffixes.find(direction);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We have the FindWithDefault() in verible/common/util/container-util.h

Maybe use that instead, not only for a more compact writing but also a more visible 'we're looking for something that might not be there but we have a fallback' intent.

return FindWithDefault(suffixes, direction, 1) == 1;

@hzeller hzeller left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for your contribution!
LGTM, but I have one comment about using a map lookup function that might be nicer in this case.

@EylonKrause

Copy link
Copy Markdown
Contributor Author

Thanks! Done — switched to FindWithDefault. Since suffixes maps each direction to a set of valid suffixes (rather than a scalar), I used it with an empty-set fallback so the "look for something that might not be there, with a fallback" intent is explicit, while keeping the behavior that a direction with no convention (e.g. ref) is treated as correct:

static const std::set<std::string_view> kNoConvention;
const std::set<std::string_view> &valid =
    verible::container::FindWithDefault(suffixes, direction, kNoConvention);
return valid.empty() || valid.count(suffix) == 1;

Address review feedback: look the direction up with
verible::container::FindWithDefault and an empty-set fallback instead of
a manual find()/end() check. Since the map holds a set of valid suffixes
per direction, an unknown direction (e.g. `ref`) yields an empty set and
is treated as correct, preserving the existing behavior.

Signed-off-by: Eylon Krause <eylon1909@gmail.com>
@EylonKrause
EylonKrause force-pushed the fix/port-name-suffix-ref-underscore branch from d3a3deb to 324346b Compare August 8, 2026 17:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants