Skip to content

[record_use] Completeness: Consider all possible static calls targets #3062

Closed

Description

@dcharkes

We should ensure our "static call recording" can

  1. capture all the kinds of static calls in the Dart programming language, and
  2. identify the definitions those calls refer to unambiguously.

Statically Resolved Dart Symbols

1. Top-Level Declarations (Library Scope)

These symbols exist directly in a library and are always resolved statically.

  • Top-Level Function (void main() {})
  • Top-Level Getter (int get x => 1;)
  • Top-Level Setter (set x(int v) {})

2. Class Members

These symbols belong to a class definition.

  • Static Method (static void helper())
  • Static Getter (static int get count)
  • Static Setter (static set count(int v))
  • Generative Constructor (Class(), Class.named()) — Invoked statically to create instances.
  • Factory Constructor (factory Class.fromCache()) — Invoked statically like a method.

3. Mixin Members

Mixins can have static members (but not constructors), which are invoked on the mixin name itself.

  • Static Method (MixinName.helper())
  • Static Getter (MixinName.value)
  • Static Setter (MixinName.value = 5)

4. Enum Members

Enums (especially enhanced enums in Dart 2.17+) can contain static members.

  • Static Method (EnumName.parse())
  • Static Getter (EnumName.allValues)
  • Static Setter
  • Generative Constructor (const MyEnum(this.value)) — Invoked statically during enum initialization.
  • Factory Constructor — Permitted in enhanced enums.

5. Extension Members

Extensions introduce two "kinds" of static resolution: members on the extension namespace, and members that "extend" instances.

  • Extension Static Method (ExtensionName.staticHelper())
  • Extension Static Getter
  • Extension Static Setter
  • Extension Instance Method — Syntactically looks like obj.method(), but compiles to Extension.method(obj).
  • Extension Instance Getter
  • Extension Instance Setter
  • Extension Operator

6. Extension Type Members (Dart 3.3+)

All members of an extension type are resolved statically because the type is erased at runtime.

  • Constructor (ExtensionType.new(value))
  • Static Method
  • Static Getter
  • Static Setter
  • Instance Method — Resolved against the static type ExtensionType.
  • Instance Getter
  • Instance Setter
  • Operator

7. Super Invocations

Calls using the super keyword are statically resolved to a specific member in the superclass chain, bypassing dynamic dispatch.

  • Super Method (super.toString())
  • Super Getter
  • Super Setter
  • Super Operator (super + 5)

Observations

I don't think we're interested in super calls, as they are not "externally addressable": e.g. package:my_package/src/foo.dart#Bar::baz.

Constructor invocations should not be captured, because they should be covered by the "record instance creation" feature which also covers const instances.

Getters and setters need special care, because otherwise package:my_package/src/foo.dart#Bar::baz is ambiguous. Either we stick to what the Dart compiler does internally package:my_package/src/foo.dart#Bar::get:baz Or we need a Kind for everything package:my_package/src/foo.dart#Bar::method:baz.

(We don't need a Kind for the "container", classes, enums, mixins, extensions, and extension types live in the same namespace. So no need for package:my_package/src/foo.dart#class:Bar::method:baz. However, we might want it for consistency if we go with a Kind for method:.)

If we prefer using valid url schemes, we also cannot use the operator literal syntax. So then we should for operators use package:my_package/src/foo.dart#operator:plus.

Activity

  1. self-assigned this
    on Feb 9, 2026
  2. moved this to In Progress in Native Assetson Feb 9, 2026
  3. dcharkes commented on Feb 11, 2026

    @dcharkes
    CollaboratorAuthor

    One approach to be able to encode all. regular, reads from left to right, complete, verbose, and no typing based on kinds.

    Definition(
      'package:my_package/file.dart',
      [
        Name(
          kind: DefinitionKind.classKind,
          'SomeClass',
        ),
        Name(
          kind: DefinitionKind.methodKind,
          'someStaticMethod',
          disambiguators: {.instanceDisambiguator}),
      ],
    ),

    Another approach. Typed per kind. Disambiguation can be typed as well. But you have to write them inside out:

    Getter(
      parent: Class(
         Library(
          'package:my_package/file.dart',
         ),
         'Foo'
       ),
      'myMethod',
      instance: true, // optional
    );
    
    Getter(
      parent: Library(
        'package:my_package/file.dart',
      ),
      'myMethod',
      instance: true, // optional
    );

    Any other bright ideas: @goderbauer @mosuem @liamappelbe

  4. dcharkes commented on Feb 11, 2026

    @dcharkes
    CollaboratorAuthor

    N.b. We might want to generate these definitions:

  5. biggs0125 commented on Feb 11, 2026

    @biggs0125

    One benefit of the latter is it's easier to do something like (in a type-safe way at least):

    final myLibrary = Library('package:...');
    final myClass = Class(myLibrary, 'Foo');
    Getter(parent: myClass, 'bar', instance: true);
    Getter(parent: myLibrary, 'baz');
    

    I might even canonicalize these forms with named constructors/factories:

    Getter.static(Class cls, String name);
    Getter.instance(Class cls, String name);
    Getter.topLevel(Library lib, String name);
    
  6. goderbauer commented on Feb 12, 2026

    @goderbauer
    Contributor

    For the final API I am also leaning more towards the second option. I think it gives developers more guidance and it reads easier. The first option gives the boilerplate (Definition, Name) a lot of prominence. The second option puts more useful information there.

  7. dcharkes commented on Feb 12, 2026

    @dcharkes
    CollaboratorAuthor

    Notes from discussion with @goderbauer:

    • We'll focus on landing a correct JSON structure and updating the compilers to emit the right kinds and disambiguators first
    • Then we'll revisit public API and probably go with something akin to the second design.
  8. dcharkes commented on Mar 3, 2026

    @dcharkes
    CollaboratorAuthor

    2026-03-03 Gemini CLI generated coverage report:

    Symbol Category Symbol Type Covered? Test File(s) Notes
    1. Top-Level Function ✅ top_level_method.dart
    Getter ✅ static_getters_setters.dart
    Setter ✅ static_getters_setters.dart
    2. Class Members Static Method ✅ basic.dart
    Static Getter ✅ static_getters_setters.dart
    Static Setter ✅ static_getters_setters.dart
    Generative Constructor ✅ non_const_constructor.dart Handled by InstanceRecorder.
    Factory Constructor ✅ factory_constructor.dart Handled by InstanceRecorder.
    3. Mixin Members Static Method ❌ BUG: CallRecorder missing Mixin parent in path.
    Static Getter ❌
    Static Setter ❌
    4. Enum Members Static Method ⚠️ enhanced_enum.dart BUG: Recorded with kind: class instead of kind: enum.
    Static Getter ❌
    Static Setter ❌
    Generative Constructor ✅ enhanced_enum.dart Handled by InstanceRecorder.
    Factory Constructor ❌
    5. Extension Members Static Method ✅ extension_static_call.dart
    Static Getter ❌
    Static Setter ❌
    Instance Method ✅ extension.dart
    Instance Getter ❌
    Instance Setter ❌
    Operator ✅ extension_operator.dart Uses literal names (e.g., +).
    6. Extension Type Constructor ✅ extension_type_call_const_receiver.dart Handled by InstanceRecorder.
    Static Method ✅ extension_type_static_method.dart
    Static Getter ❌
    Static Setter ❌
    Instance Method ✅ extension_type_call_non_const_receiver.dart
    Instance Getter ❌
    Instance Setter ❌
    Operator ✅ extension_type_operator.dart
    7. Super Invocations All ❌ Not "externally addressable" per user observation.
  9. moved this from In Progress to Done in Native Assetson Mar 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

Relationships

None yet

Development

No branches or pull requests

Issue actions