@@ -15,6 +15,7 @@ import 'package:analyzer/src/dart/analysis/driver_event.dart' as driver_events;
1515import 'package:analyzer/src/dart/analysis/file_state.dart';
1616import 'package:analyzer/src/dart/analysis/status.dart';
1717import 'package:analyzer/src/dart/ast/ast.dart';
18+ import 'package:analyzer/src/dart/element/element.dart';
1819import 'package:analyzer/src/error/codes.dart';
1920import 'package:analyzer/src/fine/requirements.dart';
2021import 'package:analyzer/src/lint/linter.dart';
@@ -5450,6 +5451,7 @@ class FineAnalysisDriverTest extends PubPackageResolutionTest
54505451
54515452 @override
54525453 Future<void> tearDown() async {
5454+ testFineAfterLibraryAnalyzerHook = null;
54535455 withFineDependencies = false;
54545456 return super.tearDown();
54555457 }
@@ -36890,6 +36892,251 @@ int get b => 0;
3689036892 );
3689136893 }
3689236894
36895+ test_req_instanceElement_getGetter() async {
36896+ newFile('$testPackageLibPath/a.dart', r'''
36897+ class A {
36898+ static int get foo {}
36899+ }
36900+ ''');
36901+
36902+ newFile(testFile.path, r'''
36903+ import 'a.dart';
36904+ ''');
36905+
36906+ _ManualRequirements.install((state) {
36907+ var A = state.singleUnit.scopeInstanceElement('A');
36908+ A.getGetter2('foo');
36909+ });
36910+
36911+ await _runManualRequirementsRecording(
36912+ expectedEvents: r'''
36913+ [status] working
36914+ [operation] linkLibraryCycle SDK
36915+ [operation] linkLibraryCycle
36916+ package:test/a.dart
36917+ manifest
36918+ A: #M0
36919+ declaredMembers
36920+ foo.getter: #M1
36921+ requirements
36922+ topLevels
36923+ dart:core
36924+ int: #M2
36925+ [operation] linkLibraryCycle
36926+ package:test/test.dart
36927+ requirements
36928+ [operation] analyzedLibrary
36929+ file: /home/test/lib/test.dart
36930+ requirements
36931+ topLevels
36932+ dart:core
36933+ A: <null>
36934+ package:test/a.dart
36935+ A: #M0
36936+ instances
36937+ package:test/a.dart
36938+ A
36939+ requestedMethods
36940+ foo: #M1
36941+ [status] idle
36942+ ''',
36943+ );
36944+ }
36945+
36946+ test_req_instanceElement_getMethod() async {
36947+ newFile('$testPackageLibPath/a.dart', r'''
36948+ class A {
36949+ static int foo() {}
36950+ }
36951+ ''');
36952+
36953+ newFile(testFile.path, r'''
36954+ import 'a.dart';
36955+ ''');
36956+
36957+ _ManualRequirements.install((state) {
36958+ var A = state.singleUnit.scopeInstanceElement('A');
36959+ A.getMethod2('foo');
36960+ });
36961+
36962+ await _runManualRequirementsRecording(
36963+ expectedEvents: r'''
36964+ [status] working
36965+ [operation] linkLibraryCycle SDK
36966+ [operation] linkLibraryCycle
36967+ package:test/a.dart
36968+ manifest
36969+ A: #M0
36970+ declaredMembers
36971+ foo.method: #M1
36972+ requirements
36973+ topLevels
36974+ dart:core
36975+ int: #M2
36976+ [operation] linkLibraryCycle
36977+ package:test/test.dart
36978+ requirements
36979+ [operation] analyzedLibrary
36980+ file: /home/test/lib/test.dart
36981+ requirements
36982+ topLevels
36983+ dart:core
36984+ A: <null>
36985+ package:test/a.dart
36986+ A: #M0
36987+ instances
36988+ package:test/a.dart
36989+ A
36990+ requestedMethods
36991+ foo: #M1
36992+ [status] idle
36993+ ''',
36994+ );
36995+ }
36996+
36997+ test_req_instanceElement_getMethod_doesNotExist() async {
36998+ newFile('$testPackageLibPath/a.dart', r'''
36999+ class A {}
37000+ ''');
37001+
37002+ newFile(testFile.path, r'''
37003+ import 'a.dart';
37004+ ''');
37005+
37006+ _ManualRequirements.install((state) {
37007+ var A = state.singleUnit.scopeInstanceElement('A');
37008+ A.getMethod2('foo');
37009+ });
37010+
37011+ await _runManualRequirementsRecording(
37012+ expectedEvents: r'''
37013+ [status] working
37014+ [operation] linkLibraryCycle SDK
37015+ [operation] linkLibraryCycle
37016+ package:test/a.dart
37017+ manifest
37018+ A: #M0
37019+ requirements
37020+ [operation] linkLibraryCycle
37021+ package:test/test.dart
37022+ requirements
37023+ [operation] analyzedLibrary
37024+ file: /home/test/lib/test.dart
37025+ requirements
37026+ topLevels
37027+ dart:core
37028+ A: <null>
37029+ package:test/a.dart
37030+ A: #M0
37031+ instances
37032+ package:test/a.dart
37033+ A
37034+ requestedMethods
37035+ foo: <null>
37036+ [status] idle
37037+ ''',
37038+ );
37039+ }
37040+
37041+ test_req_instanceElement_getSetter() async {
37042+ newFile('$testPackageLibPath/a.dart', r'''
37043+ class A {
37044+ static set foo(int _) {}
37045+ }
37046+ ''');
37047+
37048+ newFile(testFile.path, r'''
37049+ import 'a.dart';
37050+ ''');
37051+
37052+ _ManualRequirements.install((state) {
37053+ var A = state.singleUnit.scopeInstanceElement('A');
37054+ A.getSetter2('foo');
37055+ });
37056+
37057+ await _runManualRequirementsRecording(
37058+ expectedEvents: r'''
37059+ [status] working
37060+ [operation] linkLibraryCycle SDK
37061+ [operation] linkLibraryCycle
37062+ package:test/a.dart
37063+ manifest
37064+ A: #M0
37065+ declaredMembers
37066+ foo.setter: #M1
37067+ requirements
37068+ topLevels
37069+ dart:core
37070+ int: #M2
37071+ [operation] linkLibraryCycle
37072+ package:test/test.dart
37073+ requirements
37074+ [operation] analyzedLibrary
37075+ file: /home/test/lib/test.dart
37076+ requirements
37077+ topLevels
37078+ dart:core
37079+ A: <null>
37080+ package:test/a.dart
37081+ A: #M0
37082+ instances
37083+ package:test/a.dart
37084+ A
37085+ requestedMethods
37086+ foo=: #M1
37087+ [status] idle
37088+ ''',
37089+ );
37090+ }
37091+
37092+ test_req_interfaceElement_getConstructor_named() async {
37093+ newFile('$testPackageLibPath/a.dart', r'''
37094+ class A {
37095+ A.named();
37096+ }
37097+ ''');
37098+
37099+ newFile(testFile.path, r'''
37100+ import 'a.dart';
37101+ ''');
37102+
37103+ _ManualRequirements.install((state) {
37104+ var A = state.singleUnit.scopeInterfaceElement('A');
37105+ A.getNamedConstructor2('named');
37106+ });
37107+
37108+ await _runManualRequirementsRecording(
37109+ expectedEvents: r'''
37110+ [status] working
37111+ [operation] linkLibraryCycle SDK
37112+ [operation] linkLibraryCycle
37113+ package:test/a.dart
37114+ manifest
37115+ A: #M0
37116+ declaredMembers
37117+ named.constructor: #M1
37118+ requirements
37119+ [operation] linkLibraryCycle
37120+ package:test/test.dart
37121+ requirements
37122+ [operation] analyzedLibrary
37123+ file: /home/test/lib/test.dart
37124+ requirements
37125+ topLevels
37126+ dart:core
37127+ A: <null>
37128+ package:test/a.dart
37129+ A: #M0
37130+ interfaces
37131+ package:test/a.dart
37132+ A
37133+ constructors
37134+ named: #M1
37135+ [status] idle
37136+ ''',
37137+ );
37138+ }
37139+
3689337140 Future<void> _runChangeScenario({
3689437141 required _FineOperation operation,
3689537142 String? expectedInitialEvents,
@@ -37031,6 +37278,27 @@ int get b => 0;
3703137278 assertDriverStateString(testFile, expectedUpdatedDriverState);
3703237279 }
3703337280 }
37281+
37282+ /// Works together with [_ManualRequirements] to execute manual requests to
37283+ /// the element model, and observe which requirements are recorded.
37284+ Future<void> _runManualRequirementsRecording({
37285+ required String expectedEvents,
37286+ }) async {
37287+ withFineDependencies = true;
37288+ configuration
37289+ ..withAnalyzeFileEvents = false
37290+ ..withLibraryManifest = true
37291+ ..withLinkBundleEvents = true
37292+ ..withGetErrorsEvents = false
37293+ ..withResultRequirements = true
37294+ ..withStreamResolvedUnitResults = false;
37295+
37296+ var driver = driverFor(testFile);
37297+ var collector = DriverEventCollector(driver, idProvider: idProvider);
37298+
37299+ collector.getErrors('T1', testFile);
37300+ await assertEventsText(collector, expectedEvents);
37301+ }
3703437302}
3703537303
3703637304/// A lint that is always reported for all linted files.
@@ -37122,6 +37390,52 @@ final class _FineOperationTestFileGetErrors extends _FineOperation {
3712237390 const _FineOperationTestFileGetErrors();
3712337391}
3712437392
37393+ /// Helper for triggering requirements manually.
37394+ ///
37395+ /// Some [Element] APIs are not trivial, or maybe even impossible, to
37396+ /// trigger. For example because this API is not used during normal resolution
37397+ /// of Dart code, but can be used by a linter rule.
37398+ class _ManualRequirements {
37399+ final List<CompilationUnitImpl> units;
37400+
37401+ _ManualRequirements(this.units);
37402+
37403+ _ManualRequirementsUnit get singleUnit {
37404+ var unit = units.single;
37405+ return _ManualRequirementsUnit(unit);
37406+ }
37407+
37408+ static void install(void Function(_ManualRequirements) operation) {
37409+ testFineAfterLibraryAnalyzerHook = (units) {
37410+ var self = _ManualRequirements(units);
37411+ operation(self);
37412+ };
37413+ }
37414+ }
37415+
37416+ class _ManualRequirementsUnit {
37417+ final CompilationUnitImpl unit;
37418+
37419+ _ManualRequirementsUnit(this.unit);
37420+
37421+ LibraryFragmentImpl get libraryFragment {
37422+ return unit.declaredFragment!;
37423+ }
37424+
37425+ ClassElementImpl2 scopeClassElement(String name) {
37426+ return scopeInterfaceElement(name) as ClassElementImpl2;
37427+ }
37428+
37429+ InstanceElementImpl2 scopeInstanceElement(String name) {
37430+ var lookupResult = libraryFragment.scope.lookup(name);
37431+ return lookupResult.getter2 as InstanceElementImpl2;
37432+ }
37433+
37434+ InterfaceElementImpl2 scopeInterfaceElement(String name) {
37435+ return scopeInstanceElement(name) as InterfaceElementImpl2;
37436+ }
37437+ }
37438+
3712537439extension on AnalysisDriver {
3712637440 Future<void> assertFilesDefiningClassMemberName(
3712737441 String name,
0 commit comments