Skip to content

reflectdeepequalusage: function-value alias bypasses detection, gap documented by its own test fixture #66436

Description

@github-actions

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 · ◷

  • expires on Oct 13, 2026, 8:05 PM UTC-08:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    cookieIssue Monster Loves Cookies!sergo

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions