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: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 |