Fine. Record InstanceElement.getMethod(), getter, setter invocations.

Change-Id: Ieaf1e37a204b8e475e9ecd1c9ef9bb60dcca5149
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/426441
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Paul Berry <paulberry@google.com>
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 9b12d2a..127d162 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -101,7 +101,7 @@
 // TODO(scheglov): Clean up the list of implicitly analyzed files.
 class AnalysisDriver {
   /// The version of data format, should be incremented on every format change.
-  static const int DATA_VERSION = 456;
+  static const int DATA_VERSION = 457;
 
   /// The number of exception contexts allowed to write. Once this field is
   /// zero, we stop writing any new exception contexts in this process.
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 89c5b69..71a9fd4 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -4481,16 +4481,31 @@
 
   @override
   GetterElementImpl? getGetter2(String name) {
+    globalResultRequirements?.record_instanceElement_getGetter(
+      element: this,
+      name: name,
+    );
+
     return getters2.firstWhereOrNull((e) => e.name3 == name);
   }
 
   @override
   MethodElementImpl2? getMethod2(String name) {
+    globalResultRequirements?.record_instanceElement_getMethod(
+      element: this,
+      name: name,
+    );
+
     return methods2.firstWhereOrNull((e) => e.lookupName == name);
   }
 
   @override
   SetterElementImpl? getSetter2(String name) {
+    globalResultRequirements?.record_instanceElement_getSetter(
+      element: this,
+      name: name,
+    );
+
     return setters2.firstWhereOrNull((e) => e.name3 == name);
   }
 
diff --git a/pkg/analyzer/lib/src/fine/requirements.dart b/pkg/analyzer/lib/src/fine/requirements.dart
index e257280..c5fc721 100644
--- a/pkg/analyzer/lib/src/fine/requirements.dart
+++ b/pkg/analyzer/lib/src/fine/requirements.dart
@@ -185,22 +185,51 @@
   }
 }
 
+/// Requirements for [InstanceElementImpl2].
+///
+/// If [InterfaceElementImpl2], there are additional requirements in form
+/// of [InterfaceItemRequirements].
+class InstanceItemRequirements {
+  /// These are "methods" in wide meaning: methods, getters, setters.
+  final Map<LookupName, ManifestItemId?> requestedMethods;
+
+  InstanceItemRequirements({required this.requestedMethods});
+
+  factory InstanceItemRequirements.empty() {
+    return InstanceItemRequirements(requestedMethods: {});
+  }
+
+  factory InstanceItemRequirements.read(SummaryDataReader reader) {
+    return InstanceItemRequirements(requestedMethods: reader.readNameToIdMap());
+  }
+
+  void write(BufferedSink sink) {
+    sink.writeNameToIdMap(requestedMethods);
+  }
+}
+
+/// Requirements for [InterfaceElementImpl2], in addition to those that
+/// we already record as [InstanceItemRequirements].
+///
 /// Includes all requirements from class-like items: classes, enums,
-/// extensions (NB), extension types, mixins.
-class InterfaceRequirements {
+/// extension types, mixins.
+class InterfaceItemRequirements {
   final Map<LookupName, ManifestItemId?> constructors;
 
   /// These are "methods" in wide meaning: methods, getters, setters.
   final Map<LookupName, ManifestItemId?> methods;
 
-  InterfaceRequirements({required this.constructors, required this.methods});
+  InterfaceItemRequirements({
+    required this.constructors,
+    required this.methods,
+  });
 
-  factory InterfaceRequirements.empty() {
-    return InterfaceRequirements(constructors: {}, methods: {});
+  factory InterfaceItemRequirements.empty() {
+    return InterfaceItemRequirements(constructors: {}, methods: {});
   }
 
-  factory InterfaceRequirements.read(SummaryDataReader reader) {
-    return InterfaceRequirements(
+  factory InterfaceItemRequirements.read(SummaryDataReader reader) {
+    return InterfaceItemRequirements(
       constructors: reader.readNameToIdMap(),
       methods: reader.readNameToIdMap(),
     );
@@ -216,10 +245,11 @@
   /// LibraryUri => TopName => ID
   final Map<Uri, Map<LookupName, ManifestItemId?>> topLevels = {};
 
-  /// LibraryUri => TopName => InterfaceRequirements
-  ///
-  /// These are "methods" in wide meaning: methods, getters, setters.
-  final Map<Uri, Map<LookupName, InterfaceRequirements>> interfaces = {};
+  /// LibraryUri => TopName => InstanceItemRequirements
+  final Map<Uri, Map<LookupName, InstanceItemRequirements>> instances = {};
+
+  /// LibraryUri => TopName => InterfaceItemRequirements
+  final Map<Uri, Map<LookupName, InterfaceItemRequirements>> interfaces = {};
 
   final List<ExportRequirement> exportRequirements = [];
 
@@ -235,13 +265,25 @@
       ),
     );
 
+    result.instances.addAll(
+      reader.readMap(
+        readKey: () => reader.readUri(),
+        readValue: () {
+          return reader.readMap(
+            readKey: () => LookupName.read(reader),
+            readValue: () => InstanceItemRequirements.read(reader),
+          );
+        },
+      ),
+    );
+
     result.interfaces.addAll(
       reader.readMap(
         readKey: () => reader.readUri(),
         readValue: () {
           return reader.readMap(
             readKey: () => LookupName.read(reader),
-            readValue: () => InterfaceRequirements.read(reader),
+            readValue: () => InterfaceItemRequirements.read(reader),
           );
         },
       ),
@@ -296,6 +338,43 @@
       }
     }
 
+    for (var libraryEntry in instances.entries) {
+      var libraryUri = libraryEntry.key;
+
+      var libraryElement = elementFactory.libraryOfUri(libraryUri);
+      var libraryManifest = libraryElement?.manifest;
+      if (libraryManifest == null) {
+        return LibraryMissing(uri: libraryUri);
+      }
+
+      for (var instanceEntry in libraryEntry.value.entries) {
+        var instanceName = instanceEntry.key;
+        var instanceItem = libraryManifest.items[instanceName];
+        if (instanceItem is! InstanceItem) {
+          return TopLevelNotInterface(
+            libraryUri: libraryUri,
+            name: instanceName,
+          );
+        }
+
+        var methods = instanceEntry.value.requestedMethods;
+        for (var methodEntry in methods.entries) {
+          var methodName = methodEntry.key;
+          var methodId = instanceItem.getDeclaredMemberId(methodName);
+          var expectedId = methodEntry.value;
+          if (expectedId != methodId) {
+            return InstanceMethodIdMismatch(
+              libraryUri: libraryUri,
+              interfaceName: instanceName,
+              methodName: methodName,
+              expectedId: expectedId,
+              actualId: methodId,
+            );
+          }
+        }
+      }
+    }
+
     for (var libraryEntry in interfaces.entries) {
       var libraryUri = libraryEntry.key;
 
@@ -365,15 +444,17 @@
     required InterfaceElementImpl2 element,
     required String name,
   }) {
-    var interfacePair = _getInterface(element);
-    if (interfacePair == null) {
+    var itemRequirements = _getInterfaceItem(element);
+    if (itemRequirements == null) {
       return;
     }
 
-    var (interfaceItem, interface) = interfacePair;
+    var item = itemRequirements.item;
+    var requirements = itemRequirements.requirements;
+
     var constructorName = name.asLookupName;
-    var constructorId = interfaceItem.getConstructorId(constructorName);
-    interface.constructors[constructorName] = constructorId;
+    var constructorId = item.getConstructorId(constructorName);
+    requirements.constructors[constructorName] = constructorId;
   }
 
   /// This method is invoked by [InheritanceManager3] to notify the collector
@@ -388,14 +469,17 @@
       return;
     }
 
-    var interfacePair = _getInterface(element);
-    if (interfacePair == null) {
+    var itemRequirements = _getInterfaceItem(element);
+    if (itemRequirements == null) {
       return;
     }
 
-    var (interfaceItem, interface) = interfacePair;
+    var item = itemRequirements.item;
+    var requirements = itemRequirements.requirements;
+
     var methodName = nameObj.name.asLookupName;
-    var methodId = interfaceItem.getInterfaceMethodId(methodName);
+    var methodId = item.getInterfaceMethodId(methodName);
+    requirements.methods[methodName] = methodId;
 
     // Check for consistency between the actual interface and manifest.
     if (methodElement != null) {
@@ -410,7 +494,7 @@
       }
     }
 
-    interface.methods[methodName] = methodId;
+    requirements.methods[methodName] = methodId;
   }
 
   /// This method is invoked by an import scope to notify the collector that
@@ -427,6 +511,37 @@
     }
   }
 
+  void record_instanceElement_getGetter({
+    required InstanceElementImpl2 element,
+    required String name,
+  }) {
+    record_instanceElement_getMethod(element: element, name: name);
+  }
+
+  void record_instanceElement_getMethod({
+    required InstanceElementImpl2 element,
+    required String name,
+  }) {
+    var itemRequirements = _getInstanceItem(element);
+    if (itemRequirements == null) {
+      return;
+    }
+
+    var item = itemRequirements.item;
+    var requirements = itemRequirements.requirements;
+
+    var methodName = name.asLookupName;
+    var methodId = item.getDeclaredMemberId(methodName);
+    requirements.requestedMethods[methodName] = methodId;
+  }
+
+  void record_instanceElement_getSetter({
+    required InstanceElementImpl2 element,
+    required String name,
+  }) {
+    record_instanceElement_getMethod(element: element, name: '$name=');
+  }
+
   /// This method is invoked after linking of a library cycle, to exclude
   /// requirements to the libraries of this same library cycle. We already
   /// link these libraries together, so only requirements to the previous
@@ -454,6 +569,18 @@
     );
 
     sink.writeMap(
+      instances,
+      writeKey: (uri) => sink.writeUri(uri),
+      writeValue: (nameToInstanceMap) {
+        sink.writeMap(
+          nameToInstanceMap,
+          writeKey: (name) => name.write(sink),
+          writeValue: (instance) => instance.write(sink),
+        );
+      },
+    );
+
+    sink.writeMap(
       interfaces,
       writeKey: (uri) => sink.writeUri(uri),
       writeValue: (nameToInterfaceMap) {
@@ -523,7 +650,36 @@
     }
   }
 
-  (InterfaceItem, InterfaceRequirements)? _getInterface(
+  _InstanceItemWithRequirements? _getInstanceItem(
+    InstanceElementImpl2 element,
+  ) {
+    var libraryElement = element.library2;
+    var manifest = libraryElement.manifest;
+
+    // If we are linking the library, its manifest is not set yet.
+    // But then we also don't care about this dependency.
+    if (manifest == null) {
+      return null;
+    }
+
+    // SAFETY: we don't export elements without name.
+    var instanceName = element.lookupName!.asLookupName;
+
+    var instancesMap = instances[libraryElement.uri] ??= {};
+    var instanceItem = manifest.items[instanceName];
+
+    // SAFETY: every instance element must be in the manifest.
+    instanceItem as InstanceItem;
+
+    var requirements =
+        instancesMap[instanceName] ??= InstanceItemRequirements.empty();
+    return _InstanceItemWithRequirements(
+      item: instanceItem,
+      requirements: requirements,
+    );
+  }
+
+  _InterfaceItemWithRequirements? _getInterfaceItem(
     InterfaceElementImpl2 element,
   ) {
     var libraryElement = element.library2;
@@ -544,16 +700,19 @@
     // SAFETY: every interface element must be in the manifest.
     interfaceItem as InterfaceItem;
 
-    var interfaceRequirements =
-        interfacesMap[interfaceName] ??= InterfaceRequirements.empty();
-    return (interfaceItem, interfaceRequirements);
+    var requirements =
+        interfacesMap[interfaceName] ??= InterfaceItemRequirements.empty();
+    return _InterfaceItemWithRequirements(
+      item: interfaceItem,
+      requirements: requirements,
+    );
   }
 
   String _qualifiedMethodName(
     InterfaceElementImpl2 element,
     LookupName methodName,
   ) {
-    return '${element.library2.uri}'
+    return '${element.library2.uri} '
         '${element.displayName}.'
         '${methodName.asString}';
   }
@@ -561,6 +720,26 @@
 
 enum _ExportRequirementCombinatorKind { hide, show }
 
+class _InstanceItemWithRequirements {
+  final InstanceItem item;
+  final InstanceItemRequirements requirements;
+
+  _InstanceItemWithRequirements({
+    required this.item,
+    required this.requirements,
+  });
+}
+
+class _InterfaceItemWithRequirements {
+  final InterfaceItem item;
+  final InterfaceItemRequirements requirements;
+
+  _InterfaceItemWithRequirements({
+    required this.item,
+    required this.requirements,
+  });
+}
+
 extension _BufferedSinkExtension on BufferedSink {
   void writeNameToIdMap(Map<LookupName, ManifestItemId?> map) {
     writeMap(
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index 2a60f3b..a86759d 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -5,7 +5,6 @@
 import 'dart:async';
 
 import 'package:analyzer/dart/analysis/results.dart';
-import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/error/error.dart';
@@ -15,6 +14,7 @@
 import 'package:analyzer/src/dart/analysis/driver_event.dart' as driver_events;
 import 'package:analyzer/src/dart/analysis/file_state.dart';
 import 'package:analyzer/src/dart/analysis/status.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/fine/requirements.dart';
 import 'package:analyzer/src/lint/linter.dart';
@@ -6255,6 +6255,11 @@
         A: <null>
       package:test/a.dart
         A: #M0
+    instances
+      package:test/a.dart
+        A
+          requestedMethods
+            c2: <null>
     interfaces
       package:test/a.dart
         A
@@ -6501,6 +6506,11 @@
         A: <null>
       package:test/a.dart
         A: #M0
+    instances
+      package:test/a.dart
+        A
+          requestedMethods
+            c2: <null>
     interfaces
       package:test/a.dart
         A
@@ -6576,6 +6586,11 @@
       package:test/a.dart
         A: #M0
         named: <null>
+    instances
+      package:test/test.dart
+        B
+          requestedMethods
+            noSuchMethod: <null>
     interfaces
       package:test/a.dart
         A
@@ -6651,6 +6666,11 @@
       package:test/a.dart
         A: #M0
         named: <null>
+    instances
+      package:test/test.dart
+        B
+          requestedMethods
+            noSuchMethod: <null>
     interfaces
       package:test/a.dart
         A
@@ -7253,6 +7273,14 @@
     topLevels
       dart:core
         int: #M4
+    instances
+      package:test/test.dart
+        A
+          requestedMethods
+            noSuchMethod: <null>
+        B
+          requestedMethods
+            noSuchMethod: <null>
 [status] idle
 ''',
       updateFiles: () {
@@ -7299,6 +7327,14 @@
     topLevels
       dart:core
         String: #M6
+    instances
+      package:test/test.dart
+        A
+          requestedMethods
+            noSuchMethod: <null>
+        B
+          requestedMethods
+            noSuchMethod: <null>
 [status] idle
 ''',
     );
@@ -8182,6 +8218,11 @@
         A: <null>
       package:test/a.dart
         A: #M0
+    instances
+      package:test/a.dart
+        A
+          requestedMethods
+            foo: <null>
     interfaces
       package:test/a.dart
         A
@@ -8883,6 +8924,14 @@
     topLevels
       dart:core
         int: #M4
+    instances
+      package:test/test.dart
+        A
+          requestedMethods
+            noSuchMethod: <null>
+        B
+          requestedMethods
+            noSuchMethod: <null>
 [status] idle
 ''',
       updateFiles: () {
@@ -8929,6 +8978,14 @@
     topLevels
       dart:core
         String: #M6
+    instances
+      package:test/test.dart
+        A
+          requestedMethods
+            noSuchMethod: <null>
+        B
+          requestedMethods
+            noSuchMethod: <null>
 [status] idle
 ''',
     );
@@ -8986,6 +9043,14 @@
     topLevels
       dart:core
         int: #M4
+    instances
+      package:test/test.dart
+        A
+          requestedMethods
+            noSuchMethod: <null>
+        B
+          requestedMethods
+            noSuchMethod: <null>
 [status] idle
 ''',
       updateFiles: () {
@@ -9030,6 +9095,14 @@
     topLevels
       dart:core
         double: #M6
+    instances
+      package:test/test.dart
+        A
+          requestedMethods
+            noSuchMethod: <null>
+        B
+          requestedMethods
+            noSuchMethod: <null>
 [status] idle
 ''',
     );
@@ -9098,6 +9171,11 @@
         B: <null>
       package:test/a.dart
         B: #M0
+    instances
+      package:test/test.dart
+        A
+          requestedMethods
+            noSuchMethod: <null>
 [status] idle
 ''',
       updateFiles: () {
@@ -9150,6 +9228,16 @@
         B: <null>
       package:test/a.dart
         B: #M0
+    instances
+      package:test/a.dart
+        B
+          requestedMethods
+            _foo: <null>
+      package:test/test.dart
+        A
+          requestedMethods
+            _foo: <null>
+            noSuchMethod: <null>
 [status] idle
 ''',
     );
@@ -9253,6 +9341,11 @@
         A: <null>
       package:test/a.dart
         A: #M0
+    instances
+      package:test/a.dart
+        A
+          requestedMethods
+            foo: <null>
     interfaces
       package:test/a.dart
         A
@@ -9557,6 +9650,12 @@
         A: <null>
       package:test/a.dart
         A: #M0
+    instances
+      package:test/a.dart
+        A
+          requestedMethods
+            foo: <null>
+            foo=: <null>
     interfaces
       package:test/a.dart
         A
@@ -10107,6 +10206,14 @@
     topLevels
       dart:core
         int: #M4
+    instances
+      package:test/test.dart
+        A
+          requestedMethods
+            noSuchMethod: <null>
+        B
+          requestedMethods
+            noSuchMethod: <null>
 [status] idle
 ''',
       updateFiles: () {
@@ -10153,6 +10260,14 @@
     topLevels
       dart:core
         String: #M6
+    instances
+      package:test/test.dart
+        A
+          requestedMethods
+            noSuchMethod: <null>
+        B
+          requestedMethods
+            noSuchMethod: <null>
 [status] idle
 ''',
     );
@@ -10270,6 +10385,12 @@
         A: <null>
       package:test/a.dart
         A: #M0
+    instances
+      package:test/a.dart
+        A
+          requestedMethods
+            foo: <null>
+            foo=: <null>
     interfaces
       package:test/a.dart
         A
@@ -10409,6 +10530,678 @@
     );
   }
 
+  test_dependency_class_static_getter() async {
+    await _runChangeScenarioTA(
+      initialA: r'''
+class A {
+  static int get foo {}
+}
+''',
+      testCode: r'''
+import 'a.dart';
+void f() {
+  A.foo;
+}
+''',
+      operation: _FineOperationTestFileGetErrors(),
+      expectedInitialEvents: r'''
+[status] working
+[operation] linkLibraryCycle SDK
+[future] getErrors T1
+  ErrorsResult #0
+    path: /home/test/lib/test.dart
+    uri: package:test/test.dart
+    flags: isLibrary
+[operation] linkLibraryCycle
+  package:test/a.dart
+    manifest
+      A: #M0
+        declaredMembers
+          foo.getter: #M1
+  requirements
+    topLevels
+      dart:core
+        int: #M2
+[operation] linkLibraryCycle
+  package:test/test.dart
+    manifest
+      f: #M3
+  requirements
+[operation] analyzeFile
+  file: /home/test/lib/test.dart
+  library: /home/test/lib/test.dart
+[stream]
+  ResolvedUnitResult #1
+    path: /home/test/lib/test.dart
+    uri: package:test/test.dart
+    flags: exists isLibrary
+[operation] analyzedLibrary
+  file: /home/test/lib/test.dart
+  requirements
+    topLevels
+      dart:core
+        A: <null>
+      package:test/a.dart
+        A: #M0
+    instances
+      package:test/a.dart
+        A
+          requestedMethods
+            foo: #M1
+    interfaces
+      package:test/a.dart
+        A
+          constructors
+            foo: <null>
+[status] idle
+''',
+      updatedA: r'''
+class A {
+  static double get foo {}
+}
+''',
+      expectedUpdatedEvents: r'''
+[status] working
+[operation] linkLibraryCycle
+  package:test/a.dart
+    manifest
+      A: #M0
+        declaredMembers
+          foo.getter: #M4
+  requirements
+    topLevels
+      dart:core
+        double: #M5
+[future] getErrors T2
+  ErrorsResult #2
+    path: /home/test/lib/test.dart
+    uri: package:test/test.dart
+    flags: isLibrary
+[operation] readLibraryCycleBundle
+  package:test/test.dart
+[operation] getErrorsCannotReuse
+  instanceMethodIdMismatch
+    libraryUri: package:test/a.dart
+    interfaceName: A
+    methodName: foo
+    expectedId: #M1
+    actualId: #M4
+[operation] analyzeFile
+  file: /home/test/lib/test.dart
+  library: /home/test/lib/test.dart
+[stream]
+  ResolvedUnitResult #3
+    path: /home/test/lib/test.dart
+    uri: package:test/test.dart
+    flags: exists isLibrary
+[operation] analyzedLibrary
+  file: /home/test/lib/test.dart
+  requirements
+    topLevels
+      dart:core
+        A: <null>
+      package:test/a.dart
+        A: #M0
+    instances
+      package:test/a.dart
+        A
+          requestedMethods
+            foo: #M4
+    interfaces
+      package:test/a.dart
+        A
+          constructors
+            foo: <null>
+[status] idle
+''',
+    );
+  }
+
+  test_dependency_class_static_getter_notUsed() async {
+    await _runChangeScenarioTA(
+      initialA: r'''
+class A {
+  static int get foo {}
+  static int get bar {}
+}
+''',
+      testCode: r'''
+import 'a.dart';
+void f() {
+  A.foo;
+}
+''',
+      operation: _FineOperationTestFileGetErrors(),
+      expectedInitialEvents: r'''
+[status] working
+[operation] linkLibraryCycle SDK
+[future] getErrors T1
+  ErrorsResult #0
+    path: /home/test/lib/test.dart
+    uri: package:test/test.dart
+    flags: isLibrary
+[operation] linkLibraryCycle
+  package:test/a.dart
+    manifest
+      A: #M0
+        declaredMembers
+          bar.getter: #M1
+          foo.getter: #M2
+  requirements
+    topLevels
+      dart:core
+        int: #M3
+[operation] linkLibraryCycle
+  package:test/test.dart
+    manifest
+      f: #M4
+  requirements
+[operation] analyzeFile
+  file: /home/test/lib/test.dart
+  library: /home/test/lib/test.dart
+[stream]
+  ResolvedUnitResult #1
+    path: /home/test/lib/test.dart
+    uri: package:test/test.dart
+    flags: exists isLibrary
+[operation] analyzedLibrary
+  file: /home/test/lib/test.dart
+  requirements
+    topLevels
+      dart:core
+        A: <null>
+      package:test/a.dart
+        A: #M0
+    instances
+      package:test/a.dart
+        A
+          requestedMethods
+            foo: #M2
+    interfaces
+      package:test/a.dart
+        A
+          constructors
+            foo: <null>
+[status] idle
+''',
+      updatedA: r'''
+class A {
+  static int get foo {}
+  static double get bar {}
+}
+''',
+      expectedUpdatedEvents: r'''
+[status] working
+[operation] linkLibraryCycle
+  package:test/a.dart
+    manifest
+      A: #M0
+        declaredMembers
+          bar.getter: #M5
+          foo.getter: #M2
+  requirements
+    topLevels
+      dart:core
+        double: #M6
+        int: #M3
+[future] getErrors T2
+  ErrorsResult #2
+    path: /home/test/lib/test.dart
+    uri: package:test/test.dart
+    flags: isLibrary
+[operation] readLibraryCycleBundle
+  package:test/test.dart
+[operation] getErrorsFromBytes
+  file: /home/test/lib/test.dart
+  library: /home/test/lib/test.dart
+[status] idle
+''',
+    );
+  }
+
+  test_dependency_class_static_method() async {
+    await _runChangeScenarioTA(
+      initialA: r'''
+class A {
+  static int foo() {}
+}
+''',
+      testCode: r'''
+import 'a.dart';
+void f() {
+  A.foo();
+}
+''',
+      operation: _FineOperationTestFileGetErrors(),
+      expectedInitialEvents: r'''
+[status] working
+[operation] linkLibraryCycle SDK
+[future] getErrors T1
+  ErrorsResult #0
+    path: /home/test/lib/test.dart
+    uri: package:test/test.dart
+    flags: isLibrary
+[operation] linkLibraryCycle
+  package:test/a.dart
+    manifest
+      A: #M0
+        declaredMembers
+          foo.method: #M1
+  requirements
+    topLevels
+      dart:core
+        int: #M2
+[operation] linkLibraryCycle
+  package:test/test.dart
+    manifest
+      f: #M3
+  requirements
+[operation] analyzeFile
+  file: /home/test/lib/test.dart
+  library: /home/test/lib/test.dart
+[stream]
+  ResolvedUnitResult #1
+    path: /home/test/lib/test.dart
+    uri: package:test/test.dart
+    flags: exists isLibrary
+[operation] analyzedLibrary
+  file: /home/test/lib/test.dart
+  requirements
+    topLevels
+      dart:core
+        A: <null>
+      package:test/a.dart
+        A: #M0
+    instances
+      package:test/a.dart
+        A
+          requestedMethods
+            foo: #M1
+    interfaces
+      package:test/a.dart
+        A
+          constructors
+            foo: <null>
+[status] idle
+''',
+      updatedA: r'''
+class A {
+  static double foo() {}
+}
+''',
+      expectedUpdatedEvents: r'''
+[status] working
+[operation] linkLibraryCycle
+  package:test/a.dart
+    manifest
+      A: #M0
+        declaredMembers
+          foo.method: #M4
+  requirements
+    topLevels
+      dart:core
+        double: #M5
+[future] getErrors T2
+  ErrorsResult #2
+    path: /home/test/lib/test.dart
+    uri: package:test/test.dart
+    flags: isLibrary
+[operation] readLibraryCycleBundle
+  package:test/test.dart
+[operation] getErrorsCannotReuse
+  instanceMethodIdMismatch
+    libraryUri: package:test/a.dart
+    interfaceName: A
+    methodName: foo
+    expectedId: #M1
+    actualId: #M4
+[operation] analyzeFile
+  file: /home/test/lib/test.dart
+  library: /home/test/lib/test.dart
+[stream]
+  ResolvedUnitResult #3
+    path: /home/test/lib/test.dart
+    uri: package:test/test.dart
+    flags: exists isLibrary
+[operation] analyzedLibrary
+  file: /home/test/lib/test.dart
+  requirements
+    topLevels
+      dart:core
+        A: <null>
+      package:test/a.dart
+        A: #M0
+    instances
+      package:test/a.dart
+        A
+          requestedMethods
+            foo: #M4
+    interfaces
+      package:test/a.dart
+        A
+          constructors
+            foo: <null>
+[status] idle
+''',
+    );
+  }
+
+  test_dependency_class_static_method_notUsed() async {
+    await _runChangeScenarioTA(
+      initialA: r'''
+class A {
+  static int foo() {}
+  static int bar() {}
+}
+''',
+      testCode: r'''
+import 'a.dart';
+void f() {
+  A.foo();
+}
+''',
+      operation: _FineOperationTestFileGetErrors(),
+      expectedInitialEvents: r'''
+[status] working
+[operation] linkLibraryCycle SDK
+[future] getErrors T1
+  ErrorsResult #0
+    path: /home/test/lib/test.dart
+    uri: package:test/test.dart
+    flags: isLibrary
+[operation] linkLibraryCycle
+  package:test/a.dart
+    manifest
+      A: #M0
+        declaredMembers
+          bar.method: #M1
+          foo.method: #M2
+  requirements
+    topLevels
+      dart:core
+        int: #M3
+[operation] linkLibraryCycle
+  package:test/test.dart
+    manifest
+      f: #M4
+  requirements
+[operation] analyzeFile
+  file: /home/test/lib/test.dart
+  library: /home/test/lib/test.dart
+[stream]
+  ResolvedUnitResult #1
+    path: /home/test/lib/test.dart
+    uri: package:test/test.dart
+    flags: exists isLibrary
+[operation] analyzedLibrary
+  file: /home/test/lib/test.dart
+  requirements
+    topLevels
+      dart:core
+        A: <null>
+      package:test/a.dart
+        A: #M0
+    instances
+      package:test/a.dart
+        A
+          requestedMethods
+            foo: #M2
+    interfaces
+      package:test/a.dart
+        A
+          constructors
+            foo: <null>
+[status] idle
+''',
+      updatedA: r'''
+class A {
+  static int foo() {}
+  static double bar() {}
+}
+''',
+      expectedUpdatedEvents: r'''
+[status] working
+[operation] linkLibraryCycle
+  package:test/a.dart
+    manifest
+      A: #M0
+        declaredMembers
+          bar.method: #M5
+          foo.method: #M2
+  requirements
+    topLevels
+      dart:core
+        double: #M6
+        int: #M3
+[future] getErrors T2
+  ErrorsResult #2
+    path: /home/test/lib/test.dart
+    uri: package:test/test.dart
+    flags: isLibrary
+[operation] readLibraryCycleBundle
+  package:test/test.dart
+[operation] getErrorsFromBytes
+  file: /home/test/lib/test.dart
+  library: /home/test/lib/test.dart
+[status] idle
+''',
+    );
+  }
+
+  test_dependency_class_static_setter() async {
+    await _runChangeScenarioTA(
+      initialA: r'''
+class A {
+  static set foo(int _) {}
+}
+''',
+      testCode: r'''
+import 'a.dart';
+void f() {
+  A.foo = 0;
+}
+''',
+      operation: _FineOperationTestFileGetErrors(),
+      expectedInitialEvents: r'''
+[status] working
+[operation] linkLibraryCycle SDK
+[future] getErrors T1
+  ErrorsResult #0
+    path: /home/test/lib/test.dart
+    uri: package:test/test.dart
+    flags: isLibrary
+[operation] linkLibraryCycle
+  package:test/a.dart
+    manifest
+      A: #M0
+        declaredMembers
+          foo.setter: #M1
+  requirements
+    topLevels
+      dart:core
+        int: #M2
+[operation] linkLibraryCycle
+  package:test/test.dart
+    manifest
+      f: #M3
+  requirements
+[operation] analyzeFile
+  file: /home/test/lib/test.dart
+  library: /home/test/lib/test.dart
+[stream]
+  ResolvedUnitResult #1
+    path: /home/test/lib/test.dart
+    uri: package:test/test.dart
+    flags: exists isLibrary
+[operation] analyzedLibrary
+  file: /home/test/lib/test.dart
+  requirements
+    topLevels
+      dart:core
+        A: <null>
+      package:test/a.dart
+        A: #M0
+    instances
+      package:test/a.dart
+        A
+          requestedMethods
+            foo=: #M1
+[status] idle
+''',
+      updatedA: r'''
+class A {
+  static set foo(double _) {}
+}
+''',
+      expectedUpdatedEvents: r'''
+[status] working
+[operation] linkLibraryCycle
+  package:test/a.dart
+    manifest
+      A: #M0
+        declaredMembers
+          foo.setter: #M4
+  requirements
+    topLevels
+      dart:core
+        double: #M5
+[future] getErrors T2
+  ErrorsResult #2
+    path: /home/test/lib/test.dart
+    uri: package:test/test.dart
+    flags: isLibrary
+[operation] readLibraryCycleBundle
+  package:test/test.dart
+[operation] getErrorsCannotReuse
+  instanceMethodIdMismatch
+    libraryUri: package:test/a.dart
+    interfaceName: A
+    methodName: foo=
+    expectedId: #M1
+    actualId: #M4
+[operation] analyzeFile
+  file: /home/test/lib/test.dart
+  library: /home/test/lib/test.dart
+[stream]
+  ResolvedUnitResult #3
+    path: /home/test/lib/test.dart
+    uri: package:test/test.dart
+    flags: exists isLibrary
+[operation] analyzedLibrary
+  file: /home/test/lib/test.dart
+  requirements
+    topLevels
+      dart:core
+        A: <null>
+      package:test/a.dart
+        A: #M0
+    instances
+      package:test/a.dart
+        A
+          requestedMethods
+            foo=: #M4
+[status] idle
+''',
+    );
+  }
+
+  test_dependency_class_static_setter_notUsed() async {
+    await _runChangeScenarioTA(
+      initialA: r'''
+class A {
+  static set foo(int _) {}
+  static set bar(int _) {}
+}
+''',
+      testCode: r'''
+import 'a.dart';
+void f() {
+  A.foo = 0;
+}
+''',
+      operation: _FineOperationTestFileGetErrors(),
+      expectedInitialEvents: r'''
+[status] working
+[operation] linkLibraryCycle SDK
+[future] getErrors T1
+  ErrorsResult #0
+    path: /home/test/lib/test.dart
+    uri: package:test/test.dart
+    flags: isLibrary
+[operation] linkLibraryCycle
+  package:test/a.dart
+    manifest
+      A: #M0
+        declaredMembers
+          bar.setter: #M1
+          foo.setter: #M2
+  requirements
+    topLevels
+      dart:core
+        int: #M3
+[operation] linkLibraryCycle
+  package:test/test.dart
+    manifest
+      f: #M4
+  requirements
+[operation] analyzeFile
+  file: /home/test/lib/test.dart
+  library: /home/test/lib/test.dart
+[stream]
+  ResolvedUnitResult #1
+    path: /home/test/lib/test.dart
+    uri: package:test/test.dart
+    flags: exists isLibrary
+[operation] analyzedLibrary
+  file: /home/test/lib/test.dart
+  requirements
+    topLevels
+      dart:core
+        A: <null>
+      package:test/a.dart
+        A: #M0
+    instances
+      package:test/a.dart
+        A
+          requestedMethods
+            foo=: #M2
+[status] idle
+''',
+      updatedA: r'''
+class A {
+  static set foo(int _) {}
+  static set bar(double _) {}
+}
+''',
+      expectedUpdatedEvents: r'''
+[status] working
+[operation] linkLibraryCycle
+  package:test/a.dart
+    manifest
+      A: #M0
+        declaredMembers
+          bar.setter: #M5
+          foo.setter: #M2
+  requirements
+    topLevels
+      dart:core
+        double: #M6
+        int: #M3
+[future] getErrors T2
+  ErrorsResult #2
+    path: /home/test/lib/test.dart
+    uri: package:test/test.dart
+    flags: isLibrary
+[operation] readLibraryCycleBundle
+  package:test/test.dart
+[operation] getErrorsFromBytes
+  file: /home/test/lib/test.dart
+  library: /home/test/lib/test.dart
+[status] idle
+''',
+    );
+  }
+
   test_dependency_classTypaAlias_constructor_named() async {
     configuration.withStreamResolvedUnitResults = false;
     await _runChangeScenarioTA(
@@ -12496,6 +13289,11 @@
         A: <null>
       package:test/a.dart
         A: #M0
+    instances
+      package:test/a.dart
+        A
+          requestedMethods
+            foo: <null>
     interfaces
       package:test/a.dart
         A
@@ -12945,6 +13743,11 @@
         A: <null>
       package:test/a.dart
         A: #M0
+    instances
+      package:test/a.dart
+        A
+          requestedMethods
+            foo: <null>
     interfaces
       package:test/a.dart
         A
@@ -13249,6 +14052,12 @@
         A: <null>
       package:test/a.dart
         A: #M0
+    instances
+      package:test/a.dart
+        A
+          requestedMethods
+            foo: <null>
+            foo=: <null>
     interfaces
       package:test/a.dart
         A
@@ -13573,6 +14382,12 @@
         A: <null>
       package:test/a.dart
         A: #M0
+    instances
+      package:test/a.dart
+        A
+          requestedMethods
+            foo: <null>
+            foo=: <null>
     interfaces
       package:test/a.dart
         A
diff --git a/pkg/analyzer/test/src/dart/analysis/result_printer.dart b/pkg/analyzer/test/src/dart/analysis/result_printer.dart
index 89d8839..21e3080 100644
--- a/pkg/analyzer/test/src/dart/analysis/result_printer.dart
+++ b/pkg/analyzer/test/src/dart/analysis/result_printer.dart
@@ -47,7 +47,8 @@
     sink.writelnWithIndent('requirements');
     sink.withIndent(() {
       _writeTopLevels(requirements);
-      _writeInterfaces(requirements);
+      _writeInstanceItems(requirements);
+      _writeInterfaceItems(requirements);
       _writeExportRequirements(requirements);
     });
   }
@@ -83,7 +84,30 @@
     });
   }
 
-  void _writeInterfaces(RequirementsManifest requirements) {
+  void _writeInstanceItems(RequirementsManifest requirements) {
+    var libEntries = requirements.instances.sorted;
+
+    libEntries.removeWhere((entry) {
+      var ignored = configuration.requirements.ignoredLibraries;
+      return ignored.contains(entry.key);
+    });
+
+    sink.writeElements('instances', libEntries, (libEntry) {
+      var interfaceEntries = libEntry.value.sorted;
+      sink.writeElements('${libEntry.key}', interfaceEntries, (instanceEntry) {
+        sink.writelnWithIndent(instanceEntry.key.asString);
+        sink.withIndent(() {
+          sink.writeElements(
+            'requestedMethods',
+            instanceEntry.value.requestedMethods.sorted,
+            _writeNamedId,
+          );
+        });
+      });
+    });
+  }
+
+  void _writeInterfaceItems(RequirementsManifest requirements) {
     var libEntries = requirements.interfaces.sorted;
 
     libEntries.removeWhere((entry) {