-
Notifications
You must be signed in to change notification settings - Fork 490
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
lint: enable govet shadow linter and resolve linter warnings #5261
Conversation
Codecov Report
@@ Coverage Diff @@
## master #5261 +/- ##
==========================================
- Coverage 55.43% 55.41% -0.02%
==========================================
Files 452 452
Lines 63872 63875 +3
==========================================
- Hits 35405 35394 -11
- Misses 26053 26073 +20
+ Partials 2414 2408 -6
... and 13 files with indirect coverage changes 📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
Talked this through with @cce , basically we are mostly okay with the inconsistent handling in some cases (see cmd/goal/asset.go for an example) as long as the linter (which in ways is stricter than needed) is happy with both of them. For example, we are fine re-using an err variable directly, as long as it is not shadowing (and there is a quick nil check) as in https://github.com/algorand/go-algorand/pull/5261/files#diff-43408fd8ee96ef81b41df4152675473a9d2b76358da39757022f1e2d6ee00872R764 whereas in other situation err2, err3, etc is more appropriate for readability. |
ledger/acctupdates.go
Outdated
@@ -1523,7 +1523,8 @@ func (au *accountUpdates) lookupWithoutRewards(rnd basics.Round, addr basics.Add | |||
} | |||
|
|||
// getCreatorForRound returns the asset/app creator for a given asset/app index at a given round | |||
func (au *accountUpdates) getCreatorForRound(rnd basics.Round, cidx basics.CreatableIndex, ctype basics.CreatableType, synchronized bool) (creator basics.Address, ok bool, err error) { | |||
func (au *accountUpdates) getCreatorForRound(rnd basics.Round, cidx basics.CreatableIndex, ctype basics.CreatableType, synchronized bool) ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Falls in the bucket of "this function is too long for naming return variables"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wish we could enforce a rule around not naming return variables when functions are too long strictly - but doubt linter picks it up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't thinking naming them is the problem, naked returns are the problem. You might name return values if you are trying to distinguish two returned ints - you want to explain which one is which, in the signature.
But naked returns are confusing. It's so easy to not realize what you're returning, especially in the presence of shadowing. So I would much rather ban naked returns in long functions. I very often return things explicitly, even if a naked return would do the same thing. In a long function, it's much easier to understand without a moment's hesitation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, naked returns are the primary culprit. The return value naming is useful for readability, but if we can't stop naked returns in those cases seems not worth it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can ban naked returns for functions longer than a certain number of lines. What should we pick? 50 lines?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It depends on how many failures currently but ideally even less (enough for very simple if / else).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking 15-20 lines max - not sure it's a blocker for this PR but a quick follow-up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do in future PR to add the nakedret
linter maybe with perhaps 50 lines to start
accumulatedChanges := 0 | ||
|
||
for i := 0; i < accountsDeltas.len(); i++ { | ||
delta := accountsDeltas.getByIdx(i) | ||
if !delta.oldAcct.AccountData.IsEmpty() { | ||
deleteHash := trackerdb.AccountHashBuilderV6(delta.address, &delta.oldAcct.AccountData, protocol.Encode(&delta.oldAcct.AccountData)) | ||
deleted, err = ct.balancesTrie.Delete(deleteHash) | ||
deleted, err := ct.balancesTrie.Delete(deleteHash) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are safe without naming the error variable in function signature, frankly more readable too.
@@ -754,7 +754,7 @@ func (c *catchpointCatchupAccessorImpl) BuildMerkleTrie(ctx context.Context, pro | |||
defer wg.Done() | |||
defer close(writerQueue) | |||
|
|||
err := dbs.Snapshot(func(transactionCtx context.Context, tx trackerdb.SnapshotScope) (err error) { | |||
dbErr := dbs.Snapshot(func(transactionCtx context.Context, tx trackerdb.SnapshotScope) (err error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why didn't we rename/remove the err error declaration in the signature of this function (its pretty long)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Taking out named return variables seemed like a whole can of worms that could make this PR get pretty big — I was going for the minimal set to make the linter happy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with the vast majority of the changes. I left a couple of questions/suggestions in places that I disagreed or could spot an alternative.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll try to look at more later, but this looks mergable to me.
Summary
This enables the govet shadow analysis pass, implemented in https://github.com/golang/tools/blob/master/go/analysis/passes/shadow/shadow.go and enabled via golangci-lint.
The shadow linter prevents some cases of shadowed variables being used, which especially impacts the re-use of common variable names like
err
andok
. In this PR I attempted to resolve these issues mostly be just renaming names likeerr
to more specific and unused names likeerr2
orosErr
.In a few other cases I updated
to
if the check-and-return came right away. I also removed a couple of named error return variables or unnecessary declarations of names earlier in a function that were shadowed later.
The shadow linter
strict: false
setting is used which comes with the following explanation:Test Plan
Existing tests should pass — in most cases I did not change the logic at all, but I did make some bigger changes to resolve some of the warnings.