Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |