Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1842)

Side by Side Diff: pkg/analyzer/lib/src/dart/analysis/driver.dart

Issue 2673683003: Split core file tracking functionality from AnalysisDriver. (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 import 'dart:async'; 5 import 'dart:async';
6 import 'dart:collection'; 6 import 'dart:collection';
7 import 'dart:typed_data'; 7 import 'dart:typed_data';
8 8
9 import 'package:analyzer/context/declared_variables.dart'; 9 import 'package:analyzer/context/declared_variables.dart';
10 import 'package:analyzer/dart/ast/ast.dart'; 10 import 'package:analyzer/dart/ast/ast.dart';
11 import 'package:analyzer/dart/element/element.dart' show CompilationUnitElement; 11 import 'package:analyzer/dart/element/element.dart' show CompilationUnitElement;
12 import 'package:analyzer/error/error.dart'; 12 import 'package:analyzer/error/error.dart';
13 import 'package:analyzer/error/listener.dart'; 13 import 'package:analyzer/error/listener.dart';
14 import 'package:analyzer/exception/exception.dart'; 14 import 'package:analyzer/exception/exception.dart';
15 import 'package:analyzer/file_system/file_system.dart'; 15 import 'package:analyzer/file_system/file_system.dart';
16 import 'package:analyzer/src/dart/analysis/byte_store.dart'; 16 import 'package:analyzer/src/dart/analysis/byte_store.dart';
17 import 'package:analyzer/src/dart/analysis/file_state.dart'; 17 import 'package:analyzer/src/dart/analysis/file_state.dart';
18 import 'package:analyzer/src/dart/analysis/file_tracker.dart';
18 import 'package:analyzer/src/dart/analysis/index.dart'; 19 import 'package:analyzer/src/dart/analysis/index.dart';
19 import 'package:analyzer/src/dart/analysis/library_context.dart'; 20 import 'package:analyzer/src/dart/analysis/library_context.dart';
20 import 'package:analyzer/src/dart/analysis/search.dart'; 21 import 'package:analyzer/src/dart/analysis/search.dart';
21 import 'package:analyzer/src/dart/analysis/status.dart'; 22 import 'package:analyzer/src/dart/analysis/status.dart';
22 import 'package:analyzer/src/dart/analysis/top_level_declaration.dart'; 23 import 'package:analyzer/src/dart/analysis/top_level_declaration.dart';
23 import 'package:analyzer/src/generated/engine.dart' 24 import 'package:analyzer/src/generated/engine.dart'
24 show AnalysisContext, AnalysisEngine, AnalysisOptions; 25 show AnalysisContext, AnalysisEngine, AnalysisOptions;
25 import 'package:analyzer/src/generated/source.dart'; 26 import 'package:analyzer/src/generated/source.dart';
26 import 'package:analyzer/src/services/lint.dart'; 27 import 'package:analyzer/src/services/lint.dart';
27 import 'package:analyzer/src/summary/api_signature.dart'; 28 import 'package:analyzer/src/summary/api_signature.dart';
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
83 */ 84 */
84 final String name; 85 final String name;
85 86
86 /** 87 /**
87 * The scheduler that schedules analysis work in this, and possibly other 88 * The scheduler that schedules analysis work in this, and possibly other
88 * analysis drivers. 89 * analysis drivers.
89 */ 90 */
90 final AnalysisDriverScheduler _scheduler; 91 final AnalysisDriverScheduler _scheduler;
91 92
92 /** 93 /**
93 * The logger to write performed operations and performance to.
94 */
95 final PerformanceLog _logger;
96
97 /**
98 * The resource provider for working with files. 94 * The resource provider for working with files.
99 */ 95 */
100 final ResourceProvider _resourceProvider; 96 final ResourceProvider _resourceProvider;
101 97
102 /** 98 /**
103 * The byte storage to get and put serialized data. 99 * The byte storage to get and put serialized data.
104 * 100 *
105 * It can be shared with other [AnalysisDriver]s. 101 * It can be shared with other [AnalysisDriver]s.
106 */ 102 */
107 final ByteStore _byteStore; 103 final ByteStore _byteStore;
(...skipping 24 matching lines...) Expand all
132 * The declared environment variables. 128 * The declared environment variables.
133 */ 129 */
134 final DeclaredVariables declaredVariables = new DeclaredVariables(); 130 final DeclaredVariables declaredVariables = new DeclaredVariables();
135 131
136 /** 132 /**
137 * The salt to mix into all hashes used as keys for serialized data. 133 * The salt to mix into all hashes used as keys for serialized data.
138 */ 134 */
139 final Uint32List _salt = new Uint32List(1 + AnalysisOptions.signatureLength); 135 final Uint32List _salt = new Uint32List(1 + AnalysisOptions.signatureLength);
140 136
141 /** 137 /**
142 * The current file system state.
143 */
144 FileSystemState _fsState;
145
146 /**
147 * The set of added files.
148 */
149 final _addedFiles = new LinkedHashSet<String>();
150
151 /**
152 * The set of priority files, that should be analyzed sooner. 138 * The set of priority files, that should be analyzed sooner.
153 */ 139 */
154 final _priorityFiles = new LinkedHashSet<String>(); 140 final _priorityFiles = new LinkedHashSet<String>();
155 141
156 /** 142 /**
157 * The mapping from the files for which analysis was requested using 143 * The mapping from the files for which analysis was requested using
158 * [getResult] to the [Completer]s to report the result. 144 * [getResult] to the [Completer]s to report the result.
159 */ 145 */
160 final _requestedFiles = <String, List<Completer<AnalysisResult>>>{}; 146 final _requestedFiles = <String, List<Completer<AnalysisResult>>>{};
161 147
(...skipping 20 matching lines...) Expand all
182 <String, List<Completer<AnalysisDriverUnitIndex>>>{}; 168 <String, List<Completer<AnalysisDriverUnitIndex>>>{};
183 169
184 /** 170 /**
185 * The mapping from the files for which the index was requested using 171 * The mapping from the files for which the index was requested using
186 * [getIndex] to the [Completer]s to report the result. 172 * [getIndex] to the [Completer]s to report the result.
187 */ 173 */
188 final _unitElementRequestedFiles = 174 final _unitElementRequestedFiles =
189 <String, List<Completer<CompilationUnitElement>>>{}; 175 <String, List<Completer<CompilationUnitElement>>>{};
190 176
191 /** 177 /**
192 * The set of files were reported as changed through [changeFile] and not
193 * checked for actual changes yet.
194 */
195 final _changedFiles = new LinkedHashSet<String>();
196
197 /**
198 * The set of files that are currently scheduled for analysis.
199 */
200 final _filesToAnalyze = new LinkedHashSet<String>();
201
202 /**
203 * The mapping from the files for which analysis was requested using 178 * The mapping from the files for which analysis was requested using
204 * [getResult], and which were found to be parts without known libraries, 179 * [getResult], and which were found to be parts without known libraries,
205 * to the [Completer]s to report the result. 180 * to the [Completer]s to report the result.
206 */ 181 */
207 final _requestedParts = <String, List<Completer<AnalysisResult>>>{}; 182 final _requestedParts = <String, List<Completer<AnalysisResult>>>{};
208 183
209 /** 184 /**
210 * The set of part files that are currently scheduled for analysis. 185 * The set of part files that are currently scheduled for analysis.
211 */ 186 */
212 final _partsToAnalyze = new LinkedHashSet<String>(); 187 final _partsToAnalyze = new LinkedHashSet<String>();
(...skipping 15 matching lines...) Expand all
228 new StreamController<ExceptionResult>(); 203 new StreamController<ExceptionResult>();
229 204
230 /** 205 /**
231 * The instance of the [Search] helper. 206 * The instance of the [Search] helper.
232 */ 207 */
233 Search _search; 208 Search _search;
234 209
235 AnalysisDriverTestView _testView; 210 AnalysisDriverTestView _testView;
236 211
237 /** 212 /**
213 * The [FileTracker] used by this driver.
214 */
215 FileTracker _fileTracker;
216
217 /**
238 * Create a new instance of [AnalysisDriver]. 218 * Create a new instance of [AnalysisDriver].
239 * 219 *
240 * The given [SourceFactory] is cloned to ensure that it does not contain a 220 * The given [SourceFactory] is cloned to ensure that it does not contain a
241 * reference to a [AnalysisContext] in which it could have been used. 221 * reference to a [AnalysisContext] in which it could have been used.
242 */ 222 */
243 AnalysisDriver( 223 AnalysisDriver(
244 this._scheduler, 224 this._scheduler,
245 this._logger, 225 PerformanceLog logger,
246 this._resourceProvider, 226 this._resourceProvider,
247 this._byteStore, 227 this._byteStore,
248 this._contentOverlay, 228 this._contentOverlay,
249 this.name, 229 this.name,
250 SourceFactory sourceFactory, 230 SourceFactory sourceFactory,
251 this._analysisOptions, 231 this._analysisOptions,
252 {PackageBundle sdkBundle}) 232 {PackageBundle sdkBundle})
253 : _sourceFactory = sourceFactory.clone(), 233 : _sourceFactory = sourceFactory.clone(),
254 _sdkBundle = sdkBundle { 234 _sdkBundle = sdkBundle {
255 _testView = new AnalysisDriverTestView(this); 235 _testView = new AnalysisDriverTestView(this);
256 _fillSalt(); 236 _createFileTracker(logger);
257 _fsState = new FileSystemState(_logger, _byteStore, _contentOverlay,
258 _resourceProvider, sourceFactory, _analysisOptions, _salt);
259 _scheduler._add(this); 237 _scheduler._add(this);
260 _search = new Search(this); 238 _search = new Search(this);
261 } 239 }
262 240
263 /** 241 /**
264 * Return the set of files explicitly added to analysis using [addFile]. 242 * Return the set of files explicitly added to analysis using [addFile].
265 */ 243 */
266 Set<String> get addedFiles => _addedFiles; 244 Set<String> get addedFiles => _fileTracker.addedFiles;
267 245
268 /** 246 /**
269 * Return the analysis options used to control analysis. 247 * Return the analysis options used to control analysis.
270 */ 248 */
271 AnalysisOptions get analysisOptions => _analysisOptions; 249 AnalysisOptions get analysisOptions => _analysisOptions;
272 250
273 /** 251 /**
274 * Return the stream that produces [ExceptionResult]s. 252 * Return the stream that produces [ExceptionResult]s.
275 */ 253 */
276 Stream<ExceptionResult> get exceptions => _exceptionController.stream; 254 Stream<ExceptionResult> get exceptions => _exceptionController.stream;
277 255
278 /** 256 /**
279 * The current file system state. 257 * The current file system state.
280 */ 258 */
281 FileSystemState get fsState => _fsState; 259 FileSystemState get fsState => _fileTracker.fsState;
282 260
283 /** 261 /**
284 * Return `true` if the driver has a file to analyze. 262 * Return `true` if the driver has a file to analyze.
285 */ 263 */
286 bool get hasFilesToAnalyze { 264 bool get hasFilesToAnalyze {
287 return _changedFiles.isNotEmpty || 265 return _fileTracker.hasChangedFiles ||
288 _requestedFiles.isNotEmpty || 266 _requestedFiles.isNotEmpty ||
289 _requestedParts.isNotEmpty || 267 _requestedParts.isNotEmpty ||
290 _filesToAnalyze.isNotEmpty || 268 _fileTracker.hasPendingFiles ||
291 _partsToAnalyze.isNotEmpty; 269 _partsToAnalyze.isNotEmpty;
292 } 270 }
293 271
294 /** 272 /**
295 * Return the set of files that are known at this moment. This set does not 273 * Return the set of files that are known at this moment. This set does not
296 * always include all added files or all implicitly used file. If a file has 274 * always include all added files or all implicitly used file. If a file has
297 * not been processed yet, it might be missing. 275 * not been processed yet, it might be missing.
298 */ 276 */
299 Set<String> get knownFiles => _fsState.knownFilePaths; 277 Set<String> get knownFiles => _fileTracker.fsState.knownFilePaths;
300 278
301 /** 279 /**
302 * Return the number of files scheduled for analysis. 280 * Return the number of files scheduled for analysis.
303 */ 281 */
304 int get numberOfFilesToAnalyze => _filesToAnalyze.length; 282 int get numberOfFilesToAnalyze => _fileTracker.numberOfPendingFiles;
305 283
306 /** 284 /**
307 * Return the list of files that the driver should try to analyze sooner. 285 * Return the list of files that the driver should try to analyze sooner.
308 */ 286 */
309 List<String> get priorityFiles => _priorityFiles.toList(growable: false); 287 List<String> get priorityFiles => _priorityFiles.toList(growable: false);
310 288
311 /** 289 /**
312 * Set the list of files that the driver should try to analyze sooner. 290 * Set the list of files that the driver should try to analyze sooner.
313 * 291 *
314 * Every path in the list must be absolute and normalized. 292 * Every path in the list must be absolute and normalized.
315 * 293 *
316 * The driver will produce the results through the [results] stream. The 294 * The driver will produce the results through the [results] stream. The
317 * exact order in which results are produced is not defined, neither 295 * exact order in which results are produced is not defined, neither
318 * between priority files, nor between priority and non-priority files. 296 * between priority files, nor between priority and non-priority files.
319 */ 297 */
320 void set priorityFiles(List<String> priorityPaths) { 298 void set priorityFiles(List<String> priorityPaths) {
321 _priorityResults.keys 299 _priorityResults.keys
322 .toSet() 300 .toSet()
323 .difference(priorityPaths.toSet()) 301 .difference(priorityPaths.toSet())
324 .forEach(_priorityResults.remove); 302 .forEach(_priorityResults.remove);
325 _priorityFiles.clear(); 303 _priorityFiles.clear();
326 _priorityFiles.addAll(priorityPaths); 304 _priorityFiles.addAll(priorityPaths);
327 _scheduler._notify(this); 305 _scheduler.notify(this);
328 } 306 }
329 307
330 /** 308 /**
331 * Return the [Stream] that produces [AnalysisResult]s for added files. 309 * Return the [Stream] that produces [AnalysisResult]s for added files.
332 * 310 *
333 * Note that the stream supports only one single subscriber. 311 * Note that the stream supports only one single subscriber.
334 * 312 *
335 * Analysis starts when the [AnalysisDriverScheduler] is started and the 313 * Analysis starts when the [AnalysisDriverScheduler] is started and the
336 * driver is added to it. The analysis state transitions to "analyzing" and 314 * driver is added to it. The analysis state transitions to "analyzing" and
337 * an analysis result is produced for every added file prior to the next time 315 * an analysis result is produced for every added file prior to the next time
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
380 return AnalysisDriverPriority.interactive; 358 return AnalysisDriverPriority.interactive;
381 } 359 }
382 if (_unitElementRequestedFiles.isNotEmpty) { 360 if (_unitElementRequestedFiles.isNotEmpty) {
383 return AnalysisDriverPriority.interactive; 361 return AnalysisDriverPriority.interactive;
384 } 362 }
385 if (_topLevelNameDeclarationsTasks.isNotEmpty) { 363 if (_topLevelNameDeclarationsTasks.isNotEmpty) {
386 return AnalysisDriverPriority.interactive; 364 return AnalysisDriverPriority.interactive;
387 } 365 }
388 if (_priorityFiles.isNotEmpty) { 366 if (_priorityFiles.isNotEmpty) {
389 for (String path in _priorityFiles) { 367 for (String path in _priorityFiles) {
390 if (_filesToAnalyze.contains(path)) { 368 if (_fileTracker.isFilePending(path)) {
391 return AnalysisDriverPriority.priority; 369 return AnalysisDriverPriority.priority;
392 } 370 }
393 } 371 }
394 } 372 }
395 if (_filesToAnalyze.isNotEmpty) { 373 if (_fileTracker.hasPendingFiles) {
396 return AnalysisDriverPriority.general; 374 return AnalysisDriverPriority.general;
397 } 375 }
398 if (_changedFiles.isNotEmpty) { 376 if (_fileTracker.hasChangedFiles) {
399 return AnalysisDriverPriority.general; 377 return AnalysisDriverPriority.general;
400 } 378 }
401 if (_requestedParts.isNotEmpty || _partsToAnalyze.isNotEmpty) { 379 if (_requestedParts.isNotEmpty || _partsToAnalyze.isNotEmpty) {
402 return AnalysisDriverPriority.general; 380 return AnalysisDriverPriority.general;
403 } 381 }
404 return AnalysisDriverPriority.nothing; 382 return AnalysisDriverPriority.nothing;
405 } 383 }
406 384
407 /** 385 /**
408 * Add the file with the given [path] to the set of files to analyze. 386 * Add the file with the given [path] to the set of files to analyze.
409 * 387 *
410 * The [path] must be absolute and normalized. 388 * The [path] must be absolute and normalized.
411 * 389 *
412 * The results of analysis are eventually produced by the [results] stream. 390 * The results of analysis are eventually produced by the [results] stream.
413 */ 391 */
414 void addFile(String path) { 392 void addFile(String path) {
415 if (!_fsState.hasUri(path)) { 393 if (!_fileTracker.fsState.hasUri(path)) {
416 return; 394 return;
417 } 395 }
418 if (AnalysisEngine.isDartFileName(path)) { 396 if (AnalysisEngine.isDartFileName(path)) {
419 _addedFiles.add(path); 397 _fileTracker.addFile(path);
420 _filesToAnalyze.add(path);
421 _priorityResults.clear();
422 } 398 }
423 _scheduler._notify(this);
424 } 399 }
425 400
426 /** 401 /**
427 * The file with the given [path] might have changed - updated, added or 402 * The file with the given [path] might have changed - updated, added or
428 * removed. Or not, we don't know. Or it might have, but then changed back. 403 * removed. Or not, we don't know. Or it might have, but then changed back.
429 * 404 *
430 * The [path] must be absolute and normalized. 405 * The [path] must be absolute and normalized.
431 * 406 *
432 * The [path] can be any file - explicitly or implicitly analyzed, or neither. 407 * The [path] can be any file - explicitly or implicitly analyzed, or neither.
433 * 408 *
434 * Causes the analysis state to transition to "analyzing" (if it is not in 409 * Causes the analysis state to transition to "analyzing" (if it is not in
435 * that state already). Schedules the file contents for [path] to be read 410 * that state already). Schedules the file contents for [path] to be read
436 * into the current file state prior to the next time the analysis state 411 * into the current file state prior to the next time the analysis state
437 * transitions to "idle". 412 * transitions to "idle".
438 * 413 *
439 * Invocation of this method will not prevent a [Future] returned from 414 * Invocation of this method will not prevent a [Future] returned from
440 * [getResult] from completing with a result, but the result is not 415 * [getResult] from completing with a result, but the result is not
441 * guaranteed to be consistent with the new current file state after this 416 * guaranteed to be consistent with the new current file state after this
442 * [changeFile] invocation. 417 * [changeFile] invocation.
443 */ 418 */
444 void changeFile(String path) { 419 void changeFile(String path) {
445 _changedFiles.add(path); 420 _fileTracker.changeFile(path);
446 if (_addedFiles.contains(path)) {
447 _filesToAnalyze.add(path);
448 }
449 _priorityResults.clear(); 421 _priorityResults.clear();
450 _scheduler._notify(this);
451 } 422 }
452 423
453 /** 424 /**
454 * Some state on which analysis depends has changed, so the driver needs to be 425 * Some state on which analysis depends has changed, so the driver needs to be
455 * re-configured with the new state. 426 * re-configured with the new state.
456 * 427 *
457 * At least one of the optional parameters should be provided, but only those 428 * At least one of the optional parameters should be provided, but only those
458 * that represent state that has actually changed need be provided. 429 * that represent state that has actually changed need be provided.
459 */ 430 */
460 void configure( 431 void configure(
461 {AnalysisOptions analysisOptions, SourceFactory sourceFactory}) { 432 {AnalysisOptions analysisOptions, SourceFactory sourceFactory}) {
462 if (analysisOptions != null) { 433 if (analysisOptions != null) {
463 _analysisOptions = analysisOptions; 434 _analysisOptions = analysisOptions;
464 } 435 }
465 if (sourceFactory != null) { 436 if (sourceFactory != null) {
466 _sourceFactory = sourceFactory; 437 _sourceFactory = sourceFactory;
467 } 438 }
468 _fillSalt(); 439 var addedFiles = _fileTracker.addedFiles;
scheglov 2017/02/02 21:52:17 Type?
Paul Berry 2017/02/02 22:22:19 Done.
469 _fsState = new FileSystemState(_logger, _byteStore, _contentOverlay, 440 _createFileTracker(_fileTracker.logger);
470 _resourceProvider, _sourceFactory, _analysisOptions, _salt); 441 _fileTracker.addFiles(addedFiles);
471 _filesToAnalyze.addAll(_addedFiles);
472 _scheduler._notify(this);
473 } 442 }
474 443
475 /** 444 /**
476 * Notify the driver that the client is going to stop using it. 445 * Notify the driver that the client is going to stop using it.
477 */ 446 */
478 void dispose() { 447 void dispose() {
479 _scheduler._remove(this); 448 _scheduler._remove(this);
480 } 449 }
481 450
482 /** 451 /**
(...skipping 26 matching lines...) Expand all
509 analysisResult.errors); 478 analysisResult.errors);
510 } 479 }
511 480
512 /** 481 /**
513 * Return a [Future] that completes with the list of added files that 482 * Return a [Future] that completes with the list of added files that
514 * define a class member with the given [name]. 483 * define a class member with the given [name].
515 */ 484 */
516 Future<List<String>> getFilesDefiningClassMemberName(String name) { 485 Future<List<String>> getFilesDefiningClassMemberName(String name) {
517 var task = new _FilesDefiningClassMemberNameTask(this, name); 486 var task = new _FilesDefiningClassMemberNameTask(this, name);
518 _definingClassMemberNameTasks.add(task); 487 _definingClassMemberNameTasks.add(task);
519 _scheduler._notify(this); 488 _scheduler.notify(this);
520 return task.completer.future; 489 return task.completer.future;
521 } 490 }
522 491
523 /** 492 /**
524 * Return a [Future] that completes with the list of added files that 493 * Return a [Future] that completes with the list of added files that
525 * reference the given external [name]. 494 * reference the given external [name].
526 */ 495 */
527 Future<List<String>> getFilesReferencingName(String name) { 496 Future<List<String>> getFilesReferencingName(String name) {
528 var task = new _FilesReferencingNameTask(this, name); 497 var task = new _FilesReferencingNameTask(this, name);
529 _referencingNameTasks.add(task); 498 _referencingNameTasks.add(task);
530 _scheduler._notify(this); 499 _scheduler.notify(this);
531 return task.completer.future; 500 return task.completer.future;
532 } 501 }
533 502
534 /** 503 /**
535 * Return a [Future] that completes with the [AnalysisDriverUnitIndex] for 504 * Return a [Future] that completes with the [AnalysisDriverUnitIndex] for
536 * the file with the given [path], or with `null` if the file cannot be 505 * the file with the given [path], or with `null` if the file cannot be
537 * analyzed. 506 * analyzed.
538 */ 507 */
539 Future<AnalysisDriverUnitIndex> getIndex(String path) { 508 Future<AnalysisDriverUnitIndex> getIndex(String path) {
540 if (!_fsState.hasUri(path)) { 509 if (!_fileTracker.fsState.hasUri(path)) {
541 return new Future.value(); 510 return new Future.value();
542 } 511 }
543 var completer = new Completer<AnalysisDriverUnitIndex>(); 512 var completer = new Completer<AnalysisDriverUnitIndex>();
544 _indexRequestedFiles 513 _indexRequestedFiles
545 .putIfAbsent(path, () => <Completer<AnalysisDriverUnitIndex>>[]) 514 .putIfAbsent(path, () => <Completer<AnalysisDriverUnitIndex>>[])
546 .add(completer); 515 .add(completer);
547 _scheduler._notify(this); 516 _scheduler.notify(this);
548 return completer.future; 517 return completer.future;
549 } 518 }
550 519
551 /** 520 /**
552 * Return a [Future] that completes with a [AnalysisResult] for the Dart 521 * Return a [Future] that completes with a [AnalysisResult] for the Dart
553 * file with the given [path]. If the file is not a Dart file or cannot 522 * file with the given [path]. If the file is not a Dart file or cannot
554 * be analyzed, the [Future] completes with `null`. 523 * be analyzed, the [Future] completes with `null`.
555 * 524 *
556 * The [path] must be absolute and normalized. 525 * The [path] must be absolute and normalized.
557 * 526 *
558 * The [path] can be any file - explicitly or implicitly analyzed, or neither. 527 * The [path] can be any file - explicitly or implicitly analyzed, or neither.
559 * 528 *
560 * If the driver has the cached analysis result for the file, it is returned. 529 * If the driver has the cached analysis result for the file, it is returned.
561 * 530 *
562 * Otherwise causes the analysis state to transition to "analyzing" (if it is 531 * Otherwise causes the analysis state to transition to "analyzing" (if it is
563 * not in that state already), the driver will read the file and produce the 532 * not in that state already), the driver will read the file and produce the
564 * analysis result for it, which is consistent with the current file state 533 * analysis result for it, which is consistent with the current file state
565 * (including the new state of the file), prior to the next time the analysis 534 * (including the new state of the file), prior to the next time the analysis
566 * state transitions to "idle". 535 * state transitions to "idle".
567 */ 536 */
568 Future<AnalysisResult> getResult(String path) { 537 Future<AnalysisResult> getResult(String path) {
569 if (!_fsState.hasUri(path)) { 538 if (!_fileTracker.fsState.hasUri(path)) {
570 return new Future.value(); 539 return new Future.value();
571 } 540 }
572 541
573 // Return the cached result. 542 // Return the cached result.
574 { 543 {
575 AnalysisResult result = _priorityResults[path]; 544 AnalysisResult result = _priorityResults[path];
576 if (result != null) { 545 if (result != null) {
577 return new Future.value(result); 546 return new Future.value(result);
578 } 547 }
579 } 548 }
580 549
581 // Schedule analysis. 550 // Schedule analysis.
582 var completer = new Completer<AnalysisResult>(); 551 var completer = new Completer<AnalysisResult>();
583 _requestedFiles 552 _requestedFiles
584 .putIfAbsent(path, () => <Completer<AnalysisResult>>[]) 553 .putIfAbsent(path, () => <Completer<AnalysisResult>>[])
585 .add(completer); 554 .add(completer);
586 _scheduler._notify(this); 555 _scheduler.notify(this);
587 return completer.future; 556 return completer.future;
588 } 557 }
589 558
590 /** 559 /**
591 * Return a [Future] that completes with the [SourceKind] for the Dart 560 * Return a [Future] that completes with the [SourceKind] for the Dart
592 * file with the given [path]. If the file is not a Dart file or cannot 561 * file with the given [path]. If the file is not a Dart file or cannot
593 * be analyzed, the [Future] completes with `null`. 562 * be analyzed, the [Future] completes with `null`.
594 * 563 *
595 * The [path] must be absolute and normalized. 564 * The [path] must be absolute and normalized.
596 */ 565 */
597 Future<SourceKind> getSourceKind(String path) async { 566 Future<SourceKind> getSourceKind(String path) async {
598 if (AnalysisEngine.isDartFileName(path)) { 567 if (AnalysisEngine.isDartFileName(path)) {
599 FileState file = _fsState.getFileForPath(path); 568 FileState file = _fileTracker.fsState.getFileForPath(path);
600 return file.isPart ? SourceKind.PART : SourceKind.LIBRARY; 569 return file.isPart ? SourceKind.PART : SourceKind.LIBRARY;
601 } 570 }
602 return null; 571 return null;
603 } 572 }
604 573
605 /** 574 /**
606 * Return a [Future] that completes with top-level declarations with the 575 * Return a [Future] that completes with top-level declarations with the
607 * given [name] in all known libraries. 576 * given [name] in all known libraries.
608 */ 577 */
609 Future<List<TopLevelDeclarationInSource>> getTopLevelNameDeclarations( 578 Future<List<TopLevelDeclarationInSource>> getTopLevelNameDeclarations(
610 String name) { 579 String name) {
611 var task = new _TopLevelNameDeclarationsTask(this, name); 580 var task = new _TopLevelNameDeclarationsTask(this, name);
612 _topLevelNameDeclarationsTasks.add(task); 581 _topLevelNameDeclarationsTasks.add(task);
613 _scheduler._notify(this); 582 _scheduler.notify(this);
614 return task.completer.future; 583 return task.completer.future;
615 } 584 }
616 585
617 /** 586 /**
618 * Return a [Future] that completes with the [CompilationUnitElement] for the 587 * Return a [Future] that completes with the [CompilationUnitElement] for the
619 * file with the given [path], or with `null` if the file cannot be analyzed. 588 * file with the given [path], or with `null` if the file cannot be analyzed.
620 */ 589 */
621 Future<CompilationUnitElement> getUnitElement(String path) { 590 Future<CompilationUnitElement> getUnitElement(String path) {
622 if (!_fsState.hasUri(path)) { 591 if (!_fileTracker.fsState.hasUri(path)) {
623 return new Future.value(); 592 return new Future.value();
624 } 593 }
625 var completer = new Completer<CompilationUnitElement>(); 594 var completer = new Completer<CompilationUnitElement>();
626 _unitElementRequestedFiles 595 _unitElementRequestedFiles
627 .putIfAbsent(path, () => <Completer<CompilationUnitElement>>[]) 596 .putIfAbsent(path, () => <Completer<CompilationUnitElement>>[])
628 .add(completer); 597 .add(completer);
629 _scheduler._notify(this); 598 _scheduler.notify(this);
630 return completer.future; 599 return completer.future;
631 } 600 }
632 601
633 /** 602 /**
634 * Return a [Future] that completes with a [ParseResult] for the file 603 * Return a [Future] that completes with a [ParseResult] for the file
635 * with the given [path]. 604 * with the given [path].
636 * 605 *
637 * The [path] must be absolute and normalized. 606 * The [path] must be absolute and normalized.
638 * 607 *
639 * The [path] can be any file - explicitly or implicitly analyzed, or neither. 608 * The [path] can be any file - explicitly or implicitly analyzed, or neither.
640 * 609 *
641 * The parsing is performed in the method itself, and the result is not 610 * The parsing is performed in the method itself, and the result is not
642 * produced through the [results] stream (just because it is not a fully 611 * produced through the [results] stream (just because it is not a fully
643 * resolved unit). 612 * resolved unit).
644 */ 613 */
645 Future<ParseResult> parseFile(String path) async { 614 Future<ParseResult> parseFile(String path) async {
646 FileState file = _verifyApiSignature(path); 615 FileState file = _fileTracker.verifyApiSignature(path);
647 RecordingErrorListener listener = new RecordingErrorListener(); 616 RecordingErrorListener listener = new RecordingErrorListener();
648 CompilationUnit unit = file.parse(listener); 617 CompilationUnit unit = file.parse(listener);
649 return new ParseResult(file.path, file.uri, file.content, file.contentHash, 618 return new ParseResult(file.path, file.uri, file.content, file.contentHash,
650 unit.lineInfo, unit, listener.errors); 619 unit.lineInfo, unit, listener.errors);
651 } 620 }
652 621
653 /** 622 /**
654 * Remove the file with the given [path] from the list of files to analyze. 623 * Remove the file with the given [path] from the list of files to analyze.
655 * 624 *
656 * The [path] must be absolute and normalized. 625 * The [path] must be absolute and normalized.
657 * 626 *
658 * The results of analysis of the file might still be produced by the 627 * The results of analysis of the file might still be produced by the
659 * [results] stream. The driver will try to stop producing these results, 628 * [results] stream. The driver will try to stop producing these results,
660 * but does not guarantee this. 629 * but does not guarantee this.
661 */ 630 */
662 void removeFile(String path) { 631 void removeFile(String path) {
663 _addedFiles.remove(path); 632 _fileTracker.removeFile(path);
664 _filesToAnalyze.remove(path);
665 _fsState.removeFile(path);
666 _filesToAnalyze.addAll(_addedFiles);
667 _priorityResults.clear(); 633 _priorityResults.clear();
668 _scheduler._notify(this);
669 } 634 }
670 635
671 /** 636 /**
637 * Handles a notification from the [FileTracker] that there has been a change
638 * of state.
639 */
640 void _changeHook() {
641 _priorityResults.clear();
642 _scheduler.notify(this);
643 }
644
645 /**
672 * Return the cached or newly computed analysis result of the file with the 646 * Return the cached or newly computed analysis result of the file with the
673 * given [path]. 647 * given [path].
674 * 648 *
675 * The result will have the fully resolved unit and will always be newly 649 * The result will have the fully resolved unit and will always be newly
676 * compute only if [withUnit] is `true`. 650 * compute only if [withUnit] is `true`.
677 * 651 *
678 * Return `null` if the file is a part of an unknown library, so cannot be 652 * Return `null` if the file is a part of an unknown library, so cannot be
679 * analyzed yet. But [asIsIfPartWithoutLibrary] is `true`, then the file is 653 * analyzed yet. But [asIsIfPartWithoutLibrary] is `true`, then the file is
680 * analyzed anyway, even without a library. 654 * analyzed anyway, even without a library.
681 */ 655 */
682 AnalysisResult _computeAnalysisResult(String path, 656 AnalysisResult _computeAnalysisResult(String path,
683 {bool withUnit: false, bool asIsIfPartWithoutLibrary: false}) { 657 {bool withUnit: false, bool asIsIfPartWithoutLibrary: false}) {
684 /** 658 /**
685 * If the [file] is a library, return the [file] itself. 659 * If the [file] is a library, return the [file] itself.
686 * If the [file] is a part, return a library it is known to be a part of. 660 * If the [file] is a part, return a library it is known to be a part of.
687 * If there is no such library, return `null`. 661 * If there is no such library, return `null`.
688 */ 662 */
689 FileState getLibraryFile(FileState file) { 663 FileState getLibraryFile(FileState file) {
690 FileState libraryFile = file.isPart ? file.library : file; 664 FileState libraryFile = file.isPart ? file.library : file;
691 if (libraryFile == null && asIsIfPartWithoutLibrary) { 665 if (libraryFile == null && asIsIfPartWithoutLibrary) {
692 libraryFile = file; 666 libraryFile = file;
693 } 667 }
694 return libraryFile; 668 return libraryFile;
695 } 669 }
696 670
697 // If we don't need the fully resolved unit, check for the cached result. 671 // If we don't need the fully resolved unit, check for the cached result.
698 if (!withUnit) { 672 if (!withUnit) {
699 FileState file = _fsState.getFileForPath(path); 673 FileState file = _fileTracker.fsState.getFileForPath(path);
700 674
701 // Prepare the library file - the file itself, or the known library. 675 // Prepare the library file - the file itself, or the known library.
702 FileState libraryFile = getLibraryFile(file); 676 FileState libraryFile = getLibraryFile(file);
703 if (libraryFile == null) { 677 if (libraryFile == null) {
704 return null; 678 return null;
705 } 679 }
706 680
707 // Check for the cached result. 681 // Check for the cached result.
708 String key = _getResolvedUnitKey(libraryFile, file); 682 String key = _getResolvedUnitKey(libraryFile, file);
709 List<int> bytes = _byteStore.get(key); 683 List<int> bytes = _byteStore.get(key);
710 if (bytes != null) { 684 if (bytes != null) {
711 return _getAnalysisResultFromBytes(file, bytes); 685 return _getAnalysisResultFromBytes(file, bytes);
712 } 686 }
713 } 687 }
714 688
715 // We need the fully resolved unit, or the result is not cached. 689 // We need the fully resolved unit, or the result is not cached.
716 return _logger.run('Compute analysis result for $path', () { 690 return _fileTracker.logger.run('Compute analysis result for $path', () {
scheglov 2017/02/02 21:52:17 Accessing logger from _fileTracker seems a bit cum
Paul Berry 2017/02/02 22:22:19 Done.
717 FileState file = _verifyApiSignature(path); 691 FileState file = _fileTracker.verifyApiSignature(path);
718 692
719 // Prepare the library file - the file itself, or the known library. 693 // Prepare the library file - the file itself, or the known library.
720 FileState libraryFile = getLibraryFile(file); 694 FileState libraryFile = getLibraryFile(file);
721 if (libraryFile == null) { 695 if (libraryFile == null) {
722 return null; 696 return null;
723 } 697 }
724 698
725 try { 699 try {
726 LibraryContext libraryContext = _createLibraryContext(libraryFile); 700 LibraryContext libraryContext = _createLibraryContext(libraryFile);
727 try { 701 try {
(...skipping 15 matching lines...) Expand all
743 message: error.message, 717 message: error.message,
744 correction: error.correction)) 718 correction: error.correction))
745 .toList(), 719 .toList(),
746 index: index) 720 index: index)
747 .toBuffer(); 721 .toBuffer();
748 String key = _getResolvedUnitKey(libraryFile, file); 722 String key = _getResolvedUnitKey(libraryFile, file);
749 _byteStore.put(key, bytes); 723 _byteStore.put(key, bytes);
750 } 724 }
751 725
752 // Return the result, full or partial. 726 // Return the result, full or partial.
753 _logger.writeln('Computed new analysis result.'); 727 _fileTracker.logger.writeln('Computed new analysis result.');
754 AnalysisResult result = _getAnalysisResultFromBytes(file, bytes, 728 AnalysisResult result = _getAnalysisResultFromBytes(file, bytes,
755 content: withUnit ? file.content : null, 729 content: withUnit ? file.content : null,
756 withErrors: _addedFiles.contains(path), 730 withErrors: _fileTracker.addedFiles.contains(path),
757 resolvedUnit: withUnit ? resolvedUnit : null); 731 resolvedUnit: withUnit ? resolvedUnit : null);
758 if (withUnit && _priorityFiles.contains(path)) { 732 if (withUnit && _priorityFiles.contains(path)) {
759 _priorityResults[path] = result; 733 _priorityResults[path] = result;
760 } 734 }
761 return result; 735 return result;
762 } finally { 736 } finally {
763 libraryContext.dispose(); 737 libraryContext.dispose();
764 } 738 }
765 } catch (exception, stackTrace) { 739 } catch (exception, stackTrace) {
766 String contextKey = 740 String contextKey =
767 _storeExceptionContext(path, libraryFile, exception, stackTrace); 741 _storeExceptionContext(path, libraryFile, exception, stackTrace);
768 throw new _ExceptionState(exception, stackTrace, contextKey); 742 throw new _ExceptionState(exception, stackTrace, contextKey);
769 } 743 }
770 }); 744 });
771 } 745 }
772 746
773 AnalysisDriverUnitIndex _computeIndex(String path) { 747 AnalysisDriverUnitIndex _computeIndex(String path) {
774 AnalysisResult analysisResult = _computeAnalysisResult(path, 748 AnalysisResult analysisResult = _computeAnalysisResult(path,
775 withUnit: false, asIsIfPartWithoutLibrary: true); 749 withUnit: false, asIsIfPartWithoutLibrary: true);
776 return analysisResult._index; 750 return analysisResult._index;
777 } 751 }
778 752
779 CompilationUnitElement _computeUnitElement(String path) { 753 CompilationUnitElement _computeUnitElement(String path) {
780 FileState file = _fsState.getFileForPath(path); 754 FileState file = _fileTracker.fsState.getFileForPath(path);
781 FileState libraryFile = file.library ?? file; 755 FileState libraryFile = file.library ?? file;
782 756
783 // Create the AnalysisContext to resynthesize elements in. 757 // Create the AnalysisContext to resynthesize elements in.
784 LibraryContext libraryContext = _createLibraryContext(libraryFile); 758 LibraryContext libraryContext = _createLibraryContext(libraryFile);
785 759
786 // Resynthesize the CompilationUnitElement in the context. 760 // Resynthesize the CompilationUnitElement in the context.
787 try { 761 try {
788 return libraryContext.computeUnitElement(libraryFile.source, file.source); 762 return libraryContext.computeUnitElement(libraryFile.source, file.source);
789 } finally { 763 } finally {
790 libraryContext.dispose(); 764 libraryContext.dispose();
791 } 765 }
792 } 766 }
793 767
794 /** 768 /**
769 * Creates a new [FileTracker] object and stores it in [_fileTracker].
770 *
771 * This is used both on initial construction and whenever the configuration
772 * changes.
773 */
774 void _createFileTracker(PerformanceLog logger) {
775 _fillSalt();
776 _fileTracker = new FileTracker(logger, _byteStore, _contentOverlay,
777 _resourceProvider, sourceFactory, _analysisOptions, _salt, _changeHook);
778 }
779
780 /**
795 * Return the context in which the [library] should be analyzed. 781 * Return the context in which the [library] should be analyzed.
796 */ 782 */
797 LibraryContext _createLibraryContext(FileState library) => 783 LibraryContext _createLibraryContext(FileState library) =>
798 new LibraryContext.forSingleLibrary( 784 new LibraryContext.forSingleLibrary(
799 library, 785 library,
800 _logger, 786 _fileTracker.logger,
801 _sdkBundle, 787 _sdkBundle,
802 _byteStore, 788 _byteStore,
803 _analysisOptions, 789 _analysisOptions,
804 declaredVariables, 790 declaredVariables,
805 _sourceFactory, 791 _sourceFactory,
806 _fsState); 792 _fileTracker);
807 793
808 /** 794 /**
809 * Fill [_salt] with data. 795 * Fill [_salt] with data.
810 */ 796 */
811 void _fillSalt() { 797 void _fillSalt() {
812 _salt[0] = DATA_VERSION; 798 _salt[0] = DATA_VERSION;
813 List<int> crossContextOptions = _analysisOptions.signature; 799 List<int> crossContextOptions = _analysisOptions.signature;
814 assert(crossContextOptions.length == AnalysisOptions.signatureLength); 800 assert(crossContextOptions.length == AnalysisOptions.signatureLength);
815 for (int i = 0; i < crossContextOptions.length; i++) { 801 for (int i = 0; i < crossContextOptions.length; i++) {
816 _salt[i + 1] = crossContextOptions[i]; 802 _salt[i + 1] = crossContextOptions[i];
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
889 } 875 }
890 } 876 }
891 } 877 }
892 return null; 878 return null;
893 } 879 }
894 880
895 /** 881 /**
896 * Perform a single chunk of work and produce [results]. 882 * Perform a single chunk of work and produce [results].
897 */ 883 */
898 Future<Null> _performWork() async { 884 Future<Null> _performWork() async {
899 // Verify all changed files one at a time. 885 if (_fileTracker.verifyChangedFilesIfNeeded()) {
900 if (_changedFiles.isNotEmpty) {
901 String path = _removeFirst(_changedFiles);
902 // If the file has not been accessed yet, we either will eventually read
903 // it later while analyzing one of the added files, or don't need it.
904 if (_fsState.knownFilePaths.contains(path)) {
905 _verifyApiSignature(path);
906 }
907 return; 886 return;
908 } 887 }
909 888
910 // Analyze a requested file. 889 // Analyze a requested file.
911 if (_requestedFiles.isNotEmpty) { 890 if (_requestedFiles.isNotEmpty) {
912 String path = _requestedFiles.keys.first; 891 String path = _requestedFiles.keys.first;
913 try { 892 try {
914 AnalysisResult result = _computeAnalysisResult(path, withUnit: true); 893 AnalysisResult result = _computeAnalysisResult(path, withUnit: true);
915 // If a part without a library, delay its analysis. 894 // If a part without a library, delay its analysis.
916 if (result == null) { 895 if (result == null) {
917 _requestedParts 896 _requestedParts
918 .putIfAbsent(path, () => []) 897 .putIfAbsent(path, () => [])
919 .addAll(_requestedFiles.remove(path)); 898 .addAll(_requestedFiles.remove(path));
920 return; 899 return;
921 } 900 }
922 // Notify the completers. 901 // Notify the completers.
923 _requestedFiles.remove(path).forEach((completer) { 902 _requestedFiles.remove(path).forEach((completer) {
924 completer.complete(result); 903 completer.complete(result);
925 }); 904 });
926 // Remove from to be analyzed and produce it now. 905 // Remove from to be analyzed and produce it now.
927 _filesToAnalyze.remove(path);
928 _resultController.add(result); 906 _resultController.add(result);
929 } catch (exception, stackTrace) { 907 } catch (exception, stackTrace) {
930 _filesToAnalyze.remove(path);
931 _requestedFiles.remove(path).forEach((completer) { 908 _requestedFiles.remove(path).forEach((completer) {
932 completer.completeError(exception, stackTrace); 909 completer.completeError(exception, stackTrace);
933 }); 910 });
911 } finally {
912 _fileTracker.fileWasAnalyzed(path);
scheglov 2017/02/02 21:52:17 This code will be executed even if result == null,
Paul Berry 2017/02/02 22:22:19 Ah, I see. Good catch. Fixed.
934 } 913 }
935 return; 914 return;
936 } 915 }
937 916
938 // Process an index request. 917 // Process an index request.
939 if (_indexRequestedFiles.isNotEmpty) { 918 if (_indexRequestedFiles.isNotEmpty) {
940 String path = _indexRequestedFiles.keys.first; 919 String path = _indexRequestedFiles.keys.first;
941 AnalysisDriverUnitIndex index = _computeIndex(path); 920 AnalysisDriverUnitIndex index = _computeIndex(path);
942 _indexRequestedFiles.remove(path).forEach((completer) { 921 _indexRequestedFiles.remove(path).forEach((completer) {
943 completer.complete(index); 922 completer.complete(index);
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
982 bool isDone = await task.perform(); 961 bool isDone = await task.perform();
983 if (isDone) { 962 if (isDone) {
984 _topLevelNameDeclarationsTasks.remove(task); 963 _topLevelNameDeclarationsTasks.remove(task);
985 } 964 }
986 return; 965 return;
987 } 966 }
988 967
989 // Analyze a priority file. 968 // Analyze a priority file.
990 if (_priorityFiles.isNotEmpty) { 969 if (_priorityFiles.isNotEmpty) {
991 for (String path in _priorityFiles) { 970 for (String path in _priorityFiles) {
992 if (_filesToAnalyze.remove(path)) { 971 if (_fileTracker.isFilePending(path)) {
993 try { 972 try {
994 AnalysisResult result = 973 AnalysisResult result =
995 _computeAnalysisResult(path, withUnit: true); 974 _computeAnalysisResult(path, withUnit: true);
996 if (result == null) { 975 if (result == null) {
997 _partsToAnalyze.add(path); 976 _partsToAnalyze.add(path);
998 } else { 977 } else {
999 _resultController.add(result); 978 _resultController.add(result);
1000 } 979 }
1001 } catch (exception, stackTrace) { 980 } catch (exception, stackTrace) {
1002 _reportException(path, exception, stackTrace); 981 _reportException(path, exception, stackTrace);
982 } finally {
983 _fileTracker.fileWasAnalyzed(path);
1003 } 984 }
1004 return; 985 return;
1005 } 986 }
1006 } 987 }
1007 } 988 }
1008 989
1009 // Analyze a general file. 990 if (_fileTracker.hasPendingFiles) {
1010 if (_filesToAnalyze.isNotEmpty) { 991 // Analyze a general file.
1011 String path = _removeFirst(_filesToAnalyze); 992 String path = _fileTracker.anyPendingFile;
1012 try { 993 try {
1013 AnalysisResult result = _computeAnalysisResult(path, withUnit: false); 994 AnalysisResult result = _computeAnalysisResult(path, withUnit: false);
1014 if (result == null) { 995 if (result == null) {
1015 _partsToAnalyze.add(path); 996 _partsToAnalyze.add(path);
1016 } else { 997 } else {
1017 _resultController.add(result); 998 _resultController.add(result);
1018 } 999 }
1019 } catch (exception, stackTrace) { 1000 } catch (exception, stackTrace) {
1020 _reportException(path, exception, stackTrace); 1001 _reportException(path, exception, stackTrace);
1002 } finally {
1003 _fileTracker.fileWasAnalyzed(path);
1021 } 1004 }
1022 return; 1005 return;
1023 } 1006 }
1024 1007
1025 // Analyze a requested part file. 1008 // Analyze a requested part file.
1026 if (_requestedParts.isNotEmpty) { 1009 if (_requestedParts.isNotEmpty) {
1027 String path = _requestedParts.keys.first; 1010 String path = _requestedParts.keys.first;
1028 try { 1011 try {
1029 AnalysisResult result = _computeAnalysisResult(path, 1012 AnalysisResult result = _computeAnalysisResult(path,
1030 withUnit: true, asIsIfPartWithoutLibrary: true); 1013 withUnit: true, asIsIfPartWithoutLibrary: true);
1031 // Notify the completers. 1014 // Notify the completers.
1032 _requestedParts.remove(path).forEach((completer) { 1015 _requestedParts.remove(path).forEach((completer) {
1033 completer.complete(result); 1016 completer.complete(result);
1034 }); 1017 });
1035 // Remove from to be analyzed and produce it now. 1018 // Remove from to be analyzed and produce it now.
1036 _partsToAnalyze.remove(path); 1019 _partsToAnalyze.remove(path);
1037 _resultController.add(result); 1020 _resultController.add(result);
1038 } catch (exception, stackTrace) { 1021 } catch (exception, stackTrace) {
1039 _partsToAnalyze.remove(path); 1022 _partsToAnalyze.remove(path);
1040 _requestedParts.remove(path).forEach((completer) { 1023 _requestedParts.remove(path).forEach((completer) {
1041 completer.completeError(exception, stackTrace); 1024 completer.completeError(exception, stackTrace);
1042 }); 1025 });
1043 } 1026 }
1044 return; 1027 return;
1045 } 1028 }
1046 1029
1047 // Analyze a general part. 1030 // Analyze a general part.
1048 if (_partsToAnalyze.isNotEmpty) { 1031 if (_partsToAnalyze.isNotEmpty) {
1049 String path = _removeFirst(_partsToAnalyze); 1032 String path = _partsToAnalyze.first;
1033 _partsToAnalyze.remove(path);
1050 try { 1034 try {
1051 AnalysisResult result = _computeAnalysisResult(path, 1035 AnalysisResult result = _computeAnalysisResult(path,
1052 withUnit: _priorityFiles.contains(path), 1036 withUnit: _priorityFiles.contains(path),
1053 asIsIfPartWithoutLibrary: true); 1037 asIsIfPartWithoutLibrary: true);
1054 _resultController.add(result); 1038 _resultController.add(result);
1055 } catch (exception, stackTrace) { 1039 } catch (exception, stackTrace) {
1056 _reportException(path, exception, stackTrace); 1040 _reportException(path, exception, stackTrace);
1057 } 1041 }
1058 return; 1042 return;
1059 } 1043 }
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
1112 String sec = _twoDigits(time.second); 1096 String sec = _twoDigits(time.second);
1113 String ms = _threeDigits(time.millisecond); 1097 String ms = _threeDigits(time.millisecond);
1114 String key = 'exception_${time.year}$m$d' '_$h$min$sec' + '_$ms'; 1098 String key = 'exception_${time.year}$m$d' '_$h$min$sec' + '_$ms';
1115 1099
1116 _byteStore.put(key, bytes); 1100 _byteStore.put(key, bytes);
1117 return key; 1101 return key;
1118 } catch (_) { 1102 } catch (_) {
1119 return null; 1103 return null;
1120 } 1104 }
1121 } 1105 }
1122
1123 /**
1124 * Verify the API signature for the file with the given [path], and decide
1125 * which linked libraries should be invalidated, and files reanalyzed.
1126 */
1127 FileState _verifyApiSignature(String path) {
1128 return _logger.run('Verify API signature of $path', () {
1129 bool anyApiChanged = false;
1130 List<FileState> files = _fsState.getFilesForPath(path);
1131 for (FileState file in files) {
1132 bool apiChanged = file.refresh();
1133 if (apiChanged) {
1134 anyApiChanged = true;
1135 }
1136 }
1137 if (anyApiChanged) {
1138 _logger.writeln('API signatures mismatch found for $path');
1139 // TODO(scheglov) schedule analysis of only affected files
1140 _filesToAnalyze.addAll(_addedFiles);
1141 }
1142 return files[0];
1143 });
1144 }
1145
1146 /**
1147 * Remove and return the first item in the given [set].
1148 */
1149 static Object/*=T*/ _removeFirst/*<T>*/(LinkedHashSet<Object/*=T*/ > set) {
1150 Object/*=T*/ element = set.first;
1151 set.remove(element);
1152 return element;
1153 }
1154 } 1106 }
1155 1107
1156 /** 1108 /**
1157 * Priorities of [AnalysisDriver] work. The farther a priority to the beginning 1109 * Priorities of [AnalysisDriver] work. The farther a priority to the beginning
1158 * of the list, the earlier the corresponding [AnalysisDriver] should be asked 1110 * of the list, the earlier the corresponding [AnalysisDriver] should be asked
1159 * to perform work. 1111 * to perform work.
1160 */ 1112 */
1161 enum AnalysisDriverPriority { nothing, general, priority, interactive } 1113 enum AnalysisDriverPriority { nothing, general, priority, interactive }
1162 1114
1163 /** 1115 /**
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
1211 bool get _hasFilesToAnalyze { 1163 bool get _hasFilesToAnalyze {
1212 for (AnalysisDriver driver in _drivers) { 1164 for (AnalysisDriver driver in _drivers) {
1213 if (driver.hasFilesToAnalyze) { 1165 if (driver.hasFilesToAnalyze) {
1214 return true; 1166 return true;
1215 } 1167 }
1216 } 1168 }
1217 return false; 1169 return false;
1218 } 1170 }
1219 1171
1220 /** 1172 /**
1173 * Notify that there is a change to the [driver], it it might need to
1174 * perform some work.
1175 */
1176 void notify(AnalysisDriver driver) {
1177 _hasWork.notify();
1178 _statusSupport.preTransitionToAnalyzing();
1179 }
1180
1181 /**
1221 * Start the scheduler, so that any [AnalysisDriver] created before or 1182 * Start the scheduler, so that any [AnalysisDriver] created before or
1222 * after will be asked to perform work. 1183 * after will be asked to perform work.
1223 */ 1184 */
1224 void start() { 1185 void start() {
1225 if (_started) { 1186 if (_started) {
1226 throw new StateError('The scheduler has already been started.'); 1187 throw new StateError('The scheduler has already been started.');
1227 } 1188 }
1228 _started = true; 1189 _started = true;
1229 _run(); 1190 _run();
1230 } 1191 }
1231 1192
1232 /** 1193 /**
1233 * Return a future that will be completed the next time the status is idle. 1194 * Return a future that will be completed the next time the status is idle.
1234 * 1195 *
1235 * If the status is currently idle, the returned future will be signaled 1196 * If the status is currently idle, the returned future will be signaled
1236 * immediately. 1197 * immediately.
1237 */ 1198 */
1238 Future<Null> waitForIdle() => _statusSupport.waitForIdle(); 1199 Future<Null> waitForIdle() => _statusSupport.waitForIdle();
1239 1200
1240 /** 1201 /**
1241 * Add the given [driver] and schedule it to perform its work. 1202 * Add the given [driver] and schedule it to perform its work.
1242 */ 1203 */
1243 void _add(AnalysisDriver driver) { 1204 void _add(AnalysisDriver driver) {
1244 _drivers.add(driver); 1205 _drivers.add(driver);
1245 _hasWork.notify(); 1206 _hasWork.notify();
1246 } 1207 }
1247 1208
1248 /** 1209 /**
1249 * Notify that there is a change to the [driver], it it might need to
1250 * perform some work.
1251 */
1252 void _notify(AnalysisDriver driver) {
1253 _hasWork.notify();
1254 _statusSupport.preTransitionToAnalyzing();
1255 }
1256
1257 /**
1258 * Remove the given [driver] from the scheduler, so that it will not be 1210 * Remove the given [driver] from the scheduler, so that it will not be
1259 * asked to perform any new work. 1211 * asked to perform any new work.
1260 */ 1212 */
1261 void _remove(AnalysisDriver driver) { 1213 void _remove(AnalysisDriver driver) {
1262 _drivers.remove(driver); 1214 _drivers.remove(driver);
1263 _hasWork.notify(); 1215 _hasWork.notify();
1264 } 1216 }
1265 1217
1266 /** 1218 /**
1267 * Run infinitely analysis cycle, selecting the drivers with the highest 1219 * Run infinitely analysis cycle, selecting the drivers with the highest
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
1327 return new Future.delayed(Duration.ZERO, () => _pumpEventQueue(times - 1)); 1279 return new Future.delayed(Duration.ZERO, () => _pumpEventQueue(times - 1));
1328 } 1280 }
1329 } 1281 }
1330 1282
1331 @visibleForTesting 1283 @visibleForTesting
1332 class AnalysisDriverTestView { 1284 class AnalysisDriverTestView {
1333 final AnalysisDriver driver; 1285 final AnalysisDriver driver;
1334 1286
1335 AnalysisDriverTestView(this.driver); 1287 AnalysisDriverTestView(this.driver);
1336 1288
1337 Set<String> get filesToAnalyze => driver._filesToAnalyze; 1289 FileTracker get fileTracker => driver._fileTracker;
1338 1290
1339 Map<String, AnalysisResult> get priorityResults => driver._priorityResults; 1291 Map<String, AnalysisResult> get priorityResults => driver._priorityResults;
1340 } 1292 }
1341 1293
1342 /** 1294 /**
1343 * The result of analyzing of a single file. 1295 * The result of analyzing of a single file.
1344 * 1296 *
1345 * These results are self-consistent, i.e. [content], [contentHash], the 1297 * These results are self-consistent, i.e. [content], [contentHash], the
1346 * resolved [unit] correspond to each other. All referenced elements, even 1298 * resolved [unit] correspond to each other. All referenced elements, even
1347 * external ones, are also self-consistent. But none of the results is 1299 * external ones, are also self-consistent. But none of the results is
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after
1665 } 1617 }
1666 1618
1667 // If no more files to check, complete and done. 1619 // If no more files to check, complete and done.
1668 if (filesToCheck.isEmpty) { 1620 if (filesToCheck.isEmpty) {
1669 completer.complete(definingFiles); 1621 completer.complete(definingFiles);
1670 return true; 1622 return true;
1671 } 1623 }
1672 1624
1673 // Check the next file. 1625 // Check the next file.
1674 String path = filesToCheck.removeLast(); 1626 String path = filesToCheck.removeLast();
1675 FileState file = driver._fsState.getFileForPath(path); 1627 FileState file = driver._fileTracker.fsState.getFileForPath(path);
1676 if (file.definedClassMemberNames.contains(name)) { 1628 if (file.definedClassMemberNames.contains(name)) {
1677 definingFiles.add(path); 1629 definingFiles.add(path);
1678 } 1630 }
1679 checkedFiles.add(path); 1631 checkedFiles.add(path);
1680 } 1632 }
1681 1633
1682 // We're not done yet. 1634 // We're not done yet.
1683 return false; 1635 return false;
1684 } 1636 }
1685 } 1637 }
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
1722 } 1674 }
1723 1675
1724 // If no more files to check, complete and done. 1676 // If no more files to check, complete and done.
1725 if (filesToCheck.isEmpty) { 1677 if (filesToCheck.isEmpty) {
1726 completer.complete(referencingFiles); 1678 completer.complete(referencingFiles);
1727 return true; 1679 return true;
1728 } 1680 }
1729 1681
1730 // Check the next file. 1682 // Check the next file.
1731 String path = filesToCheck.removeLast(); 1683 String path = filesToCheck.removeLast();
1732 FileState file = driver._fsState.getFileForPath(path); 1684 FileState file = driver._fileTracker.fsState.getFileForPath(path);
1733 if (file.referencedNames.contains(name)) { 1685 if (file.referencedNames.contains(name)) {
1734 referencingFiles.add(path); 1686 referencingFiles.add(path);
1735 } 1687 }
1736 checkedFiles.add(path); 1688 checkedFiles.add(path);
1737 } 1689 }
1738 1690
1739 // We're not done yet. 1691 // We're not done yet.
1740 return false; 1692 return false;
1741 } 1693 }
1742 } 1694 }
(...skipping 29 matching lines...) Expand all
1772 1724
1773 // If no more files to check, complete and done. 1725 // If no more files to check, complete and done.
1774 if (filesToCheck.isEmpty) { 1726 if (filesToCheck.isEmpty) {
1775 completer.complete(libraryDeclarations); 1727 completer.complete(libraryDeclarations);
1776 return true; 1728 return true;
1777 } 1729 }
1778 1730
1779 // Check the next file. 1731 // Check the next file.
1780 String path = filesToCheck.removeLast(); 1732 String path = filesToCheck.removeLast();
1781 if (checkedFiles.add(path)) { 1733 if (checkedFiles.add(path)) {
1782 FileState file = driver._fsState.getFileForPath(path); 1734 FileState file = driver._fileTracker.fsState.getFileForPath(path);
1783 if (!file.isPart) { 1735 if (!file.isPart) {
1784 bool isExported = false; 1736 bool isExported = false;
1785 TopLevelDeclaration declaration = file.topLevelDeclarations[name]; 1737 TopLevelDeclaration declaration = file.topLevelDeclarations[name];
1786 for (FileState part in file.partedFiles) { 1738 for (FileState part in file.partedFiles) {
1787 declaration ??= part.topLevelDeclarations[name]; 1739 declaration ??= part.topLevelDeclarations[name];
1788 } 1740 }
1789 if (declaration == null) { 1741 if (declaration == null) {
1790 declaration = file.exportedTopLevelDeclarations[name]; 1742 declaration = file.exportedTopLevelDeclarations[name];
1791 isExported = true; 1743 isExported = true;
1792 } 1744 }
1793 if (declaration != null) { 1745 if (declaration != null) {
1794 libraryDeclarations.add(new TopLevelDeclarationInSource( 1746 libraryDeclarations.add(new TopLevelDeclarationInSource(
1795 file.source, declaration, isExported)); 1747 file.source, declaration, isExported));
1796 } 1748 }
1797 } 1749 }
1798 } 1750 }
1799 1751
1800 // We're not done yet. 1752 // We're not done yet.
1801 return false; 1753 return false;
1802 } 1754 }
1803 } 1755 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698