| 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 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 * and [removeFile], the analysis state will eventually transition back to | 61 * and [removeFile], the analysis state will eventually transition back to |
| 62 * "idle" after a finite amount of processing. | 62 * "idle" after a finite amount of processing. |
| 63 * | 63 * |
| 64 * As a result of these guarantees, a client may ensure that the analysis | 64 * As a result of these guarantees, a client may ensure that the analysis |
| 65 * results are "eventually consistent" with the file system by simply calling | 65 * results are "eventually consistent" with the file system by simply calling |
| 66 * [changeFile] any time the contents of a file on the file system have changed. | 66 * [changeFile] any time the contents of a file on the file system have changed. |
| 67 * | 67 * |
| 68 * | 68 * |
| 69 * TODO(scheglov) Clean up the list of implicitly analyzed files. | 69 * TODO(scheglov) Clean up the list of implicitly analyzed files. |
| 70 */ | 70 */ |
| 71 class AnalysisDriver { | 71 class AnalysisDriver implements AnalysisDriverGeneric { |
| 72 /** | 72 /** |
| 73 * The version of data format, should be incremented on every format change. | 73 * The version of data format, should be incremented on every format change. |
| 74 */ | 74 */ |
| 75 static const int DATA_VERSION = 25; | 75 static const int DATA_VERSION = 25; |
| 76 | 76 |
| 77 /** | 77 /** |
| 78 * The number of exception contexts allowed to write. Once this field is | 78 * The number of exception contexts allowed to write. Once this field is |
| 79 * zero, we stop writing any new exception contexts in this process. | 79 * zero, we stop writing any new exception contexts in this process. |
| 80 */ | 80 */ |
| 81 static int allowedNumberOfContextsToWrite = 10; | 81 static int allowedNumberOfContextsToWrite = 10; |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 251 this.name, | 251 this.name, |
| 252 SourceFactory sourceFactory, | 252 SourceFactory sourceFactory, |
| 253 this._analysisOptions, | 253 this._analysisOptions, |
| 254 {PackageBundle sdkBundle, | 254 {PackageBundle sdkBundle, |
| 255 this.analyzeWithoutTasks: true}) | 255 this.analyzeWithoutTasks: true}) |
| 256 : _logger = logger, | 256 : _logger = logger, |
| 257 _sourceFactory = sourceFactory.clone(), | 257 _sourceFactory = sourceFactory.clone(), |
| 258 _sdkBundle = sdkBundle { | 258 _sdkBundle = sdkBundle { |
| 259 _testView = new AnalysisDriverTestView(this); | 259 _testView = new AnalysisDriverTestView(this); |
| 260 _createFileTracker(logger); | 260 _createFileTracker(logger); |
| 261 _scheduler._add(this); | 261 _scheduler.add(this); |
| 262 _search = new Search(this); | 262 _search = new Search(this); |
| 263 } | 263 } |
| 264 | 264 |
| 265 /** | 265 /** |
| 266 * Return the set of files explicitly added to analysis using [addFile]. | 266 * Return the set of files explicitly added to analysis using [addFile]. |
| 267 */ | 267 */ |
| 268 Set<String> get addedFiles => _fileTracker.addedFiles; | 268 Set<String> get addedFiles => _fileTracker.addedFiles; |
| 269 | 269 |
| 270 /** | 270 /** |
| 271 * Return the analysis options used to control analysis. | 271 * Return the analysis options used to control analysis. |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 363 * from file paths. | 363 * from file paths. |
| 364 */ | 364 */ |
| 365 SourceFactory get sourceFactory => _sourceFactory; | 365 SourceFactory get sourceFactory => _sourceFactory; |
| 366 | 366 |
| 367 @visibleForTesting | 367 @visibleForTesting |
| 368 AnalysisDriverTestView get test => _testView; | 368 AnalysisDriverTestView get test => _testView; |
| 369 | 369 |
| 370 /** | 370 /** |
| 371 * Return the priority of work that the driver needs to perform. | 371 * Return the priority of work that the driver needs to perform. |
| 372 */ | 372 */ |
| 373 AnalysisDriverPriority get _workPriority { | 373 AnalysisDriverPriority get workPriority { |
| 374 if (_requestedFiles.isNotEmpty) { | 374 if (_requestedFiles.isNotEmpty) { |
| 375 return AnalysisDriverPriority.interactive; | 375 return AnalysisDriverPriority.interactive; |
| 376 } | 376 } |
| 377 if (_definingClassMemberNameTasks.isNotEmpty || | 377 if (_definingClassMemberNameTasks.isNotEmpty || |
| 378 _referencingNameTasks.isNotEmpty) { | 378 _referencingNameTasks.isNotEmpty) { |
| 379 return AnalysisDriverPriority.interactive; | 379 return AnalysisDriverPriority.interactive; |
| 380 } | 380 } |
| 381 if (_indexRequestedFiles.isNotEmpty) { | 381 if (_indexRequestedFiles.isNotEmpty) { |
| 382 return AnalysisDriverPriority.interactive; | 382 return AnalysisDriverPriority.interactive; |
| 383 } | 383 } |
| (...skipping 542 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 926 * in the [library], e.g. element model, errors, index, etc. | 926 * in the [library], e.g. element model, errors, index, etc. |
| 927 */ | 927 */ |
| 928 String _getResolvedUnitSignature(FileState library, FileState file) { | 928 String _getResolvedUnitSignature(FileState library, FileState file) { |
| 929 ApiSignature signature = new ApiSignature(); | 929 ApiSignature signature = new ApiSignature(); |
| 930 signature.addUint32List(_salt); | 930 signature.addUint32List(_salt); |
| 931 signature.addString(library.transitiveSignature); | 931 signature.addString(library.transitiveSignature); |
| 932 signature.addString(file.contentHash); | 932 signature.addString(file.contentHash); |
| 933 return signature.toHex(); | 933 return signature.toHex(); |
| 934 } | 934 } |
| 935 | 935 |
| 936 ApiSignature getUnitKeyByPath(String path) { |
| 937 var file = fsState.getFileForPath(path); |
| 938 ApiSignature signature = new ApiSignature(); |
| 939 signature.addUint32List(_salt); |
| 940 signature.addString(file.transitiveSignature); |
| 941 return signature; |
| 942 } |
| 943 |
| 944 ApiSignature getResolvedUnitKeyByPath(String path) { |
| 945 ApiSignature signature = getUnitKeyByPath(path); |
| 946 var file = fsState.getFileForPath(path); |
| 947 signature.addString(file.contentHash); |
| 948 return signature; |
| 949 } |
| 950 |
| 936 /** | 951 /** |
| 937 * Return the lint code with the given [errorName], or `null` if there is no | 952 * Return the lint code with the given [errorName], or `null` if there is no |
| 938 * lint registered with that name or the lint is not enabled in the analysis | 953 * lint registered with that name or the lint is not enabled in the analysis |
| 939 * options. | 954 * options. |
| 940 */ | 955 */ |
| 941 ErrorCode _lintCodeByUniqueName(String errorName) { | 956 ErrorCode _lintCodeByUniqueName(String errorName) { |
| 942 if (errorName.startsWith('_LintCode.')) { | 957 if (errorName.startsWith('_LintCode.')) { |
| 943 String lintName = errorName.substring(10); | 958 String lintName = errorName.substring(10); |
| 944 List<Linter> lintRules = _analysisOptions.lintRules; | 959 List<Linter> lintRules = _analysisOptions.lintRules; |
| 945 for (Linter linter in lintRules) { | 960 for (Linter linter in lintRules) { |
| 946 if (linter.name == lintName) { | 961 if (linter.name == lintName) { |
| 947 return linter.lintCode; | 962 return linter.lintCode; |
| 948 } | 963 } |
| 949 } | 964 } |
| 950 } | 965 } |
| 951 return null; | 966 return null; |
| 952 } | 967 } |
| 953 | 968 |
| 954 /** | 969 /** |
| 955 * Perform a single chunk of work and produce [results]. | 970 * Perform a single chunk of work and produce [results]. |
| 956 */ | 971 */ |
| 957 Future<Null> _performWork() async { | 972 Future<Null> performWork() async { |
| 958 if (_fileTracker.verifyChangedFilesIfNeeded()) { | 973 if (_fileTracker.verifyChangedFilesIfNeeded()) { |
| 959 return; | 974 return; |
| 960 } | 975 } |
| 961 | 976 |
| 962 // Analyze a requested file. | 977 // Analyze a requested file. |
| 963 if (_requestedFiles.isNotEmpty) { | 978 if (_requestedFiles.isNotEmpty) { |
| 964 String path = _requestedFiles.keys.first; | 979 String path = _requestedFiles.keys.first; |
| 965 try { | 980 try { |
| 966 AnalysisResult result = _computeAnalysisResult(path, withUnit: true); | 981 AnalysisResult result = _computeAnalysisResult(path, withUnit: true); |
| 967 // If a part without a library, delay its analysis. | 982 // If a part without a library, delay its analysis. |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1206 | 1221 |
| 1207 _byteStore.put(key, bytes); | 1222 _byteStore.put(key, bytes); |
| 1208 return key; | 1223 return key; |
| 1209 } catch (_) { | 1224 } catch (_) { |
| 1210 return null; | 1225 return null; |
| 1211 } | 1226 } |
| 1212 } | 1227 } |
| 1213 } | 1228 } |
| 1214 | 1229 |
| 1215 /** | 1230 /** |
| 1231 * A generic schedulable interface via the AnalysisDriverScheduler. Currently |
| 1232 * only implemented by [AnalysisDriver] and the angular plugin, at least as |
| 1233 * a temporary measure until the official plugin API is ready (and a different |
| 1234 * scheduler is used) |
| 1235 */ |
| 1236 abstract class AnalysisDriverGeneric { |
| 1237 bool get hasFilesToAnalyze; |
| 1238 AnalysisDriverPriority get workPriority; |
| 1239 Future<Null> performWork(); |
| 1240 } |
| 1241 |
| 1242 /** |
| 1216 * Priorities of [AnalysisDriver] work. The farther a priority to the beginning | 1243 * Priorities of [AnalysisDriver] work. The farther a priority to the beginning |
| 1217 * of the list, the earlier the corresponding [AnalysisDriver] should be asked | 1244 * of the list, the earlier the corresponding [AnalysisDriver] should be asked |
| 1218 * to perform work. | 1245 * to perform work. |
| 1219 */ | 1246 */ |
| 1220 enum AnalysisDriverPriority { nothing, general, priority, interactive } | 1247 enum AnalysisDriverPriority { nothing, general, priority, interactive } |
| 1221 | 1248 |
| 1222 /** | 1249 /** |
| 1223 * Instances of this class schedule work in multiple [AnalysisDriver]s so that | 1250 * Instances of this class schedule work in multiple [AnalysisDriver]s so that |
| 1224 * work with the highest priority is performed first. | 1251 * work with the highest priority is performed first. |
| 1225 */ | 1252 */ |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1239 * be able to process `updateContent` or `setPriorityFiles` requests while | 1266 * be able to process `updateContent` or `setPriorityFiles` requests while |
| 1240 * background analysis is in progress. | 1267 * background analysis is in progress. |
| 1241 * | 1268 * |
| 1242 * The number of pumpings is arbitrary, might be changed if we see that | 1269 * The number of pumpings is arbitrary, might be changed if we see that |
| 1243 * analysis or other data processing tasks are starving. Ideally we would | 1270 * analysis or other data processing tasks are starving. Ideally we would |
| 1244 * need to run all asynchronous operations using a single global scheduler. | 1271 * need to run all asynchronous operations using a single global scheduler. |
| 1245 */ | 1272 */ |
| 1246 static const int _NUMBER_OF_EVENT_QUEUE_PUMPINGS = 128; | 1273 static const int _NUMBER_OF_EVENT_QUEUE_PUMPINGS = 128; |
| 1247 | 1274 |
| 1248 final PerformanceLog _logger; | 1275 final PerformanceLog _logger; |
| 1249 final List<AnalysisDriver> _drivers = []; | 1276 final List<AnalysisDriverGeneric> _drivers = []; |
| 1250 final Monitor _hasWork = new Monitor(); | 1277 final Monitor _hasWork = new Monitor(); |
| 1251 final StatusSupport _statusSupport = new StatusSupport(); | 1278 final StatusSupport _statusSupport = new StatusSupport(); |
| 1252 | 1279 |
| 1253 bool _started = false; | 1280 bool _started = false; |
| 1254 | 1281 |
| 1255 AnalysisDriverScheduler(this._logger); | 1282 AnalysisDriverScheduler(this._logger); |
| 1256 | 1283 |
| 1257 /** | 1284 /** |
| 1258 * Return `true` if we are currently analyzing code. | 1285 * Return `true` if we are currently analyzing code. |
| 1259 */ | 1286 */ |
| 1260 bool get isAnalyzing => _hasFilesToAnalyze; | 1287 bool get isAnalyzing => _hasFilesToAnalyze; |
| 1261 | 1288 |
| 1262 /** | 1289 /** |
| 1263 * Return the stream that produces [AnalysisStatus] events. | 1290 * Return the stream that produces [AnalysisStatus] events. |
| 1264 */ | 1291 */ |
| 1265 Stream<AnalysisStatus> get status => _statusSupport.stream; | 1292 Stream<AnalysisStatus> get status => _statusSupport.stream; |
| 1266 | 1293 |
| 1267 /** | 1294 /** |
| 1268 * Return `true` if there is a driver with a file to analyze. | 1295 * Return `true` if there is a driver with a file to analyze. |
| 1269 */ | 1296 */ |
| 1270 bool get _hasFilesToAnalyze { | 1297 bool get _hasFilesToAnalyze { |
| 1271 for (AnalysisDriver driver in _drivers) { | 1298 for (AnalysisDriverGeneric driver in _drivers) { |
| 1272 if (driver.hasFilesToAnalyze) { | 1299 if (driver.hasFilesToAnalyze) { |
| 1273 return true; | 1300 return true; |
| 1274 } | 1301 } |
| 1275 } | 1302 } |
| 1276 return false; | 1303 return false; |
| 1277 } | 1304 } |
| 1278 | 1305 |
| 1279 /** | 1306 /** |
| 1280 * Notify that there is a change to the [driver], it it might need to | 1307 * Notify that there is a change to the [driver], it it might need to |
| 1281 * perform some work. | 1308 * perform some work. |
| 1282 */ | 1309 */ |
| 1283 void notify(AnalysisDriver driver) { | 1310 void notify(AnalysisDriverGeneric driver) { |
| 1284 _hasWork.notify(); | 1311 _hasWork.notify(); |
| 1285 _statusSupport.preTransitionToAnalyzing(); | 1312 _statusSupport.preTransitionToAnalyzing(); |
| 1286 } | 1313 } |
| 1287 | 1314 |
| 1288 /** | 1315 /** |
| 1289 * Start the scheduler, so that any [AnalysisDriver] created before or | 1316 * Start the scheduler, so that any [AnalysisDriver] created before or |
| 1290 * after will be asked to perform work. | 1317 * after will be asked to perform work. |
| 1291 */ | 1318 */ |
| 1292 void start() { | 1319 void start() { |
| 1293 if (_started) { | 1320 if (_started) { |
| 1294 throw new StateError('The scheduler has already been started.'); | 1321 throw new StateError('The scheduler has already been started.'); |
| 1295 } | 1322 } |
| 1296 _started = true; | 1323 _started = true; |
| 1297 _run(); | 1324 _run(); |
| 1298 } | 1325 } |
| 1299 | 1326 |
| 1300 /** | 1327 /** |
| 1301 * Return a future that will be completed the next time the status is idle. | 1328 * Return a future that will be completed the next time the status is idle. |
| 1302 * | 1329 * |
| 1303 * If the status is currently idle, the returned future will be signaled | 1330 * If the status is currently idle, the returned future will be signaled |
| 1304 * immediately. | 1331 * immediately. |
| 1305 */ | 1332 */ |
| 1306 Future<Null> waitForIdle() => _statusSupport.waitForIdle(); | 1333 Future<Null> waitForIdle() => _statusSupport.waitForIdle(); |
| 1307 | 1334 |
| 1308 /** | 1335 /** |
| 1309 * Add the given [driver] and schedule it to perform its work. | 1336 * Add the given [driver] and schedule it to perform its work. |
| 1310 */ | 1337 */ |
| 1311 void _add(AnalysisDriver driver) { | 1338 void add(AnalysisDriverGeneric driver) { |
| 1312 _drivers.add(driver); | 1339 _drivers.add(driver); |
| 1313 _hasWork.notify(); | 1340 _hasWork.notify(); |
| 1314 } | 1341 } |
| 1315 | 1342 |
| 1316 /** | 1343 /** |
| 1317 * Remove the given [driver] from the scheduler, so that it will not be | 1344 * Remove the given [driver] from the scheduler, so that it will not be |
| 1318 * asked to perform any new work. | 1345 * asked to perform any new work. |
| 1319 */ | 1346 */ |
| 1320 void _remove(AnalysisDriver driver) { | 1347 void _remove(AnalysisDriverGeneric driver) { |
| 1321 _drivers.remove(driver); | 1348 _drivers.remove(driver); |
| 1322 _hasWork.notify(); | 1349 _hasWork.notify(); |
| 1323 } | 1350 } |
| 1324 | 1351 |
| 1325 /** | 1352 /** |
| 1326 * Run infinitely analysis cycle, selecting the drivers with the highest | 1353 * Run infinitely analysis cycle, selecting the drivers with the highest |
| 1327 * priority first. | 1354 * priority first. |
| 1328 */ | 1355 */ |
| 1329 Future<Null> _run() async { | 1356 Future<Null> _run() async { |
| 1330 Stopwatch timer = new Stopwatch()..start(); | 1357 Stopwatch timer = new Stopwatch()..start(); |
| 1331 PerformanceLogSection analysisSection; | 1358 PerformanceLogSection analysisSection; |
| 1332 while (true) { | 1359 while (true) { |
| 1333 // Pump the event queue. | 1360 // Pump the event queue. |
| 1334 if (timer.elapsedMilliseconds > _MS_BEFORE_PUMPING_EVENT_QUEUE) { | 1361 if (timer.elapsedMilliseconds > _MS_BEFORE_PUMPING_EVENT_QUEUE) { |
| 1335 await _pumpEventQueue(_NUMBER_OF_EVENT_QUEUE_PUMPINGS); | 1362 await _pumpEventQueue(_NUMBER_OF_EVENT_QUEUE_PUMPINGS); |
| 1336 timer.reset(); | 1363 timer.reset(); |
| 1337 } | 1364 } |
| 1338 | 1365 |
| 1339 await _hasWork.signal; | 1366 await _hasWork.signal; |
| 1340 | 1367 |
| 1341 // Transition to analyzing if there are files to analyze. | 1368 // Transition to analyzing if there are files to analyze. |
| 1342 if (_hasFilesToAnalyze) { | 1369 if (_hasFilesToAnalyze) { |
| 1343 _statusSupport.transitionToAnalyzing(); | 1370 _statusSupport.transitionToAnalyzing(); |
| 1344 analysisSection ??= _logger.enter('Analyzing'); | 1371 analysisSection ??= _logger.enter('Analyzing'); |
| 1345 } | 1372 } |
| 1346 | 1373 |
| 1347 // Find the driver with the highest priority. | 1374 // Find the driver with the highest priority. |
| 1348 AnalysisDriver bestDriver; | 1375 AnalysisDriverGeneric bestDriver; |
| 1349 AnalysisDriverPriority bestPriority = AnalysisDriverPriority.nothing; | 1376 AnalysisDriverPriority bestPriority = AnalysisDriverPriority.nothing; |
| 1350 for (AnalysisDriver driver in _drivers) { | 1377 for (AnalysisDriver driver in _drivers) { |
| 1351 AnalysisDriverPriority priority = driver._workPriority; | 1378 AnalysisDriverPriority priority = driver.workPriority; |
| 1352 if (priority.index > bestPriority.index) { | 1379 if (priority.index > bestPriority.index) { |
| 1353 bestDriver = driver; | 1380 bestDriver = driver; |
| 1354 bestPriority = priority; | 1381 bestPriority = priority; |
| 1355 } | 1382 } |
| 1356 } | 1383 } |
| 1357 | 1384 |
| 1358 // Transition to idle if no files to analyze. | 1385 // Transition to idle if no files to analyze. |
| 1359 if (!_hasFilesToAnalyze) { | 1386 if (!_hasFilesToAnalyze) { |
| 1360 _statusSupport.transitionToIdle(); | 1387 _statusSupport.transitionToIdle(); |
| 1361 analysisSection?.exit(); | 1388 analysisSection?.exit(); |
| 1362 analysisSection = null; | 1389 analysisSection = null; |
| 1363 } | 1390 } |
| 1364 | 1391 |
| 1365 // Continue to sleep if no work to do. | 1392 // Continue to sleep if no work to do. |
| 1366 if (bestPriority == AnalysisDriverPriority.nothing) { | 1393 if (bestPriority == AnalysisDriverPriority.nothing) { |
| 1367 continue; | 1394 continue; |
| 1368 } | 1395 } |
| 1369 | 1396 |
| 1370 // Ask the driver to perform a chunk of work. | 1397 // Ask the driver to perform a chunk of work. |
| 1371 await bestDriver._performWork(); | 1398 await bestDriver.performWork(); |
| 1372 | 1399 |
| 1373 // Schedule one more cycle. | 1400 // Schedule one more cycle. |
| 1374 _hasWork.notify(); | 1401 _hasWork.notify(); |
| 1375 } | 1402 } |
| 1376 } | 1403 } |
| 1377 | 1404 |
| 1378 /** | 1405 /** |
| 1379 * Returns a [Future] that completes after performing [times] pumpings of | 1406 * Returns a [Future] that completes after performing [times] pumpings of |
| 1380 * the event queue. | 1407 * the event queue. |
| 1381 */ | 1408 */ |
| (...skipping 519 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1901 libraryDeclarations.add(new TopLevelDeclarationInSource( | 1928 libraryDeclarations.add(new TopLevelDeclarationInSource( |
| 1902 file.source, declaration, isExported)); | 1929 file.source, declaration, isExported)); |
| 1903 } | 1930 } |
| 1904 } | 1931 } |
| 1905 } | 1932 } |
| 1906 | 1933 |
| 1907 // We're not done yet. | 1934 // We're not done yet. |
| 1908 return false; | 1935 return false; |
| 1909 } | 1936 } |
| 1910 } | 1937 } |
| OLD | NEW |