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:typed_data'; | 7 import 'dart:typed_data'; |
| 8 | 8 |
| 9 import 'package:analyzer/context/declared_variables.dart'; | 9 import 'package:analyzer/context/declared_variables.dart'; |
| 10 import 'package:analyzer/dart/ast/ast.dart'; | 10 import 'package:analyzer/dart/ast/ast.dart'; |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 70 * | 70 * |
| 71 * TODO(scheglov) Clean up the list of implicitly analyzed files. | 71 * TODO(scheglov) Clean up the list of implicitly analyzed files. |
| 72 */ | 72 */ |
| 73 class AnalysisDriver { | 73 class AnalysisDriver { |
| 74 /** | 74 /** |
| 75 * The version of data format, should be incremented on every format change. | 75 * The version of data format, should be incremented on every format change. |
| 76 */ | 76 */ |
| 77 static const int DATA_VERSION = 15; | 77 static const int DATA_VERSION = 15; |
| 78 | 78 |
| 79 /** | 79 /** |
| 80 * The number of exception contexts allowed to write. Once this field is | |
| 81 * zero, we stop writing any new exception contexts in this process. | |
| 82 */ | |
| 83 static int allowedNumberOfContextsToWrite = 10; | |
| 84 | |
| 85 /** | |
| 80 * The name of the driver, e.g. the name of the folder. | 86 * The name of the driver, e.g. the name of the folder. |
| 81 */ | 87 */ |
| 82 final String name; | 88 final String name; |
| 83 | 89 |
| 84 /** | 90 /** |
| 85 * The scheduler that schedules analysis work in this, and possibly other | 91 * The scheduler that schedules analysis work in this, and possibly other |
| 86 * analysis drivers. | 92 * analysis drivers. |
| 87 */ | 93 */ |
| 88 final AnalysisDriverScheduler _scheduler; | 94 final AnalysisDriverScheduler _scheduler; |
| 89 | 95 |
| (...skipping 635 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 725 // We need the fully resolved unit, or the result is not cached. | 731 // We need the fully resolved unit, or the result is not cached. |
| 726 return _logger.run('Compute analysis result for $path', () { | 732 return _logger.run('Compute analysis result for $path', () { |
| 727 FileState file = _verifyApiSignature(path); | 733 FileState file = _verifyApiSignature(path); |
| 728 | 734 |
| 729 // Prepare the library file - the file itself, or the known library. | 735 // Prepare the library file - the file itself, or the known library. |
| 730 FileState libraryFile = getLibraryFile(file); | 736 FileState libraryFile = getLibraryFile(file); |
| 731 if (libraryFile == null) { | 737 if (libraryFile == null) { |
| 732 return null; | 738 return null; |
| 733 } | 739 } |
| 734 | 740 |
| 735 _LibraryContext libraryContext = _createLibraryContext(libraryFile); | |
| 736 AnalysisContext analysisContext = _createAnalysisContext(libraryContext); | |
| 737 try { | 741 try { |
| 738 CompilationUnit resolvedUnit = analysisContext.resolveCompilationUnit2( | 742 _LibraryContext libraryContext = _createLibraryContext(libraryFile); |
| 739 file.source, libraryFile.source); | 743 AnalysisContext analysisContext = |
| 740 List<AnalysisError> errors = analysisContext.computeErrors(file.source); | 744 _createAnalysisContext(libraryContext); |
| 741 AnalysisDriverUnitIndexBuilder index = indexUnit(resolvedUnit); | 745 try { |
| 746 CompilationUnit resolvedUnit = analysisContext | |
| 747 .resolveCompilationUnit2(file.source, libraryFile.source); | |
| 748 List<AnalysisError> errors = | |
| 749 analysisContext.computeErrors(file.source); | |
| 750 AnalysisDriverUnitIndexBuilder index = indexUnit(resolvedUnit); | |
| 742 | 751 |
| 743 // Store the result into the cache. | 752 // Store the result into the cache. |
| 744 List<int> bytes; | 753 List<int> bytes; |
| 745 { | 754 { |
| 746 bytes = new AnalysisDriverResolvedUnitBuilder( | 755 bytes = new AnalysisDriverResolvedUnitBuilder( |
| 747 errors: errors | 756 errors: errors |
| 748 .map((error) => new AnalysisDriverUnitErrorBuilder( | 757 .map((error) => new AnalysisDriverUnitErrorBuilder( |
| 749 offset: error.offset, | 758 offset: error.offset, |
| 750 length: error.length, | 759 length: error.length, |
| 751 uniqueName: error.errorCode.uniqueName, | 760 uniqueName: error.errorCode.uniqueName, |
| 752 message: error.message, | 761 message: error.message, |
| 753 correction: error.correction)) | 762 correction: error.correction)) |
| 754 .toList(), | 763 .toList(), |
| 755 index: index) | 764 index: index) |
| 756 .toBuffer(); | 765 .toBuffer(); |
| 757 String key = _getResolvedUnitKey(libraryFile, file); | 766 String key = _getResolvedUnitKey(libraryFile, file); |
| 758 _byteStore.put(key, bytes); | 767 _byteStore.put(key, bytes); |
| 768 } | |
| 769 | |
| 770 // Return the result, full or partial. | |
| 771 _logger.writeln('Computed new analysis result.'); | |
| 772 AnalysisResult result = _getAnalysisResultFromBytes(file, bytes, | |
| 773 content: withUnit ? file.content : null, | |
| 774 withErrors: _addedFiles.contains(path), | |
| 775 resolvedUnit: withUnit ? resolvedUnit : null); | |
| 776 if (withUnit && _priorityFiles.contains(path)) { | |
| 777 _priorityResults[path] = result; | |
| 778 } | |
| 779 return result; | |
| 780 } finally { | |
| 781 analysisContext.dispose(); | |
| 759 } | 782 } |
| 760 | 783 } catch (exception, stackTrace) { |
| 761 // Return the result, full or partial. | 784 String contextKey = |
| 762 _logger.writeln('Computed new analysis result.'); | 785 _storeExceptionContext(path, libraryFile, exception, stackTrace); |
| 763 AnalysisResult result = _getAnalysisResultFromBytes(file, bytes, | 786 throw new _ExceptionState(exception, stackTrace, contextKey); |
| 764 content: withUnit ? file.content : null, | |
| 765 withErrors: _addedFiles.contains(path), | |
| 766 resolvedUnit: withUnit ? resolvedUnit : null); | |
| 767 if (withUnit && _priorityFiles.contains(path)) { | |
| 768 _priorityResults[path] = result; | |
| 769 } | |
| 770 return result; | |
| 771 } finally { | |
| 772 analysisContext.dispose(); | |
| 773 } | 787 } |
| 774 }); | 788 }); |
| 775 } | 789 } |
| 776 | 790 |
| 777 AnalysisDriverUnitIndex _computeIndex(String path) { | 791 AnalysisDriverUnitIndex _computeIndex(String path) { |
| 778 AnalysisResult analysisResult = _computeAnalysisResult(path, | 792 AnalysisResult analysisResult = _computeAnalysisResult(path, |
| 779 withUnit: false, asIsIfPartWithoutLibrary: true); | 793 withUnit: false, asIsIfPartWithoutLibrary: true); |
| 780 return analysisResult._index; | 794 return analysisResult._index; |
| 781 } | 795 } |
| 782 | 796 |
| (...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1069 if (_filesToAnalyze.remove(path)) { | 1083 if (_filesToAnalyze.remove(path)) { |
| 1070 try { | 1084 try { |
| 1071 AnalysisResult result = | 1085 AnalysisResult result = |
| 1072 _computeAnalysisResult(path, withUnit: true); | 1086 _computeAnalysisResult(path, withUnit: true); |
| 1073 if (result == null) { | 1087 if (result == null) { |
| 1074 _partsToAnalyze.add(path); | 1088 _partsToAnalyze.add(path); |
| 1075 } else { | 1089 } else { |
| 1076 _resultController.add(result); | 1090 _resultController.add(result); |
| 1077 } | 1091 } |
| 1078 } catch (exception, stackTrace) { | 1092 } catch (exception, stackTrace) { |
| 1079 _reportError(path, exception, stackTrace); | 1093 _reportException(path, exception, stackTrace); |
| 1080 } | 1094 } |
| 1081 return; | 1095 return; |
| 1082 } | 1096 } |
| 1083 } | 1097 } |
| 1084 } | 1098 } |
| 1085 | 1099 |
| 1086 // Analyze a general file. | 1100 // Analyze a general file. |
| 1087 if (_filesToAnalyze.isNotEmpty) { | 1101 if (_filesToAnalyze.isNotEmpty) { |
| 1088 String path = _removeFirst(_filesToAnalyze); | 1102 String path = _removeFirst(_filesToAnalyze); |
| 1089 try { | 1103 try { |
| 1090 AnalysisResult result = _computeAnalysisResult(path, withUnit: false); | 1104 AnalysisResult result = _computeAnalysisResult(path, withUnit: false); |
| 1091 if (result == null) { | 1105 if (result == null) { |
| 1092 _partsToAnalyze.add(path); | 1106 _partsToAnalyze.add(path); |
| 1093 } else { | 1107 } else { |
| 1094 _resultController.add(result); | 1108 _resultController.add(result); |
| 1095 } | 1109 } |
| 1096 } catch (exception, stackTrace) { | 1110 } catch (exception, stackTrace) { |
| 1097 _reportError(path, exception, stackTrace); | 1111 _reportException(path, exception, stackTrace); |
| 1098 } | 1112 } |
| 1099 return; | 1113 return; |
| 1100 } | 1114 } |
| 1101 | 1115 |
| 1102 // Analyze a requested part file. | 1116 // Analyze a requested part file. |
| 1103 if (_requestedParts.isNotEmpty) { | 1117 if (_requestedParts.isNotEmpty) { |
| 1104 String path = _requestedParts.keys.first; | 1118 String path = _requestedParts.keys.first; |
| 1105 try { | 1119 try { |
| 1106 AnalysisResult result = _computeAnalysisResult(path, | 1120 AnalysisResult result = _computeAnalysisResult(path, |
| 1107 withUnit: true, asIsIfPartWithoutLibrary: true); | 1121 withUnit: true, asIsIfPartWithoutLibrary: true); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 1123 | 1137 |
| 1124 // Analyze a general part. | 1138 // Analyze a general part. |
| 1125 if (_partsToAnalyze.isNotEmpty) { | 1139 if (_partsToAnalyze.isNotEmpty) { |
| 1126 String path = _removeFirst(_partsToAnalyze); | 1140 String path = _removeFirst(_partsToAnalyze); |
| 1127 try { | 1141 try { |
| 1128 AnalysisResult result = _computeAnalysisResult(path, | 1142 AnalysisResult result = _computeAnalysisResult(path, |
| 1129 withUnit: _priorityFiles.contains(path), | 1143 withUnit: _priorityFiles.contains(path), |
| 1130 asIsIfPartWithoutLibrary: true); | 1144 asIsIfPartWithoutLibrary: true); |
| 1131 _resultController.add(result); | 1145 _resultController.add(result); |
| 1132 } catch (exception, stackTrace) { | 1146 } catch (exception, stackTrace) { |
| 1133 _reportError(path, exception, stackTrace); | 1147 _reportException(path, exception, stackTrace); |
| 1134 } | 1148 } |
| 1135 return; | 1149 return; |
| 1136 } | 1150 } |
| 1137 } | 1151 } |
| 1138 | 1152 |
| 1139 void _reportError(String path, exception, StackTrace stackTrace) { | 1153 void _reportException(String path, exception, StackTrace stackTrace) { |
| 1154 String contextKey = null; | |
| 1155 if (exception is _ExceptionState) { | |
| 1156 var state = exception as _ExceptionState; | |
| 1157 exception = state.exception; | |
| 1158 stackTrace = state.stackTrace; | |
| 1159 contextKey = state.contextKey; | |
| 1160 } | |
| 1140 CaughtException caught = new CaughtException(exception, stackTrace); | 1161 CaughtException caught = new CaughtException(exception, stackTrace); |
| 1141 _exceptionController.add(new ExceptionResult(path, caught)); | 1162 _exceptionController.add(new ExceptionResult(path, caught, contextKey)); |
| 1163 } | |
| 1164 | |
| 1165 String _storeExceptionContext( | |
| 1166 String path, FileState libraryFile, exception, StackTrace stackTrace) { | |
| 1167 if (allowedNumberOfContextsToWrite > 0) { | |
| 1168 allowedNumberOfContextsToWrite--; | |
| 1169 } | |
| 1170 try { | |
| 1171 List<AnalysisDriverExceptionFileBuilder> contextFiles = libraryFile | |
| 1172 .transitiveFiles | |
| 1173 .map((file) => new AnalysisDriverExceptionFileBuilder( | |
| 1174 path: file.path, content: file.content)) | |
| 1175 .toList(); | |
| 1176 contextFiles.sort((a, b) => a.path.compareTo(b.path)); | |
| 1177 AnalysisDriverExceptionContextBuilder contextBuilder = | |
| 1178 new AnalysisDriverExceptionContextBuilder( | |
| 1179 path: path, | |
| 1180 exception: exception.toString(), | |
| 1181 stackTrace: stackTrace.toString(), | |
| 1182 files: contextFiles); | |
| 1183 List<int> bytes = contextBuilder.toBuffer(); | |
| 1184 | |
| 1185 String _twoDigits(int n) { | |
| 1186 if (n >= 10) return '$n'; | |
| 1187 return '0$n'; | |
| 1188 } | |
| 1189 | |
| 1190 String _threeDigits(int n) { | |
| 1191 if (n >= 100) return '$n'; | |
| 1192 if (n >= 10) return '0$n'; | |
| 1193 return '00$n'; | |
| 1194 } | |
| 1195 | |
| 1196 DateTime time = new DateTime.now(); | |
| 1197 String m = _twoDigits(time.month); | |
| 1198 String d = _twoDigits(time.day); | |
| 1199 String h = _twoDigits(time.hour); | |
| 1200 String min = _twoDigits(time.minute); | |
| 1201 String sec = _twoDigits(time.second); | |
| 1202 String ms = _threeDigits(time.millisecond); | |
| 1203 String key = 'exception_${time.year}$m$d' '_$h$min$sec' + '_$ms'; | |
| 1204 | |
| 1205 _byteStore.put(key, bytes); | |
| 1206 return key; | |
| 1207 } catch (_) { | |
| 1208 return null; | |
| 1209 } | |
| 1142 } | 1210 } |
| 1143 | 1211 |
| 1144 /** | 1212 /** |
| 1145 * Verify the API signature for the file with the given [path], and decide | 1213 * Verify the API signature for the file with the given [path], and decide |
| 1146 * which linked libraries should be invalidated, and files reanalyzed. | 1214 * which linked libraries should be invalidated, and files reanalyzed. |
| 1147 */ | 1215 */ |
| 1148 FileState _verifyApiSignature(String path) { | 1216 FileState _verifyApiSignature(String path) { |
| 1149 return _logger.run('Verify API signature of $path', () { | 1217 return _logger.run('Verify API signature of $path', () { |
| 1150 bool anyApiChanged = false; | 1218 bool anyApiChanged = false; |
| 1151 List<FileState> files = _fsState.getFilesForPath(path); | 1219 List<FileState> files = _fsState.getFilesForPath(path); |
| (...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1480 * | 1548 * |
| 1481 * Absolute and normalized. | 1549 * Absolute and normalized. |
| 1482 */ | 1550 */ |
| 1483 final String path; | 1551 final String path; |
| 1484 | 1552 |
| 1485 /** | 1553 /** |
| 1486 * The exception during analysis of the file with the [path]. | 1554 * The exception during analysis of the file with the [path]. |
| 1487 */ | 1555 */ |
| 1488 final CaughtException exception; | 1556 final CaughtException exception; |
| 1489 | 1557 |
| 1490 ExceptionResult(this.path, this.exception); | 1558 /** |
| 1559 * If the exception happened during a file analysis, and the context in which | |
| 1560 * the exception happened was stores, this field is the key of the context | |
|
Paul Berry
2017/01/30 20:16:41
s/stores/stored/
| |
| 1561 * in the byte store. May be `null` if the context is unknown, the maximum | |
| 1562 * number of context to store was reached, etc. | |
| 1563 */ | |
| 1564 final String contextKey; | |
| 1565 | |
| 1566 ExceptionResult(this.path, this.exception, this.contextKey); | |
| 1491 } | 1567 } |
| 1492 | 1568 |
| 1493 /** | 1569 /** |
| 1494 * The result of parsing of a single file. | 1570 * The result of parsing of a single file. |
| 1495 * | 1571 * |
| 1496 * These results are self-consistent, i.e. [content], [contentHash], the | 1572 * These results are self-consistent, i.e. [content], [contentHash], the |
| 1497 * resolved [unit] correspond to each other. But none of the results is | 1573 * resolved [unit] correspond to each other. But none of the results is |
| 1498 * guaranteed to be consistent with the state of the files. | 1574 * guaranteed to be consistent with the state of the files. |
| 1499 */ | 1575 */ |
| 1500 class ParseResult { | 1576 class ParseResult { |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1652 throw new UnimplementedError(); | 1728 throw new UnimplementedError(); |
| 1653 } | 1729 } |
| 1654 | 1730 |
| 1655 FileState _getFileForSource(Source source) { | 1731 FileState _getFileForSource(Source source) { |
| 1656 String path = source.fullName; | 1732 String path = source.fullName; |
| 1657 return fsState.getFileForPath(path); | 1733 return fsState.getFileForPath(path); |
| 1658 } | 1734 } |
| 1659 } | 1735 } |
| 1660 | 1736 |
| 1661 /** | 1737 /** |
| 1738 * Information about an exception and its context. | |
| 1739 */ | |
| 1740 class _ExceptionState { | |
| 1741 final exception; | |
| 1742 final StackTrace stackTrace; | |
| 1743 | |
| 1744 /** | |
| 1745 * The key under which the context of the exception was stored, or `null` | |
| 1746 * if unknown, the maximum number of context to store was reached, etc. | |
| 1747 */ | |
| 1748 final String contextKey; | |
| 1749 | |
| 1750 _ExceptionState(this.exception, this.stackTrace, this.contextKey); | |
| 1751 } | |
| 1752 | |
| 1753 /** | |
| 1662 * Task that computes the list of files that were added to the driver and | 1754 * Task that computes the list of files that were added to the driver and |
| 1663 * have at least one reference to an identifier [name] defined outside of the | 1755 * have at least one reference to an identifier [name] defined outside of the |
| 1664 * file. | 1756 * file. |
| 1665 */ | 1757 */ |
| 1666 class _FilesReferencingNameTask { | 1758 class _FilesReferencingNameTask { |
| 1667 static const int _MS_WORK_INTERVAL = 5; | 1759 static const int _MS_WORK_INTERVAL = 5; |
| 1668 | 1760 |
| 1669 final AnalysisDriver driver; | 1761 final AnalysisDriver driver; |
| 1670 final String name; | 1762 final String name; |
| 1671 final Completer<List<String>> completer = new Completer<List<String>>(); | 1763 final Completer<List<String>> completer = new Completer<List<String>>(); |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1777 libraryDeclarations.add(new TopLevelDeclarationInSource( | 1869 libraryDeclarations.add(new TopLevelDeclarationInSource( |
| 1778 file.source, declaration, isExported)); | 1870 file.source, declaration, isExported)); |
| 1779 } | 1871 } |
| 1780 } | 1872 } |
| 1781 } | 1873 } |
| 1782 | 1874 |
| 1783 // We're not done yet. | 1875 // We're not done yet. |
| 1784 return false; | 1876 return false; |
| 1785 } | 1877 } |
| 1786 } | 1878 } |
| OLD | NEW |