| 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:convert'; | 7 import 'dart:convert'; |
| 8 | 8 |
| 9 import 'package:analyzer/dart/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
| 10 import 'package:analyzer/dart/ast/token.dart'; | 10 import 'package:analyzer/dart/ast/token.dart'; |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 159 /** | 159 /** |
| 160 * Mapping from library URIs to the dependency signature of the library. | 160 * Mapping from library URIs to the dependency signature of the library. |
| 161 */ | 161 */ |
| 162 final _dependencySignatureMap = <Uri, String>{}; | 162 final _dependencySignatureMap = <Uri, String>{}; |
| 163 | 163 |
| 164 /** | 164 /** |
| 165 * The monitor that is signalled when there is work to do. | 165 * The monitor that is signalled when there is work to do. |
| 166 */ | 166 */ |
| 167 final _Monitor _hasWork = new _Monitor(); | 167 final _Monitor _hasWork = new _Monitor(); |
| 168 | 168 |
| 169 /** |
| 170 * The controller for the [status] stream. |
| 171 */ |
| 172 final _statusController = new StreamController<AnalysisStatus>(); |
| 173 |
| 174 /** |
| 175 * The last status sent to the [status] stream. |
| 176 */ |
| 177 AnalysisStatus _currentStatus = AnalysisStatus.IDLE; |
| 178 |
| 169 AnalysisDriver(this._logger, this._resourceProvider, this._byteStore, | 179 AnalysisDriver(this._logger, this._resourceProvider, this._byteStore, |
| 170 this._contentCache, this._sourceFactory, this._analysisOptions) { | 180 this._contentCache, this._sourceFactory, this._analysisOptions) { |
| 171 _sdkBundle = _sourceFactory.dartSdk.getLinkedBundle(); | 181 _sdkBundle = _sourceFactory.dartSdk.getLinkedBundle(); |
| 172 } | 182 } |
| 173 | 183 |
| 174 /** | 184 /** |
| 175 * Set the list of files that the driver should try to analyze sooner. | 185 * Set the list of files that the driver should try to analyze sooner. |
| 176 * | 186 * |
| 177 * Every path in the list must be absolute and normalized. | 187 * Every path in the list must be absolute and normalized. |
| 178 * | 188 * |
| 179 * The driver will produce the results through the [results] stream. The | 189 * The driver will produce the results through the [results] stream. The |
| 180 * exact order in which results are produced is not defined, neither | 190 * exact order in which results are produced is not defined, neither |
| 181 * between priority files, nor between priority and non-priority files. | 191 * between priority files, nor between priority and non-priority files. |
| 182 */ | 192 */ |
| 183 void set priorityFiles(List<String> priorityPaths) { | 193 void set priorityFiles(List<String> priorityPaths) { |
| 184 _priorityFiles.clear(); | 194 _priorityFiles.clear(); |
| 185 _priorityFiles.addAll(priorityPaths); | 195 _priorityFiles.addAll(priorityPaths); |
| 196 _transitionToAnalyzing(); |
| 186 _hasWork.notify(); | 197 _hasWork.notify(); |
| 187 } | 198 } |
| 188 | 199 |
| 189 /** | 200 /** |
| 190 * Return the [Stream] that produces [AnalysisResult]s for added files. | 201 * Return the [Stream] that produces [AnalysisResult]s for added files. |
| 191 * | 202 * |
| 192 * Analysis starts when the client starts listening to the stream, and stops | 203 * Analysis starts when the client starts listening to the stream, and stops |
| 193 * when the client cancels the subscription. | 204 * when the client cancels the subscription. |
| 194 * | 205 * |
| 195 * When the client starts listening, the analysis state transitions to | 206 * When the client starts listening, the analysis state transitions to |
| (...skipping 11 matching lines...) Expand all Loading... |
| 207 * | 218 * |
| 208 * Results might be produced even for files that have never been added | 219 * Results might be produced even for files that have never been added |
| 209 * using [addFile], for example when [getResult] was called for a file. | 220 * using [addFile], for example when [getResult] was called for a file. |
| 210 */ | 221 */ |
| 211 Stream<AnalysisResult> get results async* { | 222 Stream<AnalysisResult> get results async* { |
| 212 try { | 223 try { |
| 213 PerformanceLogSection analysisSection = null; | 224 PerformanceLogSection analysisSection = null; |
| 214 while (true) { | 225 while (true) { |
| 215 await _hasWork.signal; | 226 await _hasWork.signal; |
| 216 | 227 |
| 217 // TODO(scheglov) implement state transitioning | |
| 218 if (analysisSection == null) { | 228 if (analysisSection == null) { |
| 219 analysisSection = _logger.enter('Analyzing'); | 229 analysisSection = _logger.enter('Analyzing'); |
| 220 } | 230 } |
| 221 | 231 |
| 222 // Verify all changed files one at a time. | 232 // Verify all changed files one at a time. |
| 223 if (_changedFiles.isNotEmpty) { | 233 if (_changedFiles.isNotEmpty) { |
| 224 String path = _removeFirst(_changedFiles); | 234 String path = _removeFirst(_changedFiles); |
| 225 _verifyApiSignatureOfChangedFile(path); | 235 _verifyApiSignatureOfChangedFile(path); |
| 226 // Repeat the processing loop. | 236 // Repeat the processing loop. |
| 227 _hasWork.notify(); | 237 _hasWork.notify(); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 265 AnalysisResult result = _computeAnalysisResult(path, withUnit: false); | 275 AnalysisResult result = _computeAnalysisResult(path, withUnit: false); |
| 266 yield result; | 276 yield result; |
| 267 // Repeat the processing loop. | 277 // Repeat the processing loop. |
| 268 _hasWork.notify(); | 278 _hasWork.notify(); |
| 269 continue; | 279 continue; |
| 270 } | 280 } |
| 271 | 281 |
| 272 // There is nothing to do. | 282 // There is nothing to do. |
| 273 analysisSection.exit(); | 283 analysisSection.exit(); |
| 274 analysisSection = null; | 284 analysisSection = null; |
| 285 _transitionToIdle(); |
| 275 } | 286 } |
| 276 } finally { | 287 } finally { |
| 277 print('The stream was cancelled.'); | 288 print('The stream was cancelled.'); |
| 278 } | 289 } |
| 279 } | 290 } |
| 280 | 291 |
| 281 /** | 292 /** |
| 293 * Return the stream that produces [AnalysisStatus] events. |
| 294 */ |
| 295 Stream<AnalysisStatus> get status => _statusController.stream; |
| 296 |
| 297 /** |
| 282 * Add the file with the given [path] to the set of files to analyze. | 298 * Add the file with the given [path] to the set of files to analyze. |
| 283 * | 299 * |
| 284 * The [path] must be absolute and normalized. | 300 * The [path] must be absolute and normalized. |
| 285 * | 301 * |
| 286 * The results of analysis are eventually produced by the [results] stream. | 302 * The results of analysis are eventually produced by the [results] stream. |
| 287 */ | 303 */ |
| 288 void addFile(String path) { | 304 void addFile(String path) { |
| 289 _explicitFiles.add(path); | 305 _explicitFiles.add(path); |
| 290 _filesToAnalyze.add(path); | 306 _filesToAnalyze.add(path); |
| 307 _transitionToAnalyzing(); |
| 291 _hasWork.notify(); | 308 _hasWork.notify(); |
| 292 } | 309 } |
| 293 | 310 |
| 294 /** | 311 /** |
| 295 * The file with the given [path] might have changed - updated, added or | 312 * The file with the given [path] might have changed - updated, added or |
| 296 * removed. Or not, we don't know. Or it might have, but then changed back. | 313 * removed. Or not, we don't know. Or it might have, but then changed back. |
| 297 * | 314 * |
| 298 * The [path] must be absolute and normalized. | 315 * The [path] must be absolute and normalized. |
| 299 * | 316 * |
| 300 * The [path] can be any file - explicitly or implicitly analyzed, or neither. | 317 * The [path] can be any file - explicitly or implicitly analyzed, or neither. |
| 301 * | 318 * |
| 302 * Causes the analysis state to transition to "analyzing" (if it is not in | 319 * Causes the analysis state to transition to "analyzing" (if it is not in |
| 303 * that state already). Schedules the file contents for [path] to be read | 320 * that state already). Schedules the file contents for [path] to be read |
| 304 * into the current file state prior to the next time the analysis state | 321 * into the current file state prior to the next time the analysis state |
| 305 * transitions to "idle". | 322 * transitions to "idle". |
| 306 * | 323 * |
| 307 * Invocation of this method will not prevent a [Future] returned from | 324 * Invocation of this method will not prevent a [Future] returned from |
| 308 * [getResult] from completing with a result, but the result is not | 325 * [getResult] from completing with a result, but the result is not |
| 309 * guaranteed to be consistent with the new current file state after this | 326 * guaranteed to be consistent with the new current file state after this |
| 310 * [changeFile] invocation. | 327 * [changeFile] invocation. |
| 311 */ | 328 */ |
| 312 void changeFile(String path) { | 329 void changeFile(String path) { |
| 313 _changedFiles.add(path); | 330 _changedFiles.add(path); |
| 314 _filesToAnalyze.add(path); | 331 _filesToAnalyze.add(path); |
| 332 _transitionToAnalyzing(); |
| 315 _hasWork.notify(); | 333 _hasWork.notify(); |
| 316 } | 334 } |
| 317 | 335 |
| 318 /** | 336 /** |
| 319 * Return the [Future] that completes with a [AnalysisResult] for the file | 337 * Return the [Future] that completes with a [AnalysisResult] for the file |
| 320 * with the given [path]. | 338 * with the given [path]. |
| 321 * | 339 * |
| 322 * The [path] must be absolute and normalized. | 340 * The [path] must be absolute and normalized. |
| 323 * | 341 * |
| 324 * The [path] can be any file - explicitly or implicitly analyzed, or neither. | 342 * The [path] can be any file - explicitly or implicitly analyzed, or neither. |
| 325 * | 343 * |
| 326 * Causes the analysis state to transition to "analyzing" (if it is not in | 344 * Causes the analysis state to transition to "analyzing" (if it is not in |
| 327 * that state already), the driver will read the file and produce the analysis | 345 * that state already), the driver will read the file and produce the analysis |
| 328 * result for it, which is consistent with the current file state (including | 346 * result for it, which is consistent with the current file state (including |
| 329 * the new state of the file), prior to the next time the analysis state | 347 * the new state of the file), prior to the next time the analysis state |
| 330 * transitions to "idle". | 348 * transitions to "idle". |
| 331 */ | 349 */ |
| 332 Future<AnalysisResult> getResult(String path) { | 350 Future<AnalysisResult> getResult(String path) { |
| 333 var completer = new Completer<AnalysisResult>(); | 351 var completer = new Completer<AnalysisResult>(); |
| 334 _requestedFiles | 352 _requestedFiles |
| 335 .putIfAbsent(path, () => <Completer<AnalysisResult>>[]) | 353 .putIfAbsent(path, () => <Completer<AnalysisResult>>[]) |
| 336 .add(completer); | 354 .add(completer); |
| 355 _transitionToAnalyzing(); |
| 337 _hasWork.notify(); | 356 _hasWork.notify(); |
| 338 return completer.future; | 357 return completer.future; |
| 339 } | 358 } |
| 340 | 359 |
| 341 /** | 360 /** |
| 342 * Remove the file with the given [path] from the list of files to analyze. | 361 * Remove the file with the given [path] from the list of files to analyze. |
| 343 * | 362 * |
| 344 * The [path] must be absolute and normalized. | 363 * The [path] must be absolute and normalized. |
| 345 * | 364 * |
| 346 * The results of analysis of the file might still be produced by the | 365 * The results of analysis of the file might still be produced by the |
| (...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 613 /** | 632 /** |
| 614 * Return the [Source] for the given [path] in [_sourceFactory]. | 633 * Return the [Source] for the given [path] in [_sourceFactory]. |
| 615 */ | 634 */ |
| 616 Source _sourceForPath(String path) { | 635 Source _sourceForPath(String path) { |
| 617 Source fileSource = _resourceProvider.getFile(path).createSource(); | 636 Source fileSource = _resourceProvider.getFile(path).createSource(); |
| 618 Uri uri = _sourceFactory.restoreUri(fileSource); | 637 Uri uri = _sourceFactory.restoreUri(fileSource); |
| 619 return _resourceProvider.getFile(path).createSource(uri); | 638 return _resourceProvider.getFile(path).createSource(uri); |
| 620 } | 639 } |
| 621 | 640 |
| 622 /** | 641 /** |
| 642 * Send a notifications to the [status] stream that the driver started |
| 643 * analyzing. |
| 644 */ |
| 645 void _transitionToAnalyzing() { |
| 646 if (_currentStatus != AnalysisStatus.ANALYZING) { |
| 647 _currentStatus = AnalysisStatus.ANALYZING; |
| 648 _statusController.add(AnalysisStatus.ANALYZING); |
| 649 } |
| 650 } |
| 651 |
| 652 /** |
| 653 * Send a notifications to the [status] stream that the driver is idle. |
| 654 */ |
| 655 void _transitionToIdle() { |
| 656 if (_currentStatus != AnalysisStatus.IDLE) { |
| 657 _currentStatus = AnalysisStatus.IDLE; |
| 658 _statusController.add(AnalysisStatus.IDLE); |
| 659 } |
| 660 } |
| 661 |
| 662 /** |
| 623 * Verify the API signature for the file with the given [path], and decide | 663 * Verify the API signature for the file with the given [path], and decide |
| 624 * which linked libraries should be invalidated, and files reanalyzed. | 664 * which linked libraries should be invalidated, and files reanalyzed. |
| 625 * | 665 * |
| 626 * TODO(scheglov) I see that adding a local var changes (full) API signature. | 666 * TODO(scheglov) I see that adding a local var changes (full) API signature. |
| 627 */ | 667 */ |
| 628 void _verifyApiSignatureOfChangedFile(String path) { | 668 void _verifyApiSignatureOfChangedFile(String path) { |
| 629 _logger.run('Verify API signature of $path', () { | 669 _logger.run('Verify API signature of $path', () { |
| 630 String oldSignature = _fileApiSignatureMap[path]; | 670 String oldSignature = _fileApiSignatureMap[path]; |
| 631 // Compute the new API signature. | 671 // Compute the new API signature. |
| 632 // _File.forResolution() also updates the content hash in the cache. | 672 // _File.forResolution() also updates the content hash in the cache. |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 697 /** | 737 /** |
| 698 * The full list of computed analysis errors, both syntactic and semantic. | 738 * The full list of computed analysis errors, both syntactic and semantic. |
| 699 */ | 739 */ |
| 700 final List<AnalysisError> errors; | 740 final List<AnalysisError> errors; |
| 701 | 741 |
| 702 AnalysisResult(this.path, this.uri, this.content, this.contentHash, this.unit, | 742 AnalysisResult(this.path, this.uri, this.content, this.contentHash, this.unit, |
| 703 this.errors); | 743 this.errors); |
| 704 } | 744 } |
| 705 | 745 |
| 706 /** | 746 /** |
| 747 * The status of [AnalysisDriver] |
| 748 */ |
| 749 class AnalysisStatus { |
| 750 static const IDLE = const AnalysisStatus._(false); |
| 751 static const ANALYZING = const AnalysisStatus._(true); |
| 752 |
| 753 final bool _analyzing; |
| 754 |
| 755 const AnalysisStatus._(this._analyzing); |
| 756 |
| 757 /** |
| 758 * Return `true` is the driver is analyzing. |
| 759 */ |
| 760 bool get isAnalyzing => _analyzing; |
| 761 |
| 762 /** |
| 763 * Return `true` is the driver is idle. |
| 764 */ |
| 765 bool get isIdle => !_analyzing; |
| 766 } |
| 767 |
| 768 /** |
| 707 * This class is used to gather and print performance information. | 769 * This class is used to gather and print performance information. |
| 708 */ | 770 */ |
| 709 class PerformanceLog { | 771 class PerformanceLog { |
| 710 final StringSink sink; | 772 final StringSink sink; |
| 711 int _level = 0; | 773 int _level = 0; |
| 712 | 774 |
| 713 PerformanceLog(this.sink); | 775 PerformanceLog(this.sink); |
| 714 | 776 |
| 715 /** | 777 /** |
| 716 * Enter a new execution section, which starts at one point of code, runs | 778 * Enter a new execution section, which starts at one point of code, runs |
| (...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1112 } | 1174 } |
| 1113 } | 1175 } |
| 1114 for (UnlinkedExportPublic export in unit.publicNamespace.exports) { | 1176 for (UnlinkedExportPublic export in unit.publicNamespace.exports) { |
| 1115 referenced.exported.add(export.uri); | 1177 referenced.exported.add(export.uri); |
| 1116 } | 1178 } |
| 1117 return referenced; | 1179 return referenced; |
| 1118 } | 1180 } |
| 1119 | 1181 |
| 1120 _ReferencedUris._(); | 1182 _ReferencedUris._(); |
| 1121 } | 1183 } |
| OLD | NEW |