Skip to content

Commit 2b1cf0b

Browse files
scheglovCommit Queue
authored andcommitted
Fine. Record InstanceElement.getMethod(), getter, setter invocations.
Change-Id: Ieaf1e37a204b8e475e9ecd1c9ef9bb60dcca5149 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/426441 Commit-Queue: Konstantin Shcheglov <[email protected]> Reviewed-by: Paul Berry <[email protected]>
1 parent 80ad4be commit 2b1cf0b

File tree

5 files changed

+1155
-122
lines changed

5 files changed

+1155
-122
lines changed

pkg/analyzer/lib/src/dart/analysis/driver.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ import 'package:meta/meta.dart';
101101
// TODO(scheglov): Clean up the list of implicitly analyzed files.
102102
class AnalysisDriver {
103103
/// The version of data format, should be incremented on every format change.
104-
static const int DATA_VERSION = 456;
104+
static const int DATA_VERSION = 457;
105105

106106
/// The number of exception contexts allowed to write. Once this field is
107107
/// zero, we stop writing any new exception contexts in this process.

pkg/analyzer/lib/src/dart/element/element.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4481,16 +4481,31 @@ abstract class InstanceElementImpl2 extends ElementImpl2
44814481

44824482
@override
44834483
GetterElementImpl? getGetter2(String name) {
4484+
globalResultRequirements?.record_instanceElement_getGetter(
4485+
element: this,
4486+
name: name,
4487+
);
4488+
44844489
return getters2.firstWhereOrNull((e) => e.name3 == name);
44854490
}
44864491

44874492
@override
44884493
MethodElementImpl2? getMethod2(String name) {
4494+
globalResultRequirements?.record_instanceElement_getMethod(
4495+
element: this,
4496+
name: name,
4497+
);
4498+
44894499
return methods2.firstWhereOrNull((e) => e.lookupName == name);
44904500
}
44914501

44924502
@override
44934503
SetterElementImpl? getSetter2(String name) {
4504+
globalResultRequirements?.record_instanceElement_getSetter(
4505+
element: this,
4506+
name: name,
4507+
);
4508+
44944509
return setters2.firstWhereOrNull((e) => e.name3 == name);
44954510
}
44964511

pkg/analyzer/lib/src/fine/requirements.dart

Lines changed: 206 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -185,22 +185,51 @@ final class ExportRequirementShowCombinator
185185
}
186186
}
187187

188+
/// Requirements for [InstanceElementImpl2].
189+
///
190+
/// If [InterfaceElementImpl2], there are additional requirements in form
191+
/// of [InterfaceItemRequirements].
192+
class InstanceItemRequirements {
193+
/// These are "methods" in wide meaning: methods, getters, setters.
194+
final Map<LookupName, ManifestItemId?> requestedMethods;
195+
196+
InstanceItemRequirements({required this.requestedMethods});
197+
198+
factory InstanceItemRequirements.empty() {
199+
return InstanceItemRequirements(requestedMethods: {});
200+
}
201+
202+
factory InstanceItemRequirements.read(SummaryDataReader reader) {
203+
return InstanceItemRequirements(requestedMethods: reader.readNameToIdMap());
204+
}
205+
206+
void write(BufferedSink sink) {
207+
sink.writeNameToIdMap(requestedMethods);
208+
}
209+
}
210+
211+
/// Requirements for [InterfaceElementImpl2], in addition to those that
212+
/// we already record as [InstanceItemRequirements].
213+
///
188214
/// Includes all requirements from class-like items: classes, enums,
189-
/// extensions (NB), extension types, mixins.
190-
class InterfaceRequirements {
215+
/// extension types, mixins.
216+
class InterfaceItemRequirements {
191217
final Map<LookupName, ManifestItemId?> constructors;
192218

193219
/// These are "methods" in wide meaning: methods, getters, setters.
194220
final Map<LookupName, ManifestItemId?> methods;
195221

196-
InterfaceRequirements({required this.constructors, required this.methods});
222+
InterfaceItemRequirements({
223+
required this.constructors,
224+
required this.methods,
225+
});
197226

198-
factory InterfaceRequirements.empty() {
199-
return InterfaceRequirements(constructors: {}, methods: {});
227+
factory InterfaceItemRequirements.empty() {
228+
return InterfaceItemRequirements(constructors: {}, methods: {});
200229
}
201230

202-
factory InterfaceRequirements.read(SummaryDataReader reader) {
203-
return InterfaceRequirements(
231+
factory InterfaceItemRequirements.read(SummaryDataReader reader) {
232+
return InterfaceItemRequirements(
204233
constructors: reader.readNameToIdMap(),
205234
methods: reader.readNameToIdMap(),
206235
);
@@ -216,10 +245,11 @@ class RequirementsManifest {
216245
/// LibraryUri => TopName => ID
217246
final Map<Uri, Map<LookupName, ManifestItemId?>> topLevels = {};
218247

219-
/// LibraryUri => TopName => InterfaceRequirements
220-
///
221-
/// These are "methods" in wide meaning: methods, getters, setters.
222-
final Map<Uri, Map<LookupName, InterfaceRequirements>> interfaces = {};
248+
/// LibraryUri => TopName => InstanceItemRequirements
249+
final Map<Uri, Map<LookupName, InstanceItemRequirements>> instances = {};
250+
251+
/// LibraryUri => TopName => InterfaceItemRequirements
252+
final Map<Uri, Map<LookupName, InterfaceItemRequirements>> interfaces = {};
223253

224254
final List<ExportRequirement> exportRequirements = [];
225255

@@ -235,13 +265,25 @@ class RequirementsManifest {
235265
),
236266
);
237267

268+
result.instances.addAll(
269+
reader.readMap(
270+
readKey: () => reader.readUri(),
271+
readValue: () {
272+
return reader.readMap(
273+
readKey: () => LookupName.read(reader),
274+
readValue: () => InstanceItemRequirements.read(reader),
275+
);
276+
},
277+
),
278+
);
279+
238280
result.interfaces.addAll(
239281
reader.readMap(
240282
readKey: () => reader.readUri(),
241283
readValue: () {
242284
return reader.readMap(
243285
readKey: () => LookupName.read(reader),
244-
readValue: () => InterfaceRequirements.read(reader),
286+
readValue: () => InterfaceItemRequirements.read(reader),
245287
);
246288
},
247289
),
@@ -296,6 +338,43 @@ class RequirementsManifest {
296338
}
297339
}
298340

341+
for (var libraryEntry in instances.entries) {
342+
var libraryUri = libraryEntry.key;
343+
344+
var libraryElement = elementFactory.libraryOfUri(libraryUri);
345+
var libraryManifest = libraryElement?.manifest;
346+
if (libraryManifest == null) {
347+
return LibraryMissing(uri: libraryUri);
348+
}
349+
350+
for (var instanceEntry in libraryEntry.value.entries) {
351+
var instanceName = instanceEntry.key;
352+
var instanceItem = libraryManifest.items[instanceName];
353+
if (instanceItem is! InstanceItem) {
354+
return TopLevelNotInterface(
355+
libraryUri: libraryUri,
356+
name: instanceName,
357+
);
358+
}
359+
360+
var methods = instanceEntry.value.requestedMethods;
361+
for (var methodEntry in methods.entries) {
362+
var methodName = methodEntry.key;
363+
var methodId = instanceItem.getDeclaredMemberId(methodName);
364+
var expectedId = methodEntry.value;
365+
if (expectedId != methodId) {
366+
return InstanceMethodIdMismatch(
367+
libraryUri: libraryUri,
368+
interfaceName: instanceName,
369+
methodName: methodName,
370+
expectedId: expectedId,
371+
actualId: methodId,
372+
);
373+
}
374+
}
375+
}
376+
}
377+
299378
for (var libraryEntry in interfaces.entries) {
300379
var libraryUri = libraryEntry.key;
301380

@@ -365,15 +444,17 @@ class RequirementsManifest {
365444
required InterfaceElementImpl2 element,
366445
required String name,
367446
}) {
368-
var interfacePair = _getInterface(element);
369-
if (interfacePair == null) {
447+
var itemRequirements = _getInterfaceItem(element);
448+
if (itemRequirements == null) {
370449
return;
371450
}
372451

373-
var (interfaceItem, interface) = interfacePair;
452+
var item = itemRequirements.item;
453+
var requirements = itemRequirements.requirements;
454+
374455
var constructorName = name.asLookupName;
375-
var constructorId = interfaceItem.getConstructorId(constructorName);
376-
interface.constructors[constructorName] = constructorId;
456+
var constructorId = item.getConstructorId(constructorName);
457+
requirements.constructors[constructorName] = constructorId;
377458
}
378459

379460
/// This method is invoked by [InheritanceManager3] to notify the collector
@@ -388,14 +469,17 @@ class RequirementsManifest {
388469
return;
389470
}
390471

391-
var interfacePair = _getInterface(element);
392-
if (interfacePair == null) {
472+
var itemRequirements = _getInterfaceItem(element);
473+
if (itemRequirements == null) {
393474
return;
394475
}
395476

396-
var (interfaceItem, interface) = interfacePair;
477+
var item = itemRequirements.item;
478+
var requirements = itemRequirements.requirements;
479+
397480
var methodName = nameObj.name.asLookupName;
398-
var methodId = interfaceItem.getInterfaceMethodId(methodName);
481+
var methodId = item.getInterfaceMethodId(methodName);
482+
requirements.methods[methodName] = methodId;
399483

400484
// Check for consistency between the actual interface and manifest.
401485
if (methodElement != null) {
@@ -410,7 +494,7 @@ class RequirementsManifest {
410494
}
411495
}
412496

413-
interface.methods[methodName] = methodId;
497+
requirements.methods[methodName] = methodId;
414498
}
415499

416500
/// This method is invoked by an import scope to notify the collector that
@@ -427,6 +511,37 @@ class RequirementsManifest {
427511
}
428512
}
429513

514+
void record_instanceElement_getGetter({
515+
required InstanceElementImpl2 element,
516+
required String name,
517+
}) {
518+
record_instanceElement_getMethod(element: element, name: name);
519+
}
520+
521+
void record_instanceElement_getMethod({
522+
required InstanceElementImpl2 element,
523+
required String name,
524+
}) {
525+
var itemRequirements = _getInstanceItem(element);
526+
if (itemRequirements == null) {
527+
return;
528+
}
529+
530+
var item = itemRequirements.item;
531+
var requirements = itemRequirements.requirements;
532+
533+
var methodName = name.asLookupName;
534+
var methodId = item.getDeclaredMemberId(methodName);
535+
requirements.requestedMethods[methodName] = methodId;
536+
}
537+
538+
void record_instanceElement_getSetter({
539+
required InstanceElementImpl2 element,
540+
required String name,
541+
}) {
542+
record_instanceElement_getMethod(element: element, name: '$name=');
543+
}
544+
430545
/// This method is invoked after linking of a library cycle, to exclude
431546
/// requirements to the libraries of this same library cycle. We already
432547
/// link these libraries together, so only requirements to the previous
@@ -453,6 +568,18 @@ class RequirementsManifest {
453568
writeValue: (map) => sink.writeNameToIdMap(map),
454569
);
455570

571+
sink.writeMap(
572+
instances,
573+
writeKey: (uri) => sink.writeUri(uri),
574+
writeValue: (nameToInstanceMap) {
575+
sink.writeMap(
576+
nameToInstanceMap,
577+
writeKey: (name) => name.write(sink),
578+
writeValue: (instance) => instance.write(sink),
579+
);
580+
},
581+
);
582+
456583
sink.writeMap(
457584
interfaces,
458585
writeKey: (uri) => sink.writeUri(uri),
@@ -523,7 +650,36 @@ class RequirementsManifest {
523650
}
524651
}
525652

526-
(InterfaceItem, InterfaceRequirements)? _getInterface(
653+
_InstanceItemWithRequirements? _getInstanceItem(
654+
InstanceElementImpl2 element,
655+
) {
656+
var libraryElement = element.library2;
657+
var manifest = libraryElement.manifest;
658+
659+
// If we are linking the library, its manifest is not set yet.
660+
// But then we also don't care about this dependency.
661+
if (manifest == null) {
662+
return null;
663+
}
664+
665+
// SAFETY: we don't export elements without name.
666+
var instanceName = element.lookupName!.asLookupName;
667+
668+
var instancesMap = instances[libraryElement.uri] ??= {};
669+
var instanceItem = manifest.items[instanceName];
670+
671+
// SAFETY: every instance element must be in the manifest.
672+
instanceItem as InstanceItem;
673+
674+
var requirements =
675+
instancesMap[instanceName] ??= InstanceItemRequirements.empty();
676+
return _InstanceItemWithRequirements(
677+
item: instanceItem,
678+
requirements: requirements,
679+
);
680+
}
681+
682+
_InterfaceItemWithRequirements? _getInterfaceItem(
527683
InterfaceElementImpl2 element,
528684
) {
529685
var libraryElement = element.library2;
@@ -544,23 +700,46 @@ class RequirementsManifest {
544700
// SAFETY: every interface element must be in the manifest.
545701
interfaceItem as InterfaceItem;
546702

547-
var interfaceRequirements =
548-
interfacesMap[interfaceName] ??= InterfaceRequirements.empty();
549-
return (interfaceItem, interfaceRequirements);
703+
var requirements =
704+
interfacesMap[interfaceName] ??= InterfaceItemRequirements.empty();
705+
return _InterfaceItemWithRequirements(
706+
item: interfaceItem,
707+
requirements: requirements,
708+
);
550709
}
551710

552711
String _qualifiedMethodName(
553712
InterfaceElementImpl2 element,
554713
LookupName methodName,
555714
) {
556-
return '${element.library2.uri}'
715+
return '${element.library2.uri} '
557716
'${element.displayName}.'
558717
'${methodName.asString}';
559718
}
560719
}
561720

562721
enum _ExportRequirementCombinatorKind { hide, show }
563722

723+
class _InstanceItemWithRequirements {
724+
final InstanceItem item;
725+
final InstanceItemRequirements requirements;
726+
727+
_InstanceItemWithRequirements({
728+
required this.item,
729+
required this.requirements,
730+
});
731+
}
732+
733+
class _InterfaceItemWithRequirements {
734+
final InterfaceItem item;
735+
final InterfaceItemRequirements requirements;
736+
737+
_InterfaceItemWithRequirements({
738+
required this.item,
739+
required this.requirements,
740+
});
741+
}
742+
564743
extension _BufferedSinkExtension on BufferedSink {
565744
void writeNameToIdMap(Map<LookupName, ManifestItemId?> map) {
566745
writeMap(

0 commit comments

Comments
 (0)