feat(lint): prohibit var shadowing#172
Conversation
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
📝 WalkthroughWalkthroughThis pull request applies extensive refactoring across 15 files to prevent variable shadowing by converting short variable declarations ( Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 golangci-lint (2.5.0)level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies" Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
cmd/enter/run.go (1)
30-33:⚠️ Potential issue | 🟠 MajorVariable shadowing:
erron line 31 shadows theerrfrom the if-init on line 30.Change the assignment on line 31 from
:=to=to use the outer error variable instead of creating a shadow:Fix
if _, err := os.Stat(nixosMarker); err != nil { - err := fmt.Errorf("%v is not a valid NixOS system", opts.RootLocation) + err = fmt.Errorf("%v is not a valid NixOS system", opts.RootLocation) log.Error(err) return err }cmd/install/install.go (1)
550-552:⚠️ Potential issue | 🟠 MajorFix remaining variable shadowing issues: Lines 550 and 564 redeclare
errinstead of reassigning it.Line 550 declares a new
errvariable that shadows the outererrdeclared at line 540. Line 564 does the same. Use assignment (=) instead of declaration (:=) to reuse the outer variable:Line 550 fix
- if err := installBootloader(s, mountpoint); err != nil { + if err = installBootloader(s, mountpoint); err != nil { return err }Line 564 fix
- err := setRootPassword(s, mountpoint) + err = setRootPassword(s, mountpoint)cmd/activate/user.go (1)
79-83:⚠️ Potential issue | 🟡 Minor
erron line 82 shadows the outererrdeclared on line 42.The
err :=on line 82 creates a new variable that shadows the outererrfrom the function scope. While this doesn't cause a functional issue (the block immediately returns), it should be fixed for code clarity and to satisfy the Go shadowing linter.Proposed fix
if status == "timeout" || status == "failed" || status == "dependency" { - err := fmt.Errorf("restarting nixos-activation.service failed with status %s", status) + err = fmt.Errorf("restarting nixos-activation.service failed with status %s", status) log.Error(err) return err }internal/system/ssh.go (1)
345-353:⚠️ Potential issue | 🔴 CriticalData race: goroutine writes to the shared
errvariable concurrently.Line 348 assigns to the outer
err(fromRunon line 270) inside a goroutine that runs concurrently withsession.Run(fullCmd)on line 355, which also assigns toerr. Previously,:=would have scoped a localerrto the goroutine; now both paths race on the same variable.Proposed fix — use a local variable inside the goroutine
go func() { for sig := range sigCh { if s := osSignalToSSHSignal(sig); s != "" { - if err = session.Signal(s); err != nil { + if sigErr := session.Signal(s); sigErr != nil { - log.Warnf("failed to forward signal '%v': %v", s, err) + log.Warnf("failed to forward signal '%v': %v", s, sigErr) } } } }()cmd/option/option.go (1)
187-195:⚠️ Potential issue | 🟠 MajorUse a local
errvariable in the evaluator closure to prevent data race when called concurrently.The closure captures and mutates the outer
optionMainscope'serrvariable. Since optnix's TUI can invokeEvaluatorFuncfrom multiple goroutines, concurrent writes to the sharederrcreate a data race. The fix is straightforward:Proposed fix
var evaluator option.EvaluatorFunc = func(optionName string) (string, error) { - var value *string - value, err = nixosConfig.EvalAttribute(optionName) + value, err := nixosConfig.EvalAttribute(optionName) realValue := "" if value != nil { realValue = *value } return realValue, err }
🤖 Fix all issues with AI agents
In `@cmd/features/features.go`:
- Around line 45-48: Rename the exported struct CompliationOptions to the
correctly spelled CompilationOptions and update every reference/usage to that
type (including any variable declarations, struct literals, function
parameters/returns and instantiations that use CompliationOptions) so the API
stays consistent; keep the struct fields (NixpkgsVersion, Flake) and their tags
unchanged, and ensure exported references (e.g., any places constructing the
struct or accepting it) are updated to use CompilationOptions.
🧹 Nitpick comments (3)
internal/system/ssh.go (2)
59-66: Variable name collision:currentused for both*user.Userandos.Getenv("USER").Line 59 declares
currentas*user.User, but line 62 usescurrentas astringfromos.Getenv. These are in different scopes (theelse ifstarts a new block), so it compiles, but the shadowing of the variable name within this narrow block is confusing — ironic given the PR's purpose.
102-108: Closure captures outererr— verify this is safe with SSH auth retries.With
:=→=, the password callback now mutatesNewSSHSystem'serr. If the SSH library calls this callback multiple times (e.g., on authentication retry), intermediate errors written to the outererrcould leak into unrelated code paths. In practice,ssh.Dialon line 114 overwriteserr, so this appears safe, but the coupling is fragile.Safer alternative — keep a local err in the closure
passwordCallback := ssh.PasswordCallback(func() (string, error) { - var bytePassword []byte - bytePassword, err = promptForPassword(username, address) + bytePassword, err := promptForPassword(username, address) if err != nil { return "", err }cmd/apply/apply.go (1)
633-643: Assigning to outererrinside defer — safe now, but fragile if named returns are ever introduced.Currently
erris not a named return value, so mutating it in the defer has no effect on the returned error. However, ifapplyMainis ever refactored to use a namederrreturn, this assignment would silently overwrite the original return error on the rollback path. Consider using a locally-scoped variable (e.g.,rollbackErr) to make intent explicit and avoid that future pitfall.Suggested change
- if err = activation.SetNixProfileGeneration( + if rollbackErr := activation.SetNixProfileGeneration( targetHost, opts.ProfileName, previousGenNumber, &activation.SetNixProfileGenerationOptions{ RootCommand: cfg.RootCommand, UseRootCommand: activationUseRoot, }, - ); err != nil { + ); rollbackErr != nil { - log.Errorf("failed to rollback system profile: %v", err) + log.Errorf("failed to rollback system profile: %v", rollbackErr) log.Info("make sure to rollback the system manually before deleting anything!") }
44aef7c to
2d9135d
Compare
2d9135d to
5c79564
Compare
Lax variable shadowing rules have caused bugs in the past, especially in #169 and elsewhere.
This takes a more restrictive approach: variable shadowing is now completely disallowed in most situations. It does make short-hand variable assignments a little harder to write in cases with common variable names like
err, but this is a worthwhile tradeoff IMO.Summary by CodeRabbit
Refactor
Chores