Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 902538e

Browse files
author
Dart CI
committed
Version 2.11.0-236.0.dev
Merge commit 'c003c1a64dbcce0102182d271c3c92ea34a20779' into 'dev'
2 parents 7f2b3f0 + c003c1a commit 902538e

File tree

13 files changed

+236
-73
lines changed

13 files changed

+236
-73
lines changed

pkg/analyzer/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
## 0.40.5-dev
22
* Deprecated `GenericTypeAliasElement`. Use `FunctionTypeAliasElement`.
3+
* Read imports, exports, and parts on demand in `AnalysisDriver`.
4+
Specifically, `parseFileSync` will not read any referenced files.
35

46
## 0.40.4
57
* Deprecated `IndexExpression.auxiliaryElements` and

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

Lines changed: 80 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -192,23 +192,54 @@ class FileState {
192192

193193
/// Return the set of all directly referenced files - imported, exported or
194194
/// parted.
195-
Set<FileState> get directReferencedFiles => _directReferencedFiles;
195+
Set<FileState> get directReferencedFiles {
196+
return _directReferencedFiles ??= <FileState>{
197+
...importedFiles,
198+
...exportedFiles,
199+
...partedFiles,
200+
};
201+
}
196202

197203
/// Return the set of all directly referenced libraries - imported or
198204
/// exported.
199-
Set<FileState> get directReferencedLibraries => _directReferencedLibraries;
205+
Set<FileState> get directReferencedLibraries {
206+
return _directReferencedLibraries ??= <FileState>{
207+
...importedFiles,
208+
...exportedFiles,
209+
};
210+
}
200211

201212
/// Return `true` if the file exists.
202213
bool get exists => _exists;
203214

204215
/// The list of files this file exports.
205-
List<FileState> get exportedFiles => _exportedFiles;
216+
List<FileState> get exportedFiles {
217+
if (_exportedFiles == null) {
218+
_exportedFiles = <FileState>[];
219+
for (var directive in _unlinked2.exports) {
220+
var uri = _selectRelativeUri(directive);
221+
var file = _fileForRelativeUri(uri);
222+
_exportedFiles.add(file);
223+
}
224+
}
225+
return _exportedFiles;
226+
}
206227

207228
@override
208229
int get hashCode => uri.hashCode;
209230

210231
/// The list of files this file imports.
211-
List<FileState> get importedFiles => _importedFiles;
232+
List<FileState> get importedFiles {
233+
if (_importedFiles == null) {
234+
_importedFiles = <FileState>[];
235+
for (var directive in _unlinked2.imports) {
236+
var uri = _selectRelativeUri(directive);
237+
var file = _fileForRelativeUri(uri);
238+
_importedFiles.add(file);
239+
}
240+
}
241+
return _importedFiles;
242+
}
212243

213244
LibraryCycle get internal_libraryCycle => _libraryCycle;
214245

@@ -237,6 +268,7 @@ class FileState {
237268
/// of. Return `null` if a library is not known, for example because we have
238269
/// not processed a library file yet.
239270
FileState get library {
271+
_fsState.readPartsForLibraries();
240272
List<FileState> libraries = _fsState._partToLibraries[this];
241273
if (libraries == null || libraries.isEmpty) {
242274
return null;
@@ -264,13 +296,27 @@ class FileState {
264296

265297
/// The list of files files that this library consists of, i.e. this library
266298
/// file itself and its [partedFiles].
267-
List<FileState> get libraryFiles => _libraryFiles;
299+
List<FileState> get libraryFiles {
300+
return _libraryFiles ??= [this, ...partedFiles];
301+
}
268302

269303
/// Return information about line in the file.
270304
LineInfo get lineInfo => _lineInfo;
271305

272306
/// The list of files this library file references as parts.
273-
List<FileState> get partedFiles => _partedFiles;
307+
List<FileState> get partedFiles {
308+
if (_partedFiles == null) {
309+
_partedFiles = <FileState>[];
310+
for (var uri in _unlinked2.parts) {
311+
var file = _fileForRelativeUri(uri);
312+
_partedFiles.add(file);
313+
_fsState._partToLibraries
314+
.putIfAbsent(file, () => <FileState>[])
315+
.add(this);
316+
}
317+
}
318+
return _partedFiles;
319+
}
274320

275321
/// The external names referenced by the file.
276322
Set<String> get referencedNames {
@@ -287,7 +333,7 @@ class FileState {
287333

288334
void appendReferenced(FileState file) {
289335
if (transitiveFiles.add(file)) {
290-
file._directReferencedFiles?.forEach(appendReferenced);
336+
file.directReferencedFiles.forEach(appendReferenced);
291337
}
292338
}
293339

@@ -436,39 +482,16 @@ class FileState {
436482
}
437483
}
438484

439-
// Build the graph.
440-
_importedFiles = <FileState>[];
441-
_exportedFiles = <FileState>[];
442-
_partedFiles = <FileState>[];
443-
for (var directive in _unlinked2.imports) {
444-
var uri = _selectRelativeUri(directive);
445-
var file = _fileForRelativeUri(uri);
446-
_importedFiles.add(file);
447-
}
448-
for (var directive in _unlinked2.exports) {
449-
var uri = _selectRelativeUri(directive);
450-
var file = _fileForRelativeUri(uri);
451-
_exportedFiles.add(file);
452-
}
453-
for (var uri in _unlinked2.parts) {
454-
var file = _fileForRelativeUri(uri);
455-
_partedFiles.add(file);
456-
_fsState._partToLibraries
457-
.putIfAbsent(file, () => <FileState>[])
458-
.add(this);
459-
}
460-
_libraryFiles = [this, ..._partedFiles];
485+
// Read imports/exports on demand.
486+
_importedFiles = null;
487+
_exportedFiles = null;
488+
_directReferencedFiles = null;
489+
_directReferencedLibraries = null;
461490

462-
// Compute referenced files.
463-
_directReferencedFiles = <FileState>{
464-
..._importedFiles,
465-
..._exportedFiles,
466-
..._partedFiles,
467-
};
468-
_directReferencedLibraries = <FileState>{
469-
..._importedFiles,
470-
..._exportedFiles,
471-
};
491+
// Read parts on demand.
492+
_fsState._librariesWithoutPartsRead.add(this);
493+
_partedFiles = null;
494+
_libraryFiles = null;
472495

473496
// Update mapping from subtyped names to files.
474497
for (var name in _driverUnlinkedUnit.subtypedNames) {
@@ -748,6 +771,11 @@ class FileSystemState {
748771
/// Mapping from a path to the corresponding canonical [FileState].
749772
final Map<String, FileState> _pathToCanonicalFile = {};
750773

774+
/// We don't read parts until requested, but if we need to know the
775+
/// library for a file, we need to read parts of every file to know
776+
/// which libraries reference this part.
777+
final List<FileState> _librariesWithoutPartsRead = [];
778+
751779
/// Mapping from a part to the libraries it is a part of.
752780
final Map<FileState, List<FileState>> _partToLibraries = {};
753781

@@ -950,6 +978,19 @@ class FileSystemState {
950978
_fileContentCache.remove(path);
951979
}
952980

981+
void readPartsForLibraries() {
982+
// Make a copy, because reading new files will update it.
983+
var libraryToProcess = _librariesWithoutPartsRead.toList();
984+
985+
// We will process these files, so clear it now.
986+
// It will be filled with new files during the loop below.
987+
_librariesWithoutPartsRead.clear();
988+
989+
for (var library in libraryToProcess) {
990+
library.partedFiles;
991+
}
992+
}
993+
953994
/// Remove the file with the given [path].
954995
void removeFile(String path) {
955996
markFileForReading(path);

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

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2349,6 +2349,49 @@ void f(A a) {}
23492349
}
23502350
}
23512351

2352+
test_parseFileSync_doesNotReadImportedFiles() async {
2353+
var a = convertPath('/test/lib/a.dart');
2354+
var b = convertPath('/test/lib/b.dart');
2355+
2356+
newFile(a, content: '');
2357+
newFile(b, content: r'''
2358+
import 'a.dart';
2359+
''');
2360+
2361+
expect(driver.fsState.knownFilePaths, isEmpty);
2362+
2363+
// Don't read `a.dart` when parse.
2364+
driver.parseFileSync(b);
2365+
expect(driver.fsState.knownFilePaths, unorderedEquals([b]));
2366+
2367+
// Still don't read `a.dart` when parse the second time.
2368+
driver.parseFileSync(b);
2369+
expect(driver.fsState.knownFilePaths, unorderedEquals([b]));
2370+
}
2371+
2372+
test_parseFileSync_doesNotReadPartedFiles() async {
2373+
var a = convertPath('/test/lib/a.dart');
2374+
var b = convertPath('/test/lib/b.dart');
2375+
2376+
newFile(a, content: r'''
2377+
part of my;
2378+
''');
2379+
newFile(b, content: r'''
2380+
library my;
2381+
part 'a.dart';
2382+
''');
2383+
2384+
expect(driver.fsState.knownFilePaths, isEmpty);
2385+
2386+
// Don't read `a.dart` when parse.
2387+
driver.parseFileSync(b);
2388+
expect(driver.fsState.knownFilePaths, unorderedEquals([b]));
2389+
2390+
// Still don't read `a.dart` when parse the second time.
2391+
driver.parseFileSync(b);
2392+
expect(driver.fsState.knownFilePaths, unorderedEquals([b]));
2393+
}
2394+
23522395
test_parseFileSync_languageVersion() async {
23532396
var path = convertPath('/test/lib/test.dart');
23542397

pkg/analyzer_cli/lib/src/driver.dart

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import 'dart:isolate';
88
import 'package:analyzer/dart/analysis/context_locator.dart' as api;
99
import 'package:analyzer/dart/sdk/build_sdk_summary.dart';
1010
import 'package:analyzer/error/error.dart';
11+
import 'package:analyzer/error/listener.dart';
1112
import 'package:analyzer/file_system/file_system.dart';
1213
import 'package:analyzer/file_system/physical_file_system.dart';
1314
import 'package:analyzer/src/context/builder.dart';
@@ -27,6 +28,8 @@ import 'package:analyzer/src/generated/interner.dart';
2728
import 'package:analyzer/src/generated/java_engine.dart';
2829
import 'package:analyzer/src/generated/sdk.dart';
2930
import 'package:analyzer/src/generated/source.dart';
31+
import 'package:analyzer/src/lint/linter.dart';
32+
import 'package:analyzer/src/lint/pub.dart';
3033
import 'package:analyzer/src/manifest/manifest_validator.dart';
3134
import 'package:analyzer/src/pubspec/pubspec_validator.dart';
3235
import 'package:analyzer/src/source/package_map_resolver.dart';
@@ -284,24 +287,54 @@ class Driver with HasContextMixin implements CommandLineStarter {
284287
}
285288
}
286289
} else if (shortName == AnalysisEngine.PUBSPEC_YAML_FILE) {
290+
var errors = <AnalysisError>[];
287291
try {
288292
var file = resourceProvider.getFile(path);
289293
var content = file.readAsStringSync();
290294
var node = loadYamlNode(content);
291295
if (node is YamlMap) {
292296
var validator =
293297
PubspecValidator(resourceProvider, file.createSource());
294-
var lineInfo = LineInfo.fromContent(content);
295-
var errors = validator.validate(node.nodes);
296-
formatter.formatErrors([
297-
ErrorsResultImpl(analysisDriver.currentSession, path, null,
298-
lineInfo, false, errors)
299-
]);
298+
errors.addAll(validator.validate(node.nodes));
299+
}
300+
301+
if (analysisDriver != null && analysisDriver.analysisOptions.lint) {
302+
var visitors = <LintRule, PubspecVisitor>{};
303+
for (var linter in analysisDriver.analysisOptions.lintRules) {
304+
if (linter is LintRule) {
305+
var visitor = linter.getPubspecVisitor();
306+
if (visitor != null) {
307+
visitors[linter] = visitor;
308+
}
309+
}
310+
}
311+
if (visitors.isNotEmpty) {
312+
var sourceUri = resourceProvider.pathContext.toUri(path);
313+
var pubspecAst = Pubspec.parse(content,
314+
sourceUrl: sourceUri, resourceProvider: resourceProvider);
315+
var listener = RecordingErrorListener();
316+
var reporter = ErrorReporter(listener,
317+
resourceProvider.getFile(path).createSource(sourceUri),
318+
isNonNullableByDefault: false);
319+
for (var entry in visitors.entries) {
320+
entry.key.reporter = reporter;
321+
pubspecAst.accept(entry.value);
322+
}
323+
errors.addAll(listener.errors);
324+
}
325+
}
326+
327+
if (errors.isNotEmpty) {
300328
for (var error in errors) {
301329
var severity = determineProcessedSeverity(
302330
error, options, analysisDriver.analysisOptions);
303331
allResult = allResult.max(severity);
304332
}
333+
var lineInfo = LineInfo.fromContent(content);
334+
formatter.formatErrors([
335+
ErrorsResultImpl(analysisDriver.currentSession, path, null,
336+
lineInfo, false, errors)
337+
]);
305338
}
306339
} catch (exception) {
307340
// If the file cannot be analyzed, ignore it.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
linter:
22
rules:
33
- camel_case_types
4+
- sort_pub_dependencies
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
name: linter_project
2+
3+
dependencies:
4+
test: any
5+
async: any

pkg/analyzer_cli/test/driver_test.dart

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -863,9 +863,10 @@ linter:
863863
/// Lints should be enabled.
864864
expect(analysisOptions.lint, isTrue);
865865

866-
/// The analysis options file only specifies 'camel_case_types'.
866+
/// The analysis options file specifies 'camel_case_types' and 'sort_pub_dependencies'.
867867
var lintNames = analysisOptions.lintRules.map((r) => r.name);
868-
expect(lintNames, orderedEquals(['camel_case_types']));
868+
expect(lintNames,
869+
orderedEquals(['camel_case_types', 'sort_pub_dependencies']));
869870
}
870871

871872
Future<void> test_noLints_lintsDisabled() async {
@@ -883,6 +884,12 @@ linter:
883884
expect(analysisOptions.lintRules, isEmpty);
884885
}
885886

887+
Future<void> test_pubspec_lintsInOptions_generatedLints() async {
888+
await drive('data/linter_project/pubspec.yaml',
889+
options: 'data/linter_project/$optionsFileName');
890+
expect(bulletToDash(outSink), contains('lint - Sort pub dependencies'));
891+
}
892+
886893
YamlMap _parseOptions(String src) =>
887894
AnalysisOptionsProvider().getOptionsFromString(src);
888895

0 commit comments

Comments
 (0)