Skip to content

rule: add no-increment-decrement rule - #1771

Open
ChrisJr404 wants to merge 2 commits into
revive-lint:masterfrom
ChrisJr404:add-no-increment-decrement-rule
Open

ChrisJr404 wants to merge 2 commits into
revive-lint:masterfrom
ChrisJr404:add-no-increment-decrement-rule

Conversation

@ChrisJr404

Copy link
Copy Markdown
Contributor

This adds no-increment-decrement, a new rule that is the mirror image of the existing increment-decrement rule, for people who prefer the explicit i += 1 / i -= 1 forms over i++ / i--.

As raised in #910, increment-decrement is opinionated in the direction of ++/--, but plenty of styles (and languages) go the other way, and in practice ++/-- are rarely used in Go outside of loop counters. The new rule spots i++ and i-- statements and proposes replacing them with i += 1 and i -= 1. Increment/decrement statements that appear as the post statement of a for loop are intentionally left alone, since that is the idiomatic place for a loop counter (see the for i := 0; i < n; i++ example in the docs).

Like every other revive rule it is opt-in, so the default behaviour is unchanged. It works purely on the AST and requires no type information, so it is registered in untyped.toml.

Naming: I went with no-increment-decrement to make it easy to find as the counterpart of increment-decrement, but I'm happy to rename it if you'd prefer something else.

Changes:

  • rule/no_increment_decrement.go — the rule.
  • test/no_increment_decrement_test.go + testdata/no_increment_decrement.go — fixtures covering standalone ++/--, a selector operand, a counter incremented inside a loop body (flagged), and for-loop counters (not flagged).
  • Registered the rule in config/config.go and untyped.toml, bumped the rule count in config/config_test.go, and documented it in RULES_DESCRIPTIONS.md.

Testing: go test ./... passes, and both revive --config revive.toml ./... and golangci-lint run are clean on the new files.

Closes #910

Add a new rule that is the opposite of increment-decrement: it flags
`i++` and `i--` statements and suggests replacing them with `i += 1` and
`i -= 1`. Increment/decrement statements used as the post statement of a
`for` loop are left untouched, since that is the idiomatic place for a
loop counter.

The rule is opt-in like every other revive rule, so default behaviour is
unchanged.

Closes revive-lint#910

@chavacava chavacava 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.

Hi @ChrisJr404, thanks for the PR.
I've left some comments.

Comment on lines +47 to +51
if stmt.Post != nil {
// The post statement of a for loop is the idiomatic place for a loop
// counter, so it is exempted from the rule.
w.loopPosts[stmt.Post] = struct{}{}
}

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.

I think it's possible to handle the special case of increments in the loop post without keeping track of loopPosts in a list: when visiting a forStmt launch the visitor on the for body and then return nil; this will make the visitor to skip the post part of the for.

Something like:

Suggested change
if stmt.Post != nil {
// The post statement of a for loop is the idiomatic place for a loop
// counter, so it is exempted from the rule.
w.loopPosts[stmt.Post] = struct{}{}
}
w.Visit(stmt.Body) //maybe a check stmt.Body != nil is necessary before calling Visit
return nil

}

w.onFailure(lint.Failure{
Confidence: 0.8,

@chavacava chavacava Aug 18, 2026 •

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.

confidence could be 1, here we are sure it's an increment/decrement that should be replaced

Comment on lines +13 to +15
for j := 10; j > 0; j-- {
_ = j
}

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.

It could be interesting to test with an increment in a for body

Suggested change
for j := 10; j > 0; j-- {
_ = j
}
for j := 10; j > 0; j-- {
_ = j
}
x := 0
for j := 10; j > 0; j-- {
_ = j
x++ // MATCH /should replace x++ with x += 1/
x-- // MATCH /should replace x-- with x -= 1/
}

@chavacava

Copy link
Copy Markdown
Collaborator

@ChrisJr404 please also include the rule in the rule list table on the README.md

@ChrisJr404

Copy link
Copy Markdown
Contributor Author

Good catch - added the rule to the README rule list table (between nested-structs and optimize-operands-order).

@ccoVeille

ccoVeille commented Aug 18, 2026 •

Copy link
Copy Markdown
Contributor

I have a problem here.

First, this rule is purely stylistic. Some may like it, some may not. I feel like 99% of people will be in the second team.

But the real problem is the fact once merged this rule will be part of revive enable all rules settings. And then it would be enabled for anyone.

For me, this should be a linter independent from revive.

The only possible way according to me would be that this feature becomes a setting of an existing revive rule. So here, I feel a setting of increment-decrement should be the way.

Also, if we now consider there is a rule for using i++ and one for using i += 1, using enable-all-rules would lead to infinite back and forth fixes

This is the feedback I do, and I'm looking for maintainers feedback.

Do not rush into doing changes.

@alexandear alexandear added the blocked Needs a direct action from a maintainer. label Aug 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

blocked Needs a direct action from a maintainer.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Opposite of increment-decrement (for non-loop-counter usage)

4 participants