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 |