Summary
First-ever audit of the 77th linter, reflectdeepequalusage (pkg/linters/reflect-deepequal-usage/reflect_deepequal_usage.go), added since the last Sergo run. The linter only detects reflect.DeepEqual when called directly as a selector expression (reflect.DeepEqual(a, b)). When the function is aliased to a variable and called indirectly, the call is invisible to the linter, and this gap is already documented, unintentionally, by the linter own test fixture.
Evidence
astutil.PackageCall (pkg/linters/internal/astutil/astutil.go:83-100) requires call.Fun to type-assert directly to *ast.SelectorExpr:
sel, ok := call.Fun.(*ast.SelectorExpr)
if !ok {
return "", "", false
}
When reflect.DeepEqual is assigned to a variable first and invoked through that variable, call.Fun is a plain *ast.Ident, so PackageCall returns ok=false and analyzeCall (reflect_deepequal_usage.go:56-86) returns without reporting.
The linter own positive-case fixture, pkg/linters/reflect-deepequal-usage/testdata/src/a/a.go:31-35, documents this exact scenario and intent, but the // want annotation required to assert a diagnostic is missing:
// testDeepEqualWithAlias should be flagged - using an alias for reflect package
func testDeepEqualWithAlias(a, b interface{}) bool {
r := reflect.DeepEqual // reference to function
return r(a, b)
}
Every other function in this same positive-cases file carries a // want comment and is genuinely flagged; this one is the sole exception, silently encoding the gap as accepted behavior in analysistest.Run rather than catching it as a regression.
Impact
Latent. A grep of reflect.DeepEqual across pkg (excluding _test.go) found no live production site assigning reflect.DeepEqual to a variable before calling it, so there is no current false negative in this repository. The linter is also not yet CI-enforced (pkg/linters/doc_sync_test.go:39 lists it under notYetEnforced, pending case-by-case review of existing reflect.DeepEqual uses), so there is no immediate enforcement risk either. The value here is closing a correctness gap before enforcement is turned on and before the gap is forgotten as working as tested.
Recommendation
Either: (1) extend analyzeCall to also resolve call.Fun through *ast.Ident definitions that resolve to *types.Func for reflect.DeepEqual via pass.TypesInfo Uses/Defs on the aliasing assignment, or (2) if function-value aliasing is intentionally out of scope, remove the should be flagged comment and the dangling non-want fixture entry so the test file accurately documents the linter real scope, matching how other linters document intentional scope limits.
Validation checklist
- Add a case to testdata/src/a/a.go with a real want annotation if aliasing support is implemented, or move the alias case to testdata/src/b/b.go (negative cases) with an updated comment if it is an intentional scope limit
- go test ./pkg/linters/reflect-deepequal-usage/... passes
- No change needed to CI enforcement status, already deferred per doc_sync_test.go
Effort: small, single-file fix or single-file test/comment correction.
Generated by 🤖 Sergo - Serena Go Expert · claude · agent · 249 AIC · ⌖ 5.47 AIC · ⊞ 5.2K · ◷
Summary
First-ever audit of the 77th linter, reflectdeepequalusage (pkg/linters/reflect-deepequal-usage/reflect_deepequal_usage.go), added since the last Sergo run. The linter only detects reflect.DeepEqual when called directly as a selector expression (reflect.DeepEqual(a, b)). When the function is aliased to a variable and called indirectly, the call is invisible to the linter, and this gap is already documented, unintentionally, by the linter own test fixture.
Evidence
astutil.PackageCall (pkg/linters/internal/astutil/astutil.go:83-100) requires call.Fun to type-assert directly to *ast.SelectorExpr:
When reflect.DeepEqual is assigned to a variable first and invoked through that variable, call.Fun is a plain *ast.Ident, so PackageCall returns ok=false and analyzeCall (reflect_deepequal_usage.go:56-86) returns without reporting.
The linter own positive-case fixture, pkg/linters/reflect-deepequal-usage/testdata/src/a/a.go:31-35, documents this exact scenario and intent, but the
// wantannotation required to assert a diagnostic is missing:Every other function in this same positive-cases file carries a
// wantcomment and is genuinely flagged; this one is the sole exception, silently encoding the gap as accepted behavior in analysistest.Run rather than catching it as a regression.Impact
Latent. A grep of reflect.DeepEqual across pkg (excluding _test.go) found no live production site assigning reflect.DeepEqual to a variable before calling it, so there is no current false negative in this repository. The linter is also not yet CI-enforced (pkg/linters/doc_sync_test.go:39 lists it under notYetEnforced, pending case-by-case review of existing reflect.DeepEqual uses), so there is no immediate enforcement risk either. The value here is closing a correctness gap before enforcement is turned on and before the gap is forgotten as working as tested.
Recommendation
Either: (1) extend analyzeCall to also resolve call.Fun through *ast.Ident definitions that resolve to *types.Func for reflect.DeepEqual via pass.TypesInfo Uses/Defs on the aliasing assignment, or (2) if function-value aliasing is intentionally out of scope, remove the should be flagged comment and the dangling non-want fixture entry so the test file accurately documents the linter real scope, matching how other linters document intentional scope limits.
Validation checklist
Effort: small, single-file fix or single-file test/comment correction.