Skip to content

dart: local variable (not just parameter) shadowing a class field still mis-resolves receiver type #2478

Description

@carlos-alm

Background

Follow-up to the Greptile finding on PR #2477 (itself a follow-up to #2319): Dart's receiver extraction (findDartSelectorReceiver in src/extractors/dart.ts, find_dart_selector_receiver + handle_dart_call_expression in crates/codegraph-core/src/extractors/dart.rs) now detects when a bare-identifier receiver is shadowed by a same-named parameter of the enclosing function/method, and skips the this.-prefix normalization that would otherwise incorrectly trigger the resolver's class-scoped field lookup for that receiver.

That fix's scope was deliberately limited to parameters only. Dart also allows a local variable declaration to shadow a class field:

class Service {
  final Repository _repo;   // field, type Repository
  Service(this._repo);

  void run() {
    // ... some code ...
    var _repo = MockRepository();   // LOCAL VARIABLE shadows the field, different type!
    _repo.mockOnlyMethod();         // means the LOCAL here, not the field
  }
}

This case is not handled by the parameter-shadowing fix — the extractor has no way to know a local variable declaration exists between the start of the enclosing block and the call site, so a bare _repo.mockOnlyMethod() after such a local declaration would still be treated as (potentially) a field access and could resolve incorrectly, or not fall through as safely as the parameter case does.

Why this was scoped out

Full lexical-scope-correct local-variable shadowing detection requires tracking declaration order within nested blocks (a local variable declared AFTER the call site in the same block does NOT shadow it there; one declared BEFORE does, for the rest of the enclosing block) — a materially bigger undertaking than the parameter case, which only needs a single formal-parameter-list lookup with no ordering/control-flow reasoning. Per this file's own "conservative, don't guess, document the residual gap" convention (see findDartSelectorReceiver's own doc comment for other deliberately-unhandled cases, e.g. chained-call intermediate receivers, subscript-indexed receivers, explicit this.field.method() chains), this gap is being tracked here rather than silently left unstated.

Scope

  • src/extractors/dart.ts (findDartSelectorReceiver, findEnclosingDartParamListForCall and friends)
  • crates/codegraph-core/src/extractors/dart.rs (find_dart_selector_receiver, handle_dart_call_expression)

Both engines need the fix, mirroring how every other Dart extractor fix on #2319/PR #2477 was applied dual-engine.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions