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'; |
11 import 'package:analyzer/error/error.dart'; | 11 import 'package:analyzer/error/error.dart'; |
12 import 'package:analyzer/error/listener.dart'; | 12 import 'package:analyzer/error/listener.dart'; |
13 import 'package:analyzer/file_system/file_system.dart'; | 13 import 'package:analyzer/file_system/file_system.dart'; |
14 import 'package:analyzer/src/context/context.dart'; | 14 import 'package:analyzer/src/context/context.dart'; |
15 import 'package:analyzer/src/context/source.dart'; | 15 import 'package:analyzer/src/context/source.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/error/todo_codes.dart'; | |
18 import 'package:analyzer/src/dart/scanner/reader.dart'; | 17 import 'package:analyzer/src/dart/scanner/reader.dart'; |
19 import 'package:analyzer/src/dart/scanner/scanner.dart'; | 18 import 'package:analyzer/src/dart/scanner/scanner.dart'; |
20 import 'package:analyzer/src/generated/engine.dart' | 19 import 'package:analyzer/src/generated/engine.dart' |
21 show AnalysisContext, AnalysisEngine, AnalysisOptions, ChangeSet; | 20 show AnalysisContext, AnalysisEngine, AnalysisOptions, ChangeSet; |
22 import 'package:analyzer/src/generated/parser.dart'; | 21 import 'package:analyzer/src/generated/parser.dart'; |
23 import 'package:analyzer/src/generated/source.dart'; | 22 import 'package:analyzer/src/generated/source.dart'; |
24 import 'package:analyzer/src/generated/utilities_dart.dart'; | 23 import 'package:analyzer/src/generated/utilities_dart.dart'; |
25 import 'package:analyzer/src/summary/api_signature.dart'; | 24 import 'package:analyzer/src/summary/api_signature.dart'; |
26 import 'package:analyzer/src/summary/flat_buffers.dart' as fb; | |
27 import 'package:analyzer/src/summary/format.dart'; | 25 import 'package:analyzer/src/summary/format.dart'; |
28 import 'package:analyzer/src/summary/idl.dart'; | 26 import 'package:analyzer/src/summary/idl.dart'; |
29 import 'package:analyzer/src/summary/link.dart'; | 27 import 'package:analyzer/src/summary/link.dart'; |
30 import 'package:analyzer/src/summary/package_bundle_reader.dart'; | 28 import 'package:analyzer/src/summary/package_bundle_reader.dart'; |
31 import 'package:analyzer/src/summary/summarize_ast.dart'; | 29 import 'package:analyzer/src/summary/summarize_ast.dart'; |
32 import 'package:analyzer/src/summary/summarize_elements.dart'; | 30 import 'package:analyzer/src/summary/summarize_elements.dart'; |
33 import 'package:analyzer/src/util/fast_uri.dart'; | 31 import 'package:analyzer/src/util/fast_uri.dart'; |
34 import 'package:convert/convert.dart'; | 32 import 'package:convert/convert.dart'; |
35 import 'package:crypto/crypto.dart'; | 33 import 'package:crypto/crypto.dart'; |
36 | 34 |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
178 /** | 176 /** |
179 * Return the [Stream] that produces [AnalysisResult]s for added files. | 177 * Return the [Stream] that produces [AnalysisResult]s for added files. |
180 * | 178 * |
181 * Analysis starts when the client starts listening to the stream, and stops | 179 * Analysis starts when the client starts listening to the stream, and stops |
182 * when the client cancels the subscription. | 180 * when the client cancels the subscription. |
183 * | 181 * |
184 * When the client starts listening, the analysis state transitions to | 182 * When the client starts listening, the analysis state transitions to |
185 * "analyzing" and an analysis result is produced for every added file prior | 183 * "analyzing" and an analysis result is produced for every added file prior |
186 * to the next time the analysis state transitions to "idle". | 184 * to the next time the analysis state transitions to "idle". |
187 * | 185 * |
188 * Invocation of [addFile] or [changeFile] might result in producing more | 186 * At least one analysis result is produced for every file passed to |
189 * analysis results that reflect the new current file state. | 187 * [addFile] or [changeFile] prior to the next time the analysis state |
188 * transitions to "idle". Analysis results for other files are produced | |
189 * only if the changes affect analysis results of other files. | |
190 * | 190 * |
191 * More than one result might be produced for the same file, even if the | 191 * More than one result might be produced for the same file, even if the |
192 * client does not change the state of the files. | 192 * client does not change the state of the files. |
193 * | 193 * |
194 * Results might be produced even for files that have never been added | 194 * Results might be produced even for files that have never been added |
195 * using [addFile], for example when [getResult] was called for a file. | 195 * using [addFile], for example when [getResult] was called for a file. |
196 */ | 196 */ |
197 Stream<AnalysisResult> get results async* { | 197 Stream<AnalysisResult> get results async* { |
198 try { | 198 try { |
199 while (true) { | 199 while (true) { |
200 // TODO(scheglov) implement state transitioning | 200 // TODO(scheglov) implement state transitioning |
201 await for (String why in _hasWorkStreamController.stream) { | 201 await for (String why in _hasWorkStreamController.stream) { |
202 _verifyUnlinkedSignatureOfChangedFiles(); | 202 _verifyUnlinkedSignatureOfChangedFiles(); |
203 | 203 |
204 // Analyze the first file in the general queue. | 204 // Analyze the first file in the general queue. |
205 if (_filesToAnalyze.isNotEmpty) { | 205 if (_filesToAnalyze.isNotEmpty) { |
206 _logger.run('Analyze ${_filesToAnalyze.length} files', () { | 206 PerformanceLogSection analysisSection = |
207 _logger.enter('Analyze ${_filesToAnalyze.length} files'); | |
208 try { | |
209 // TODO(scheglov) The loop is strange for now. | |
Brian Wilkerson
2016/10/26 06:45:03
Describe what needs to be done to fix the strangen
| |
207 while (_filesToAnalyze.isNotEmpty) { | 210 while (_filesToAnalyze.isNotEmpty) { |
208 String path = _filesToAnalyze.first; | 211 String path = _filesToAnalyze.first; |
209 _filesToAnalyze.remove(path); | 212 _filesToAnalyze.remove(path); |
210 _File file = _fileForPath(path); | 213 _File file = _fileForPath(path); |
211 _computeAndPrintErrors(file); | 214 AnalysisResult result = _computeAnalysisResult(file); |
212 // TODO(scheglov) yield the result | 215 yield result; |
213 } | 216 } |
214 }); | 217 } finally { |
218 analysisSection.exit(); | |
219 } | |
215 } | 220 } |
216 } | 221 } |
217 // TODO(scheglov) implement | 222 // TODO(scheglov) implement |
218 } | 223 } |
219 } finally { | 224 } finally { |
220 print('The stream was cancelled.'); | 225 print('The stream was cancelled.'); |
221 } | 226 } |
222 } | 227 } |
223 | 228 |
224 /** | 229 /** |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
311 * add [UnlinkedUnit] with wrong URI. | 316 * add [UnlinkedUnit] with wrong URI. |
312 * | 317 * |
313 * We need to clean this up. | 318 * We need to clean this up. |
314 */ | 319 */ |
315 void _addToStoreUnlinked( | 320 void _addToStoreUnlinked( |
316 SummaryDataStore store, String uri, UnlinkedUnit unlinked) { | 321 SummaryDataStore store, String uri, UnlinkedUnit unlinked) { |
317 store.unlinkedMap[uri] = unlinked; | 322 store.unlinkedMap[uri] = unlinked; |
318 } | 323 } |
319 | 324 |
320 /** | 325 /** |
321 * TODO(scheglov) replace with actual [AnalysisResult] computing. | 326 * Compute the [AnalysisResult] for the [file]. |
322 */ | 327 */ |
323 List<String> _computeAndPrintErrors(_File file) { | 328 AnalysisResult _computeAnalysisResult(_File file) { |
324 // TODO(scheglov) Computing resolved unit fails for these units. | 329 // TODO(scheglov) Computing resolved unit fails for these units. |
325 // pkg/analyzer/lib/plugin/embedded_resolver_provider.dart | 330 // pkg/analyzer/lib/plugin/embedded_resolver_provider.dart |
326 // pkg/analyzer/lib/plugin/embedded_resolver_provider.dart | 331 // pkg/analyzer/lib/plugin/embedded_resolver_provider.dart |
327 if (file.path.endsWith( | 332 if (file.path.endsWith( |
328 'pkg/analyzer/lib/plugin/embedded_resolver_provider.dart') || | 333 'pkg/analyzer/lib/plugin/embedded_resolver_provider.dart') || |
329 file.path.endsWith('pkg/analyzer/lib/source/embedder.dart') || | 334 file.path.endsWith('pkg/analyzer/lib/source/embedder.dart') || |
330 file.path.endsWith('pkg/analyzer/lib/src/generated/ast.dart') || | 335 file.path.endsWith('pkg/analyzer/lib/src/generated/ast.dart') || |
331 file.path.endsWith('pkg/analyzer/lib/src/generated/element.dart') || | 336 file.path.endsWith('pkg/analyzer/lib/src/generated/element.dart') || |
332 file.path | 337 file.path |
333 .endsWith('pkg/analyzer/lib/src/generated/element_handle.dart') || | 338 .endsWith('pkg/analyzer/lib/src/generated/element_handle.dart') || |
334 file.path.endsWith('pkg/analyzer/lib/src/generated/error.dart') || | 339 file.path.endsWith('pkg/analyzer/lib/src/generated/error.dart') || |
335 file.path.endsWith('pkg/analyzer/lib/src/generated/scanner.dart') || | 340 file.path.endsWith('pkg/analyzer/lib/src/generated/scanner.dart') || |
336 file.path.endsWith('pkg/analyzer/lib/src/generated/sdk_io.dart') || | 341 file.path.endsWith('pkg/analyzer/lib/src/generated/sdk_io.dart') || |
337 file.path.endsWith('pkg/analyzer/lib/src/generated/visitors.dart') || | 342 file.path.endsWith('pkg/analyzer/lib/src/generated/visitors.dart') || |
338 file.path.endsWith('pkg/analyzer/test/generated/constant_test.dart') || | 343 file.path.endsWith('pkg/analyzer/test/generated/constant_test.dart') || |
339 file.path.endsWith('pkg/analyzer/test/source/embedder_test.dart')) { | 344 file.path.endsWith('pkg/analyzer/test/source/embedder_test.dart')) { |
340 return []; | 345 return new AnalysisResult( |
346 file.path, file.uri, null, file.contentHash, null, []); | |
341 } | 347 } |
342 | 348 |
343 List<String> errorStrings = _logger.run('Compute errors $file', () { | 349 return _logger.run('Compute analysis result for $file', () { |
344 _LibraryContext libraryContext = _createLibraryContext(file); | 350 _LibraryContext libraryContext = _createLibraryContext(file); |
345 | |
346 String errorsKey; | |
347 { | |
348 ApiSignature signature = new ApiSignature(); | |
349 signature.addString(libraryContext.node.dependencySignature); | |
350 signature.addString(file.contentHash); | |
351 errorsKey = '${signature.toHex()}.errors'; | |
352 } | |
353 | |
354 { | |
355 List<int> bytes = _byteStore.get(errorsKey); | |
356 if (bytes != null) { | |
357 fb.BufferContext bp = new fb.BufferContext.fromBytes(bytes); | |
358 int table = bp.derefObject(0); | |
359 return const fb.ListReader<String>(const fb.StringReader()) | |
360 .vTableGet(bp, table, 0); | |
361 } | |
362 } | |
363 | |
364 AnalysisContext analysisContext = _createAnalysisContext(libraryContext); | 351 AnalysisContext analysisContext = _createAnalysisContext(libraryContext); |
365 analysisContext.setContents(file.source, file.content); | 352 analysisContext.setContents(file.source, file.content); |
366 try { | 353 // TODO(scheglov) Add support for parts. |
367 // Compute resolved unit. | 354 CompilationUnit resolvedUnit = |
368 // _logger.runTimed('Computed resolved unit', () { | 355 analysisContext.resolveCompilationUnit2(file.source, file.source); |
369 // analysisContext.resolveCompilationUnit2( | 356 List<AnalysisError> errors = analysisContext.computeErrors(file.source); |
370 // libraryContext.file.source, libraryContext.file.source); | 357 return new AnalysisResult(file.path, file.uri, file.content, |
371 // }); | 358 file.contentHash, resolvedUnit, errors); |
372 // Compute errors. | |
373 List<AnalysisError> errors = _logger.run('Compute errors', () { | |
374 return analysisContext.computeErrors(file.source); | |
375 }); | |
376 List<String> errorStrings = errors | |
377 .where((error) => error.errorCode is! TodoCode) | |
378 .map((error) => error.toString()) | |
379 .toList(); | |
380 { | |
381 fb.Builder fbBuilder = new fb.Builder(); | |
382 var exportedOffset = fbBuilder.writeList(errorStrings | |
383 .map((errorStr) => fbBuilder.writeString(errorStr)) | |
384 .toList()); | |
385 fbBuilder.startTable(); | |
386 fbBuilder.addOffset(0, exportedOffset); | |
387 var offset = fbBuilder.endTable(); | |
388 List<int> bytes = fbBuilder.finish(offset, 'CErr'); | |
389 _byteStore.put(errorsKey, bytes); | |
390 } | |
391 | |
392 return errorStrings; | |
393 } finally { | |
394 analysisContext.dispose(); | |
395 } | |
396 }); | 359 }); |
397 | |
398 if (errorStrings.isNotEmpty) { | |
399 errorStrings.forEach((errorString) => print('\t$errorString')); | |
400 } else { | |
401 print('\tNO ERRORS'); | |
402 } | |
403 return errorStrings; | |
404 } | 360 } |
405 | 361 |
406 AnalysisContext _createAnalysisContext(_LibraryContext libraryContext) { | 362 AnalysisContext _createAnalysisContext(_LibraryContext libraryContext) { |
407 AnalysisContextImpl analysisContext = | 363 AnalysisContextImpl analysisContext = |
408 AnalysisEngine.instance.createAnalysisContext(); | 364 AnalysisEngine.instance.createAnalysisContext(); |
409 | 365 |
410 analysisContext.sourceFactory = | 366 analysisContext.sourceFactory = |
411 new SourceFactory((_sourceFactory as SourceFactoryImpl).resolvers); | 367 new SourceFactory((_sourceFactory as SourceFactoryImpl).resolvers); |
412 analysisContext.resultProvider = | 368 analysisContext.resultProvider = |
413 new InputPackagesResultProvider(analysisContext, libraryContext.store); | 369 new InputPackagesResultProvider(analysisContext, libraryContext.store); |
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
665 /** | 621 /** |
666 * This class is used to gather and print performance information. | 622 * This class is used to gather and print performance information. |
667 */ | 623 */ |
668 class PerformanceLog { | 624 class PerformanceLog { |
669 final StringSink sink; | 625 final StringSink sink; |
670 int _level = 0; | 626 int _level = 0; |
671 | 627 |
672 PerformanceLog(this.sink); | 628 PerformanceLog(this.sink); |
673 | 629 |
674 /** | 630 /** |
631 * Enter a new execution section, which starts at one point of code, runs | |
632 * some time, and then ends at the other point of code. | |
633 * | |
634 * The client must call [PerformanceLogSection.exit] for every [enter]. | |
635 */ | |
636 PerformanceLogSection enter(String msg) { | |
637 writeln('+++ $msg.'); | |
638 _level++; | |
639 return new PerformanceLogSection(this, msg); | |
640 } | |
641 | |
642 /** | |
675 * Return the result of the function [f] invocation and log the elapsed time. | 643 * Return the result of the function [f] invocation and log the elapsed time. |
676 * | 644 * |
677 * Each invocation of [run] creates a new enclosed section in the log, | 645 * Each invocation of [run] creates a new enclosed section in the log, |
678 * which begins with printing [msg], then any log output produced during | 646 * which begins with printing [msg], then any log output produced during |
679 * [f] invocation, and ends with printing [msg] with the elapsed time. | 647 * [f] invocation, and ends with printing [msg] with the elapsed time. |
680 */ | 648 */ |
681 /*=T*/ run/*<T>*/(String msg, /*=T*/ f()) { | 649 /*=T*/ run/*<T>*/(String msg, /*=T*/ f()) { |
682 Stopwatch timer = new Stopwatch()..start(); | 650 Stopwatch timer = new Stopwatch()..start(); |
683 try { | 651 try { |
684 writeln('+++ $msg.'); | 652 writeln('+++ $msg.'); |
685 _level++; | 653 _level++; |
686 return f(); | 654 return f(); |
687 } finally { | 655 } finally { |
688 _level--; | 656 _level--; |
689 int ms = timer.elapsedMilliseconds; | 657 int ms = timer.elapsedMilliseconds; |
690 writeln('--- $msg in $ms ms.'); | 658 writeln('--- $msg in $ms ms.'); |
691 } | 659 } |
692 } | 660 } |
693 | 661 |
694 /** | 662 /** |
695 * Write a new line into the log | 663 * Write a new line into the log |
696 */ | 664 */ |
697 void writeln(String msg) { | 665 void writeln(String msg) { |
698 String indent = '\t' * _level; | 666 String indent = '\t' * _level; |
699 sink.writeln('$indent$msg'); | 667 sink.writeln('$indent$msg'); |
700 } | 668 } |
701 } | 669 } |
702 | 670 |
703 /** | 671 /** |
672 * The performance measurement section for operations that start and end | |
673 * at different place in code, so cannot be run using [PerformanceLog.run]. | |
674 * | |
675 * The client must call [exit] for every [PerformanceLog.enter]. | |
676 */ | |
677 class PerformanceLogSection { | |
Brian Wilkerson
2016/10/26 06:45:03
Consider moving logging into a separate library.
| |
678 final PerformanceLog _logger; | |
679 final String _msg; | |
680 final Stopwatch _timer = new Stopwatch()..start(); | |
681 | |
682 PerformanceLogSection(this._logger, this._msg); | |
683 | |
684 /** | |
685 * Stop the timer, log the time. | |
686 */ | |
687 void exit() { | |
688 _timer.stop(); | |
689 _logger._level--; | |
690 int ms = _timer.elapsedMilliseconds; | |
691 _logger.writeln('--- $_msg in $ms ms.'); | |
692 } | |
693 } | |
694 | |
695 /** | |
704 * Information about a file being analyzed, explicitly or implicitly. | 696 * Information about a file being analyzed, explicitly or implicitly. |
705 * | 697 * |
706 * It keeps a consistent view on its [content], [contentHash] and [unit]. | 698 * It keeps a consistent view on its [content], [contentHash] and [unit]. |
707 * | 699 * |
708 * Instances of this class may only be used during computing a single analysis | 700 * Instances of this class may only be used during computing a single analysis |
709 * result and should not be cached anywhere. We need this limitation to prevent | 701 * result and should not be cached anywhere. We need this limitation to prevent |
710 * references from caches to the resolved [unit], so to element models, etc. | 702 * references from caches to the resolved [unit], so to element models, etc. |
711 * The data structures should be short lived - computed, returned to the client, | 703 * The data structures should be short lived - computed, returned to the client, |
712 * processed there and quickly thrown away. | 704 * processed there and quickly thrown away. |
713 */ | 705 */ |
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
982 } | 974 } |
983 } | 975 } |
984 for (UnlinkedExportPublic export in unit.publicNamespace.exports) { | 976 for (UnlinkedExportPublic export in unit.publicNamespace.exports) { |
985 referenced.exported.add(export.uri); | 977 referenced.exported.add(export.uri); |
986 } | 978 } |
987 return referenced; | 979 return referenced; |
988 } | 980 } |
989 | 981 |
990 _ReferencedUris._(); | 982 _ReferencedUris._(); |
991 } | 983 } |
OLD | NEW |