Skip to content

Commit c975fdf

Browse files
scheglovCommit Queue
authored and
Commit Queue
committed
Macro. Support for macro generated files in getFilesDefiningClassMemberName()
Change-Id: I153dd67bb569ee8e6d086fae3326c7a6776195da Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/348724 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent e2f76a1 commit c975fdf

File tree

2 files changed

+122
-190
lines changed

2 files changed

+122
-190
lines changed

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

Lines changed: 70 additions & 190 deletions
Original file line numberDiff line numberDiff line change
@@ -189,13 +189,8 @@ class AnalysisDriver {
189189
/// The queue of requests for completion.
190190
final List<_ResolveForCompletionRequest> _resolveForCompletionRequests = [];
191191

192-
/// The task that discovers available files. If this field is not `null`,
193-
/// and the task is not completed, it should be performed and completed
194-
/// before any name searching task.
195-
_DiscoverAvailableFilesTask? _discoverAvailableFilesTask;
196-
197-
/// The list of tasks to compute files defining a class member name.
198-
final _definingClassMemberNameTasks = <_FilesDefiningClassMemberNameTask>[];
192+
/// Set to `true` after first [discoverAvailableFiles].
193+
bool _hasAvailableFilesDiscovered = false;
199194

200195
/// The list of tasks to compute files referencing a name.
201196
final _referencingNameTasks = <_FilesReferencingNameTask>[];
@@ -442,12 +437,7 @@ class AnalysisDriver {
442437
if (_requestedLibraries.isNotEmpty) {
443438
return AnalysisDriverPriority.interactive;
444439
}
445-
if (_discoverAvailableFilesTask != null &&
446-
!_discoverAvailableFilesTask!.isCompleted) {
447-
return AnalysisDriverPriority.interactive;
448-
}
449-
if (_definingClassMemberNameTasks.isNotEmpty ||
450-
_referencingNameTasks.isNotEmpty) {
440+
if (_referencingNameTasks.isNotEmpty) {
451441
return AnalysisDriverPriority.interactive;
452442
}
453443
if (_errorsRequestedFiles.isNotEmpty) {
@@ -639,14 +629,49 @@ class AnalysisDriver {
639629

640630
/// Return a [Future] that completes when discovery of all files that are
641631
/// potentially available is done, so that they are included in [knownFiles].
642-
Future<void> discoverAvailableFiles() {
643-
if (_discoverAvailableFilesTask != null &&
644-
_discoverAvailableFilesTask!.isCompleted) {
645-
return Future.value();
632+
Future<void> discoverAvailableFiles() async {
633+
if (_hasAvailableFilesDiscovered) {
634+
return;
635+
}
636+
_hasAvailableFilesDiscovered = true;
637+
638+
// Discover added files.
639+
for (var path in addedFiles) {
640+
_fsState.getFileForPath(path);
641+
}
642+
643+
// Discover SDK libraries.
644+
if (_sourceFactory.dartSdk case var dartSdk?) {
645+
for (var sdkLibrary in dartSdk.sdkLibraries) {
646+
var source = dartSdk.mapDartUri(sdkLibrary.shortName);
647+
var path = source!.fullName;
648+
_fsState.getFileForPath(path);
649+
}
650+
}
651+
652+
void discoverRecursively(Folder folder) {
653+
try {
654+
var pathContext = resourceProvider.pathContext;
655+
for (var child in folder.getChildren()) {
656+
if (child is File) {
657+
var path = child.path;
658+
if (file_paths.isDart(pathContext, path)) {
659+
_fsState.getFileForPath(path);
660+
}
661+
} else if (child is Folder) {
662+
discoverRecursively(child);
663+
}
664+
}
665+
} catch (_) {}
666+
}
667+
668+
// Discover files in package/lib folders.
669+
if (_sourceFactory.packageMap case var packageMap?) {
670+
var folders = packageMap.values.flattenedToList2;
671+
for (var folder in folders) {
672+
discoverRecursively(folder);
673+
}
646674
}
647-
_discoverAvailableFiles();
648-
_scheduler.notify();
649-
return _discoverAvailableFilesTask!.completer.future;
650675
}
651676

652677
/// Notify the driver that the client is going to stop using it.
@@ -757,17 +782,27 @@ class AnalysisDriver {
757782

758783
/// Completes with files that define a class member with the [name].
759784
Future<List<FileState>> getFilesDefiningClassMemberName(String name) async {
760-
_discoverAvailableFiles();
761-
var task = _FilesDefiningClassMemberNameTask(this, name);
762-
_definingClassMemberNameTasks.add(task);
763-
_scheduler.notify();
764-
return await task.completer.future;
785+
await discoverAvailableFiles();
786+
787+
// Get library elements, so macro generated files are added.
788+
for (var file in knownFiles.toList()) {
789+
await getLibraryByUri(file.uriStr);
790+
}
791+
792+
var definingFiles = <FileState>[];
793+
for (var file in knownFiles) {
794+
if (file.definedClassMemberNames.contains(name)) {
795+
definingFiles.add(file);
796+
}
797+
}
798+
799+
return definingFiles;
765800
}
766801

767802
/// Return a [Future] that completes with the list of known files that
768803
/// reference the given external [name].
769804
Future<List<String>> getFilesReferencingName(String name) {
770-
_discoverAvailableFiles();
805+
discoverAvailableFiles();
771806
var task = _FilesReferencingNameTask(this, name);
772807
_referencingNameTasks.add(task);
773808
_scheduler.notify();
@@ -1188,23 +1223,6 @@ class AnalysisDriver {
11881223
return;
11891224
}
11901225

1191-
// Discover available files.
1192-
if (_discoverAvailableFilesTask case var task?) {
1193-
if (!task.isCompleted) {
1194-
task.perform();
1195-
return;
1196-
}
1197-
}
1198-
1199-
// Compute files defining a name.
1200-
if (_definingClassMemberNameTasks.firstOrNull case var task?) {
1201-
bool isDone = task.perform();
1202-
if (isDone) {
1203-
_definingClassMemberNameTasks.remove(task);
1204-
}
1205-
return;
1206-
}
1207-
12081226
// Compute files referencing a name.
12091227
if (_referencingNameTasks.firstOrNull case var task?) {
12101228
bool isDone = task.perform();
@@ -1579,12 +1597,6 @@ class AnalysisDriver {
15791597
);
15801598
}
15811599

1582-
/// If this has not been done yet, schedule discovery of all files that are
1583-
/// potentially available, so that they are included in [knownFiles].
1584-
void _discoverAvailableFiles() {
1585-
_discoverAvailableFilesTask ??= _DiscoverAvailableFilesTask(this);
1586-
}
1587-
15881600
/// When we look at a part that has a `part of name;` directive, we
15891601
/// usually don't know the library (in contrast to `part of uri;`).
15901602
/// So, we have no choice than to resolve this part as its own library.
@@ -2492,95 +2504,6 @@ abstract class SchedulerWorker {
24922504
Future<void> performWork();
24932505
}
24942506

2495-
/// Task that discovers all files that are available to the driver, and makes
2496-
/// them known.
2497-
class _DiscoverAvailableFilesTask {
2498-
static const int _MS_WORK_INTERVAL = 5;
2499-
2500-
final AnalysisDriver driver;
2501-
2502-
final Completer<void> completer = Completer<void>();
2503-
2504-
Iterator<Folder>? folderIterator;
2505-
2506-
final List<String> files = [];
2507-
2508-
int fileIndex = 0;
2509-
2510-
_DiscoverAvailableFilesTask(this.driver);
2511-
2512-
bool get isCompleted => completer.isCompleted;
2513-
2514-
/// Perform the next piece of work, and set [isCompleted] to `true` to
2515-
/// indicate that the task is done, or keeps it `false` to indicate that the
2516-
/// task should continue to be run.
2517-
void perform() {
2518-
if (folderIterator == null) {
2519-
files.addAll(driver.addedFiles);
2520-
2521-
// Discover SDK libraries.
2522-
var dartSdk = driver._sourceFactory.dartSdk;
2523-
if (dartSdk != null) {
2524-
for (var sdkLibrary in dartSdk.sdkLibraries) {
2525-
var file = dartSdk.mapDartUri(sdkLibrary.shortName)!.fullName;
2526-
files.add(file);
2527-
}
2528-
}
2529-
2530-
// Discover files in package/lib folders.
2531-
var packageMap = driver._sourceFactory.packageMap;
2532-
if (packageMap != null) {
2533-
folderIterator = packageMap.values.flattenedToList2.iterator;
2534-
} else {
2535-
folderIterator = <Folder>[].iterator;
2536-
}
2537-
}
2538-
2539-
// List each package/lib folder recursively.
2540-
Stopwatch timer = Stopwatch()..start();
2541-
while (folderIterator!.moveNext()) {
2542-
var folder = folderIterator!.current;
2543-
_appendFilesRecursively(folder);
2544-
2545-
// Note: must check if we are exiting before calling moveNext()
2546-
// otherwise we will skip one iteration of the loop when we come back.
2547-
if (timer.elapsedMilliseconds > _MS_WORK_INTERVAL) {
2548-
return;
2549-
}
2550-
}
2551-
2552-
// Get know files one by one.
2553-
while (fileIndex < files.length) {
2554-
if (timer.elapsedMilliseconds > _MS_WORK_INTERVAL) {
2555-
return;
2556-
}
2557-
var file = files[fileIndex++];
2558-
driver._fsState.getFileForPath(file);
2559-
}
2560-
2561-
// The task is done, clean up.
2562-
folderIterator = null;
2563-
files.clear();
2564-
completer.complete();
2565-
}
2566-
2567-
void _appendFilesRecursively(Folder folder) {
2568-
try {
2569-
var pathContext = driver.resourceProvider.pathContext;
2570-
for (var child in folder.getChildren()) {
2571-
if (child is File) {
2572-
var path = child.path;
2573-
if (file_paths.isDart(pathContext, path)) {
2574-
files.add(path);
2575-
}
2576-
} else if (child is Folder) {
2577-
_appendFilesRecursively(child);
2578-
}
2579-
}
2580-
} catch (_) {}
2581-
}
2582-
}
2583-
25842507
class _FileChange {
25852508
final String path;
25862509
final _FileChangeKind kind;
@@ -2595,57 +2518,6 @@ class _FileChange {
25952518

25962519
enum _FileChangeKind { add, change, remove }
25972520

2598-
/// Task that computes the list of files that were added to the driver and
2599-
/// declare a class member with the given [name].
2600-
class _FilesDefiningClassMemberNameTask {
2601-
static const int _MS_WORK_INTERVAL = 5;
2602-
2603-
final AnalysisDriver driver;
2604-
final String name;
2605-
final Completer<List<FileState>> completer = Completer<List<FileState>>();
2606-
2607-
final List<FileState> definingFiles = [];
2608-
final Set<FileState> checkedFiles = {};
2609-
final List<FileState> filesToCheck = [];
2610-
2611-
_FilesDefiningClassMemberNameTask(this.driver, this.name);
2612-
2613-
/// Perform work for a fixed length of time, and complete the [completer] to
2614-
/// either return `true` to indicate that the task is done, or return `false`
2615-
/// to indicate that the task should continue to be run.
2616-
///
2617-
/// Each invocation of an asynchronous method has overhead, which looks as
2618-
/// `_SyncCompleter.complete` invocation, we see as much as 62% in some
2619-
/// scenarios. Instead we use a fixed length of time, so we can spend less time
2620-
/// overall and keep quick enough response time.
2621-
bool perform() {
2622-
Stopwatch timer = Stopwatch()..start();
2623-
while (timer.elapsedMilliseconds < _MS_WORK_INTERVAL) {
2624-
// Prepare files to check.
2625-
if (filesToCheck.isEmpty) {
2626-
var newFiles = driver.knownFiles.difference(checkedFiles);
2627-
filesToCheck.addAll(newFiles);
2628-
}
2629-
2630-
// If no more files to check, complete and done.
2631-
if (filesToCheck.isEmpty) {
2632-
completer.complete(definingFiles);
2633-
return true;
2634-
}
2635-
2636-
// Check the next file.
2637-
var file = filesToCheck.removeLast();
2638-
if (file.definedClassMemberNames.contains(name)) {
2639-
definingFiles.add(file);
2640-
}
2641-
checkedFiles.add(file);
2642-
}
2643-
2644-
// We're not done yet.
2645-
return false;
2646-
}
2647-
}
2648-
26492521
/// Task that computes the list of files that were added to the driver and
26502522
/// have at least one reference to an identifier [name] defined outside of the
26512523
/// file.
@@ -2723,12 +2595,20 @@ extension<K, V> on Map<K, List<Completer<V>>> {
27232595
}
27242596
}
27252597

2726-
extension on File {
2598+
extension FileExtension on File {
27272599
File? get libraryForMacro {
27282600
if (path.removeSuffix('.macro.dart') case var noExtPath?) {
27292601
var libraryPath = '$noExtPath.dart';
27302602
return provider.getFile(libraryPath);
27312603
}
27322604
return null;
27332605
}
2606+
2607+
File? get macroForLibrary {
2608+
if (path.removeSuffix('.dart') case var noExtPath?) {
2609+
var libraryPath = '$noExtPath.macro.dart';
2610+
return provider.getFile(libraryPath);
2611+
}
2612+
return null;
2613+
}
27342614
}

pkg/analyzer/test/src/dart/analysis/driver_test.dart

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1742,6 +1742,58 @@ class D {
17421742
expect(await forName('m3'), unorderedEquals([d]));
17431743
}
17441744

1745+
test_getFilesDefiningClassMemberName_macroGenerated() async {
1746+
if (!_configureWithCommonMacros()) {
1747+
return;
1748+
}
1749+
1750+
var a = newFile('$testPackageLibPath/a.dart', r'''
1751+
import 'append.dart';
1752+
1753+
@DeclareInType(' void foo() {}')
1754+
class A {}
1755+
''');
1756+
1757+
var b = newFile('$testPackageLibPath/b.dart', r'''
1758+
import 'append.dart';
1759+
1760+
@DeclareInType(' void bar() {}')
1761+
class B {}
1762+
''');
1763+
1764+
var c = newFile('$testPackageLibPath/c.dart', r'''
1765+
import 'append.dart';
1766+
1767+
@DeclareInType(' void foo() {}')
1768+
class C {}
1769+
''');
1770+
1771+
final driver = driverFor(testFile);
1772+
driver.addFile2(a);
1773+
driver.addFile2(b);
1774+
driver.addFile2(c);
1775+
1776+
Future<List<File>> forName(String name) async {
1777+
var files = await driver.getFilesDefiningClassMemberName(name);
1778+
return files.resources;
1779+
}
1780+
1781+
expect(
1782+
await forName('foo'),
1783+
unorderedEquals([
1784+
a.macroForLibrary,
1785+
c.macroForLibrary,
1786+
]),
1787+
);
1788+
1789+
expect(
1790+
await forName('bar'),
1791+
unorderedEquals([
1792+
b.macroForLibrary,
1793+
]),
1794+
);
1795+
}
1796+
17451797
test_getFilesDefiningClassMemberName_mixin() async {
17461798
final a = newFile('$testPackageLibPath/a.dart', r'''
17471799
mixin A {

0 commit comments

Comments
 (0)