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 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
342 file.path.endsWith('pkg/analyzer/lib/src/generated/visitors.dart') || | 342 file.path.endsWith('pkg/analyzer/lib/src/generated/visitors.dart') || |
343 file.path.endsWith('pkg/analyzer/test/generated/constant_test.dart') || | 343 file.path.endsWith('pkg/analyzer/test/generated/constant_test.dart') || |
344 file.path.endsWith('pkg/analyzer/test/source/embedder_test.dart')) { | 344 file.path.endsWith('pkg/analyzer/test/source/embedder_test.dart')) { |
345 return new AnalysisResult( | 345 return new AnalysisResult( |
346 file.path, file.uri, null, file.contentHash, null, []); | 346 file.path, file.uri, null, file.contentHash, null, []); |
347 } | 347 } |
348 | 348 |
349 return _logger.run('Compute analysis result for $file', () { | 349 return _logger.run('Compute analysis result for $file', () { |
350 _LibraryContext libraryContext = _createLibraryContext(file); | 350 _LibraryContext libraryContext = _createLibraryContext(file); |
351 AnalysisContext analysisContext = _createAnalysisContext(libraryContext); | 351 AnalysisContext analysisContext = _createAnalysisContext(libraryContext); |
352 analysisContext.setContents(file.source, file.content); | 352 try { |
353 // TODO(scheglov) Add support for parts. | 353 analysisContext.setContents(file.source, file.content); |
354 CompilationUnit resolvedUnit = | 354 // TODO(scheglov) Add support for parts. |
355 analysisContext.resolveCompilationUnit2(file.source, file.source); | 355 CompilationUnit resolvedUnit = |
356 List<AnalysisError> errors = analysisContext.computeErrors(file.source); | 356 analysisContext.resolveCompilationUnit2(file.source, file.source); |
357 return new AnalysisResult(file.path, file.uri, file.content, | 357 List<AnalysisError> errors = analysisContext.computeErrors(file.source); |
358 file.contentHash, resolvedUnit, errors); | 358 return new AnalysisResult(file.path, file.uri, file.content, |
| 359 file.contentHash, resolvedUnit, errors); |
| 360 } finally { |
| 361 analysisContext.dispose(); |
| 362 } |
359 }); | 363 }); |
360 } | 364 } |
361 | 365 |
362 AnalysisContext _createAnalysisContext(_LibraryContext libraryContext) { | 366 AnalysisContext _createAnalysisContext(_LibraryContext libraryContext) { |
363 AnalysisContextImpl analysisContext = | 367 AnalysisContextImpl analysisContext = |
364 AnalysisEngine.instance.createAnalysisContext(); | 368 AnalysisEngine.instance.createAnalysisContext(); |
365 | 369 |
366 analysisContext.sourceFactory = | 370 analysisContext.sourceFactory = |
367 new SourceFactory((_sourceFactory as SourceFactoryImpl).resolvers); | 371 new SourceFactory((_sourceFactory as SourceFactoryImpl).resolvers); |
368 analysisContext.resultProvider = | 372 analysisContext.resultProvider = |
(...skipping 26 matching lines...) Expand all Loading... |
395 | 399 |
396 String libraryUriStr = libraryUri.toString(); | 400 String libraryUriStr = libraryUri.toString(); |
397 _LibraryNode node = nodes[libraryUriStr]; | 401 _LibraryNode node = nodes[libraryUriStr]; |
398 if (node == null) { | 402 if (node == null) { |
399 node = new _LibraryNode(this, nodes, libraryUri); | 403 node = new _LibraryNode(this, nodes, libraryUri); |
400 nodes[libraryUriStr] = node; | 404 nodes[libraryUriStr] = node; |
401 | 405 |
402 // Append the defining unit. | 406 // Append the defining unit. |
403 _ReferencedUris referenced; | 407 _ReferencedUris referenced; |
404 { | 408 { |
405 PackageBundle bundle = _getUnlinked(libraryFile); | 409 PackageBundle bundle = libraryFile.unlinked; |
406 UnlinkedUnit unlinked = bundle.unlinkedUnits.single; | 410 UnlinkedUnit unlinked = bundle.unlinkedUnits.single; |
407 referenced = new _ReferencedUris(unlinked); | 411 referenced = new _ReferencedUris(unlinked); |
408 node.unlinkedBundles.add(bundle); | 412 node.unlinkedBundles.add(bundle); |
409 _addToStoreUnlinked(store, libraryUriStr, unlinked); | 413 _addToStoreUnlinked(store, libraryUriStr, unlinked); |
410 } | 414 } |
411 | 415 |
412 // Append parts. | 416 // Append parts. |
413 for (String uri in referenced.parted) { | 417 for (String uri in referenced.parted) { |
414 _File file = libraryFile.resolveUri(uri); | 418 _File file = libraryFile.resolveUri(uri); |
415 PackageBundle bundle = _getUnlinked(file); | 419 PackageBundle bundle = file.unlinked; |
416 UnlinkedUnit unlinked = bundle.unlinkedUnits.single; | 420 UnlinkedUnit unlinked = bundle.unlinkedUnits.single; |
417 node.unlinkedBundles.add(bundle); | 421 node.unlinkedBundles.add(bundle); |
418 _addToStoreUnlinked(store, file.uri.toString(), unlinked); | 422 _addToStoreUnlinked(store, file.uri.toString(), unlinked); |
419 } | 423 } |
420 | 424 |
421 // Create nodes for referenced libraries. | 425 // Create nodes for referenced libraries. |
422 for (String uri in referenced.imported) { | 426 for (String uri in referenced.imported) { |
423 _File file = libraryFile.resolveUri(uri); | 427 _File file = libraryFile.resolveUri(uri); |
424 createLibraryNodes(file); | 428 createLibraryNodes(file); |
425 } | 429 } |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
494 * Return the [_File] for the given [path] in [_sourceFactory]. | 498 * Return the [_File] for the given [path] in [_sourceFactory]. |
495 */ | 499 */ |
496 _File _fileForPath(String path) { | 500 _File _fileForPath(String path) { |
497 Source fileSource = _resourceProvider.getFile(path).createSource(); | 501 Source fileSource = _resourceProvider.getFile(path).createSource(); |
498 Uri uri = _sourceFactory.restoreUri(fileSource); | 502 Uri uri = _sourceFactory.restoreUri(fileSource); |
499 Source source = _resourceProvider.getFile(path).createSource(uri); | 503 Source source = _resourceProvider.getFile(path).createSource(uri); |
500 return new _File(this, source); | 504 return new _File(this, source); |
501 } | 505 } |
502 | 506 |
503 /** | 507 /** |
504 * Return the unlinked bundle of [file] for the current file state, or `null`. | |
505 */ | |
506 PackageBundle _getCurrentUnlinked(_File file) { | |
507 String key = '${file.currentContentHash}.unlinked'; | |
508 List<int> bytes = _byteStore.get(key); | |
509 return bytes != null ? new PackageBundle.fromBuffer(bytes) : null; | |
510 } | |
511 | |
512 /** | |
513 * Return the unlinked bundle of [file] for the current file state. | |
514 * | |
515 * Return [_getCurrentUnlinked] or read the [file] content is read, compute | |
516 * the content hash and update the current file state accordingly. Parse the | |
517 * content into the [CompilationUnit] and serialize into a new unlinked | |
518 * bundle. The bundle is then put into the [_byteStore] and returned. | |
519 */ | |
520 PackageBundle _getUnlinked(_File file) { | |
521 // By accessing 'contentHash' we ensure that the current file state | |
522 // has some version of the file content hash, so we will be able to | |
523 // use it to attempt to get the current unlinked bundle. | |
524 String key = '${file.contentHash}.unlinked'; | |
525 return _getCurrentUnlinked(file) ?? | |
526 _logger.run('Create unlinked for $file', () { | |
527 UnlinkedUnitBuilder unlinkedUnit = serializeAstUnlinked(file.unit); | |
528 PackageBundleAssembler assembler = new PackageBundleAssembler(); | |
529 assembler.addUnlinkedUnitWithHash( | |
530 file.uri.toString(), unlinkedUnit, key); | |
531 List<int> bytes = assembler.assemble().toBuffer(); | |
532 _byteStore.put(key, bytes); | |
533 return new PackageBundle.fromBuffer(bytes); | |
534 }); | |
535 } | |
536 | |
537 /** | |
538 * Verify the API signatures for the changed files, and decide which linked | 508 * Verify the API signatures for the changed files, and decide which linked |
539 * libraries should be invalidated, and files reanalyzed. | 509 * libraries should be invalidated, and files reanalyzed. |
540 * | 510 * |
541 * TODO(scheglov) I see that adding a local var changes (full) API signature. | 511 * TODO(scheglov) I see that adding a local var changes (full) API signature. |
542 */ | 512 */ |
543 void _verifyUnlinkedSignatureOfChangedFiles() { | 513 void _verifyUnlinkedSignatureOfChangedFiles() { |
544 if (_filesToVerifyUnlinkedSignature.isEmpty) { | 514 if (_filesToVerifyUnlinkedSignature.isEmpty) { |
545 return; | 515 return; |
546 } | 516 } |
547 int numOfFiles = _filesToVerifyUnlinkedSignature.length; | 517 int numOfFiles = _filesToVerifyUnlinkedSignature.length; |
548 _logger.run('Verify API signatures of $numOfFiles files', () { | 518 _logger.run('Verify API signatures of $numOfFiles files', () { |
549 for (String path in _filesToVerifyUnlinkedSignature) { | 519 for (String path in _filesToVerifyUnlinkedSignature) { |
550 _File file = _fileForPath(path); | 520 _File file = _fileForPath(path); |
551 // Get the existing old API signature, maybe null. | 521 // Get the existing old API signature, maybe null. |
552 String oldSignature = _getCurrentUnlinked(file)?.apiSignature; | 522 String oldSignature = file.currentUnlinked?.apiSignature; |
553 // Clear the content hash cache, so force the file reading. | 523 // Clear the content hash cache, so force the file reading. |
554 _fileContentHashMap.remove(path); | 524 _fileContentHashMap.remove(path); |
555 // Compute the new API signature. | 525 // Compute the new API signature. |
556 String newSignature = _getUnlinked(file).apiSignature; | 526 String newSignature = file.unlinked.apiSignature; |
557 // If the signatures are not the same, then potentially every linked | 527 // If the signatures are not the same, then potentially every linked |
558 // library is inconsistent and should be recomputed, and every explicit | 528 // library is inconsistent and should be recomputed, and every explicit |
559 // file has inconsistent analysis results which also should be recompute
d. | 529 // file has inconsistent analysis results which also should be recompute
d. |
560 if (oldSignature != newSignature) { | 530 if (oldSignature != newSignature) { |
561 _logger.writeln('API signature mismatch found for $file.'); | 531 _logger.writeln('API signature mismatch found for $file.'); |
562 _dependencySignatureMap.clear(); | 532 _dependencySignatureMap.clear(); |
563 _filesToAnalyze.addAll(_explicitFiles); | 533 _filesToAnalyze.addAll(_explicitFiles); |
564 // Stop the verification, and restart analysis. | 534 // Stop the verification, and restart analysis. |
565 break; | 535 break; |
566 } | 536 } |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
760 } | 730 } |
761 | 731 |
762 /** | 732 /** |
763 * Return the hash of the file content in the current file state, or `null` | 733 * Return the hash of the file content in the current file state, or `null` |
764 * if the current file state does not know the current file content hash. | 734 * if the current file state does not know the current file content hash. |
765 */ | 735 */ |
766 String get currentContentHash { | 736 String get currentContentHash { |
767 return driver._fileContentHashMap[path]; | 737 return driver._fileContentHashMap[path]; |
768 } | 738 } |
769 | 739 |
| 740 /** |
| 741 * Return the unlinked bundle for the current file state, or `null`. |
| 742 */ |
| 743 PackageBundle get currentUnlinked { |
| 744 String hash = currentContentHash; |
| 745 if (hash != null) { |
| 746 String key = '$hash.unlinked'; |
| 747 List<int> bytes = driver._byteStore.get(key); |
| 748 if (bytes != null) { |
| 749 return new PackageBundle.fromBuffer(bytes); |
| 750 } |
| 751 } |
| 752 return null; |
| 753 } |
| 754 |
770 String get path => source.fullName; | 755 String get path => source.fullName; |
771 | 756 |
772 /** | 757 /** |
773 * Return the unresolved [CompilationUnit] of the file. | 758 * Return the unresolved [CompilationUnit] of the file. |
774 * | 759 * |
775 * Performing resolution and computing errors is done in a separate analysis | 760 * Performing resolution and computing errors is done in a separate analysis |
776 * context. In the future we might push the existing unresolved unit into the | 761 * context. In the future we might push the existing unresolved unit into the |
777 * analysis context, so at some point the unit might become resolved. | 762 * analysis context, so at some point the unit might become resolved. |
778 */ | 763 */ |
779 CompilationUnit get unit { | 764 CompilationUnit get unit { |
780 AnalysisErrorListener errorListener = AnalysisErrorListener.NULL_LISTENER; | 765 if (_unit == null) { |
| 766 AnalysisErrorListener errorListener = AnalysisErrorListener.NULL_LISTENER; |
781 | 767 |
782 CharSequenceReader reader = new CharSequenceReader(content); | 768 CharSequenceReader reader = new CharSequenceReader(content); |
783 Scanner scanner = new Scanner(source, reader, errorListener); | 769 Scanner scanner = new Scanner(source, reader, errorListener); |
784 scanner.scanGenericMethodComments = driver._analysisOptions.strongMode; | 770 scanner.scanGenericMethodComments = driver._analysisOptions.strongMode; |
785 Token token = scanner.tokenize(); | 771 Token token = scanner.tokenize(); |
786 LineInfo lineInfo = new LineInfo(scanner.lineStarts); | 772 LineInfo lineInfo = new LineInfo(scanner.lineStarts); |
787 | 773 |
788 Parser parser = new Parser(source, errorListener); | 774 Parser parser = new Parser(source, errorListener); |
789 parser.parseGenericMethodComments = driver._analysisOptions.strongMode; | 775 parser.parseGenericMethodComments = driver._analysisOptions.strongMode; |
790 _unit = parser.parseCompilationUnit(token); | 776 _unit = parser.parseCompilationUnit(token); |
791 _unit.lineInfo = lineInfo; | 777 _unit.lineInfo = lineInfo; |
| 778 } |
| 779 return _unit; |
| 780 } |
792 | 781 |
793 return _unit; | 782 /** |
| 783 * Return the unlinked bundle for the current file state. |
| 784 * |
| 785 * If the file [contentHash] is cached, try to load the bundle with this |
| 786 * hash. Otherwise, read the content, compute the new hash and try to find |
| 787 * the existing bundle, or parse the content and compute a new bundle. |
| 788 */ |
| 789 PackageBundle get unlinked { |
| 790 String key = '$contentHash.unlinked'; |
| 791 List<int> bytes = driver._byteStore.get(key); |
| 792 if (bytes == null) { |
| 793 driver._logger.run('Create unlinked for $this', () { |
| 794 UnlinkedUnitBuilder unlinkedUnit = serializeAstUnlinked(unit); |
| 795 PackageBundleAssembler assembler = new PackageBundleAssembler(); |
| 796 assembler.addUnlinkedUnitWithHash( |
| 797 uri.toString(), unlinkedUnit, contentHash); |
| 798 bytes = assembler.assemble().toBuffer(); |
| 799 driver._byteStore.put(key, bytes); |
| 800 }); |
| 801 } |
| 802 return new PackageBundle.fromBuffer(bytes); |
794 } | 803 } |
795 | 804 |
796 Uri get uri => source.uri; | 805 Uri get uri => source.uri; |
797 | 806 |
798 /** | 807 /** |
799 * Return the [_File] for the [uri] referenced in this file. | 808 * Return the [_File] for the [uri] referenced in this file. |
800 */ | 809 */ |
801 _File resolveUri(String uri) { | 810 _File resolveUri(String uri) { |
802 // TODO(scheglov) Consider removing this caching after implementing other | 811 // TODO(scheglov) Consider removing this caching after implementing other |
803 // optimizations, e.g. changeFile() optimization. | 812 // optimizations, e.g. changeFile() optimization. |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
974 } | 983 } |
975 } | 984 } |
976 for (UnlinkedExportPublic export in unit.publicNamespace.exports) { | 985 for (UnlinkedExportPublic export in unit.publicNamespace.exports) { |
977 referenced.exported.add(export.uri); | 986 referenced.exported.add(export.uri); |
978 } | 987 } |
979 return referenced; | 988 return referenced; |
980 } | 989 } |
981 | 990 |
982 _ReferencedUris._(); | 991 _ReferencedUris._(); |
983 } | 992 } |
OLD | NEW |