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) {