Honour disable comments in FIELD_NUMBERS_ORDER_ASCENDING - #566
Conversation
The rule walks message.MessageBody and enum.EnumBody itself instead of implementing VisitField and VisitEnumField, so extendedDisableRuleVisitor never gets to look at the comments attached to a single field and "// protolint:disable:this FIELD_NUMBERS_ORDER_ASCENDING" is silently ignored. The block form is ignored inside a message for the same reason, so the rule cannot currently be turned off for part of a message at all. Interpret the directives in the rule itself. A disabled field still takes part in the ordering chain and only the report about it is suppressed, so a field added after the disabled ones keeps being checked against them. Fixes yoheimuta#558
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1d0e506830
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // to be interpreted here. A disabled field keeps taking part in the ordering chain; | ||
| // only the report about it is suppressed. | ||
| // See https://github.com/yoheimuta/protolint/issues/558 | ||
| interpreter := disablerule.NewInterpreter(v.ruleID) |
There was a problem hiding this comment.
Share disable state with the visitor wrapper
When a persistent disable is already active upon entering a message or enum, extendedDisableRuleVisitor skips this method, so this newly created interpreter never sees an enable attached to a field and checks cannot resume for later fields in that body. Conversely, if this local interpreter encounters a disable after an earlier ordering failure, return !hasError prevents the wrapper from traversing the children, so the disable is not carried to later declarations. Both cases violate the documented disable-until-enable-or-EOF behavior; the ordering logic needs to participate in the wrapper's single stateful traversal rather than maintaining an independent interpreter.
Useful? React with 👍 / 👎.
| continue | ||
| } | ||
|
|
||
| disabled := interpreter.Interpret(field.Comments, field.InlineComment) |
There was a problem hiding this comment.
Process directives on every body element
Because Interpret is called only after the element has been asserted to *parser.Field, persistent directives attached to an option, reserved declaration, nested declaration, or standalone comment are ignored while this method evaluates the fields. For example, option deprecated = true; // protolint:disable FIELD_NUMBERS_ORDER_ASCENDING followed by descending fields still produces a failure; the wrapper visits the option only after VisitMessage has already performed the ordering check. The enum loop has the same problem, so directives from every body element need to be consumed in source order.
Useful? React with 👍 / 👎.
Fixes #558
The problem
// protolint:disable:this FIELD_NUMBERS_ORDER_ASCENDINGon a field line issilently ignored:
The same is true for the block form inside a message, so at the moment there is no
way to turn this rule off for part of a message.
That the directive itself is fine is easy to show — on the same line, for another
rule, it works:
badNameis exempted fromFIELD_NAMES_LOWER_SNAKE_CASEas asked, whileFIELD_NUMBERS_ORDER_ASCENDINGignores the directive on the very same line.The cause
extendedDisableRuleVisitoris what interprets the directives, and it does so perelement:
VisitFieldreadsf.Comments/f.InlineCommentand, when a directivematches, does not call the inner rule at all.
FieldNumbersOrderAscendingRuledoes not implementVisitFieldorVisitEnumField— it walks
message.MessageBodyandenum.EnumBodyitself insideVisitMessage/VisitEnum. The wrapper therefore never reaches the fields, and nobody reads thecomments attached to them.
The change
Interpret the directives in the rule itself, with the same
disablerule.Interpreterthe wrapper uses.One decision worth calling out: a disabled field still takes part in the ordering
chain, only the report about it is suppressed. Dropping disabled fields from the
chain also makes the reported case quiet, but then the next field is compared
against nothing and effectively stops being checked — the opposite of what the
issue asks for ("when my colleagues add
uint64 c = 3I want protolint to force itin the end of the message"). With this patch:
If you would rather have disabled fields dropped from the chain entirely, that is a
two-line change and I am happy to switch.
Tests
New table in
fieldNumbersOrderAscendingRule_disable_test.go: fields with thedirective, enum fields with the directive, a field following disabled ones (still
checked), and a field without the directive (still checked).
got [field a should be after b (ascending order expected)], but want []TestFieldNumbersOrderAscendingRule_Applykeep passinggo test -race ./...: no new failures.internal/linter/report/reporters(
TestEnvMatcherReporterFromUnallowedTemplateFile_Report) already fails on aclean master here and is unrelated to this change.