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