Skip to content

scanner: chained factory-call-then-method (factoryFunc().Method(...)) is not detected #20

Description

@flaglint

Found while writing flaglint.dev documentation for cross-package factory-function resolution (#14/ADR 004): resolveReceiver (internal/scanner/identity.go) only handles a method call's receiver expression when it's an *ast.Ident or *ast.SelectorExpr — never an *ast.CallExpr. So a direct chained call on a factory function's result is not detected, only the assign-then-use form:

// NOT detected — receiver is a CallExpr (flags.Client()), not an Ident/SelectorExpr
flags.Client().BoolVariation("checkout-v2", ctx, false)

// Detected — the call result is first assigned to a variable
client := flags.Client()
client.BoolVariation("checkout-v2", ctx, false)

Confirmed via a minimal repro: identical code, only the call shape differs, and flaglint-go audit finds 0 usages for the chained form and 2 for the assigned form.

This affects factory-function resolution generally (any receiver expression that's itself a call — not just the specific cross-package factory case #14 added), and is idiomatic enough Go style (GetClient().Method()) to be worth fixing rather than leaving as a silent gap: resolveReceiver would need a new case for *ast.CallExpr that recognizes isSDKConstructorCall/isFactoryCall on the inner call and, if it resolves to a bound client version, treats the outer method call as detected directly (no binding-map lookup needed, since the version is known immediately from the inner call itself — no receiver variable to look up in bindings at all in this shape).

Not found during the original field-testing round (all 4 real repos' factory-getter usage happened to go through an intermediate variable) — found only while writing accurate documentation. Filed as a known gap; see docs/adr/004-whole-scan-identity-resolution.md for the surrounding factory-function design.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions