| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 library analysis.server; | 5 library analysis.server; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:collection'; | 8 import 'dart:collection'; |
| 9 import 'dart:core' hide Resource; | 9 import 'dart:core' hide Resource; |
| 10 import 'dart:math' show max; | 10 import 'dart:math' show max; |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 265 /** | 265 /** |
| 266 * If the "analysis.analyzedFiles" notification is currently being subscribed | 266 * If the "analysis.analyzedFiles" notification is currently being subscribed |
| 267 * to (see [generalAnalysisServices]), and at least one such notification has | 267 * to (see [generalAnalysisServices]), and at least one such notification has |
| 268 * been sent since the subscription was enabled, the set of analyzed files | 268 * been sent since the subscription was enabled, the set of analyzed files |
| 269 * that was delivered in the most recently sent notification. Otherwise | 269 * that was delivered in the most recently sent notification. Otherwise |
| 270 * `null`. | 270 * `null`. |
| 271 */ | 271 */ |
| 272 Set<String> prevAnalyzedFiles; | 272 Set<String> prevAnalyzedFiles; |
| 273 | 273 |
| 274 /** | 274 /** |
| 275 * The default options used to create new analysis contexts. |
| 276 */ |
| 277 AnalysisOptionsImpl defaultContextOptions = new AnalysisOptionsImpl(); |
| 278 |
| 279 /** |
| 280 * The controller for sending [ContextsChangedEvent]s. |
| 281 */ |
| 282 StreamController<ContextsChangedEvent> _onContextsChangedController = |
| 283 new StreamController<ContextsChangedEvent>.broadcast(); |
| 284 |
| 285 /** |
| 275 * Initialize a newly created server to receive requests from and send | 286 * Initialize a newly created server to receive requests from and send |
| 276 * responses to the given [channel]. | 287 * responses to the given [channel]. |
| 277 * | 288 * |
| 278 * If a [contextManager] is provided, then the [packageResolverProvider] will | 289 * If a [contextManager] is provided, then the [packageResolverProvider] will |
| 279 * be ignored. | 290 * be ignored. |
| 280 * | 291 * |
| 281 * If [rethrowExceptions] is true, then any exceptions thrown by analysis are | 292 * If [rethrowExceptions] is true, then any exceptions thrown by analysis are |
| 282 * propagated up the call stack. The default is true to allow analysis | 293 * propagated up the call stack. The default is true to allow analysis |
| 283 * exceptions to show up in unit tests, but it should be set to false when | 294 * exceptions to show up in unit tests, but it should be set to false when |
| 284 * running a full analysis server. | 295 * running a full analysis server. |
| 285 */ | 296 */ |
| 286 AnalysisServer(this.channel, this.resourceProvider, | 297 AnalysisServer(this.channel, this.resourceProvider, |
| 287 OptimizingPubPackageMapProvider packageMapProvider, Index _index, | 298 OptimizingPubPackageMapProvider packageMapProvider, Index _index, |
| 288 this.serverPlugin, this.options, this.defaultSdk, | 299 this.serverPlugin, this.options, this.defaultSdk, |
| 289 this.instrumentationService, {ContextManager contextManager: null, | 300 this.instrumentationService, {ContextManager contextManager: null, |
| 290 ResolverProvider packageResolverProvider: null, | 301 ResolverProvider packageResolverProvider: null, |
| 291 this.rethrowExceptions: true}) | 302 this.rethrowExceptions: true}) |
| 292 : index = _index, | 303 : index = _index, |
| 293 searchEngine = _index != null ? createSearchEngine(_index) : null { | 304 searchEngine = _index != null ? createSearchEngine(_index) : null { |
| 294 _performance = performanceDuringStartup; | 305 _performance = performanceDuringStartup; |
| 295 operationQueue = new ServerOperationQueue(); | 306 operationQueue = new ServerOperationQueue(); |
| 296 if (contextManager == null) { | 307 if (contextManager == null) { |
| 297 contextManager = new ContextManagerImpl(resourceProvider, | 308 contextManager = new ContextManagerImpl(resourceProvider, |
| 298 packageResolverProvider, packageMapProvider, instrumentationService); | 309 packageResolverProvider, packageMapProvider, instrumentationService); |
| 299 } | 310 } |
| 300 ServerContextManagerCallbacks contextManagerCallbacks = | 311 ServerContextManagerCallbacks contextManagerCallbacks = |
| 301 new ServerContextManagerCallbacks(this, resourceProvider); | 312 new ServerContextManagerCallbacks(this, resourceProvider); |
| 302 contextManager.callbacks = contextManagerCallbacks; | 313 contextManager.callbacks = contextManagerCallbacks; |
| 303 AnalysisOptionsImpl analysisOptions = | 314 defaultContextOptions.incremental = true; |
| 304 contextManagerCallbacks.defaultOptions; | 315 defaultContextOptions.incrementalApi = |
| 305 analysisOptions.incremental = true; | 316 options.enableIncrementalResolutionApi; |
| 306 analysisOptions.incrementalApi = options.enableIncrementalResolutionApi; | 317 defaultContextOptions.incrementalValidation = |
| 307 analysisOptions.incrementalValidation = | |
| 308 options.enableIncrementalResolutionValidation; | 318 options.enableIncrementalResolutionValidation; |
| 309 analysisOptions.generateImplicitErrors = false; | 319 defaultContextOptions.generateImplicitErrors = false; |
| 310 this.contextManager = contextManager; | 320 this.contextManager = contextManager; |
| 311 _noErrorNotification = options.noErrorNotification; | 321 _noErrorNotification = options.noErrorNotification; |
| 312 AnalysisEngine.instance.logger = new AnalysisLogger(); | 322 AnalysisEngine.instance.logger = new AnalysisLogger(); |
| 313 _onAnalysisStartedController = new StreamController.broadcast(); | 323 _onAnalysisStartedController = new StreamController.broadcast(); |
| 314 _onFileAnalyzedController = new StreamController.broadcast(); | 324 _onFileAnalyzedController = new StreamController.broadcast(); |
| 315 _onPriorityChangeController = | 325 _onPriorityChangeController = |
| 316 new StreamController<PriorityChangeEvent>.broadcast(); | 326 new StreamController<PriorityChangeEvent>.broadcast(); |
| 317 running = true; | 327 running = true; |
| 318 onAnalysisStarted.first.then((_) { | 328 onAnalysisStarted.first.then((_) { |
| 319 onAnalysisComplete.then((_) { | 329 onAnalysisComplete.then((_) { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 345 * The stream that is notified when analysis of a context is started. | 355 * The stream that is notified when analysis of a context is started. |
| 346 */ | 356 */ |
| 347 Stream<AnalysisContext> get onAnalysisStarted { | 357 Stream<AnalysisContext> get onAnalysisStarted { |
| 348 return _onAnalysisStartedController.stream; | 358 return _onAnalysisStartedController.stream; |
| 349 } | 359 } |
| 350 | 360 |
| 351 /** | 361 /** |
| 352 * The stream that is notified when contexts are added or removed. | 362 * The stream that is notified when contexts are added or removed. |
| 353 */ | 363 */ |
| 354 Stream<ContextsChangedEvent> get onContextsChanged => | 364 Stream<ContextsChangedEvent> get onContextsChanged => |
| 355 (contextManager.callbacks as ServerContextManagerCallbacks).onContextsChan
ged; | 365 _onContextsChangedController.stream; |
| 356 | 366 |
| 357 /** | 367 /** |
| 358 * The stream that is notified when a single file has been analyzed. | 368 * The stream that is notified when a single file has been analyzed. |
| 359 */ | 369 */ |
| 360 Stream get onFileAnalyzed => _onFileAnalyzedController.stream; | 370 Stream get onFileAnalyzed => _onFileAnalyzedController.stream; |
| 361 | 371 |
| 362 /** | 372 /** |
| 363 * The stream that is notified when priority sources change. | 373 * The stream that is notified when priority sources change. |
| 364 */ | 374 */ |
| 365 Stream<PriorityChangeEvent> get onPriorityChange => | 375 Stream<PriorityChangeEvent> get onPriorityChange => |
| (...skipping 851 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1217 optionUpdaters.forEach((OptionUpdater optionUpdater) { | 1227 optionUpdaters.forEach((OptionUpdater optionUpdater) { |
| 1218 optionUpdater(options); | 1228 optionUpdater(options); |
| 1219 }); | 1229 }); |
| 1220 context.analysisOptions = options; | 1230 context.analysisOptions = options; |
| 1221 // TODO(brianwilkerson) As far as I can tell, this doesn't cause analysis | 1231 // TODO(brianwilkerson) As far as I can tell, this doesn't cause analysis |
| 1222 // to be scheduled for this context. | 1232 // to be scheduled for this context. |
| 1223 }); | 1233 }); |
| 1224 // | 1234 // |
| 1225 // Update the defaults used to create new contexts. | 1235 // Update the defaults used to create new contexts. |
| 1226 // | 1236 // |
| 1227 AnalysisOptionsImpl options = | |
| 1228 (contextManager.callbacks as ServerContextManagerCallbacks).defaultOptio
ns; | |
| 1229 optionUpdaters.forEach((OptionUpdater optionUpdater) { | 1237 optionUpdaters.forEach((OptionUpdater optionUpdater) { |
| 1230 optionUpdater(options); | 1238 optionUpdater(defaultContextOptions); |
| 1231 }); | 1239 }); |
| 1232 } | 1240 } |
| 1233 | 1241 |
| 1234 /** | 1242 /** |
| 1235 * Return a set of contexts containing all of the resources in the given list | 1243 * Return a set of contexts containing all of the resources in the given list |
| 1236 * of [resources]. | 1244 * of [resources]. |
| 1237 */ | 1245 */ |
| 1238 Set<AnalysisContext> _getContexts(List<Resource> resources) { | 1246 Set<AnalysisContext> _getContexts(List<Resource> resources) { |
| 1239 Set<AnalysisContext> contexts = new HashSet<AnalysisContext>(); | 1247 Set<AnalysisContext> contexts = new HashSet<AnalysisContext>(); |
| 1240 resources.forEach((Resource resource) { | 1248 resources.forEach((Resource resource) { |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1333 class PriorityChangeEvent { | 1341 class PriorityChangeEvent { |
| 1334 final Source firstSource; | 1342 final Source firstSource; |
| 1335 | 1343 |
| 1336 PriorityChangeEvent(this.firstSource); | 1344 PriorityChangeEvent(this.firstSource); |
| 1337 } | 1345 } |
| 1338 | 1346 |
| 1339 class ServerContextManagerCallbacks extends ContextManagerCallbacks { | 1347 class ServerContextManagerCallbacks extends ContextManagerCallbacks { |
| 1340 final AnalysisServer analysisServer; | 1348 final AnalysisServer analysisServer; |
| 1341 | 1349 |
| 1342 /** | 1350 /** |
| 1343 * The default options used to create new analysis contexts. | |
| 1344 * | |
| 1345 * TODO(paulberry): move this into AnalysisServer so that a cast isn't needed | |
| 1346 * to access it. | |
| 1347 */ | |
| 1348 AnalysisOptionsImpl defaultOptions = new AnalysisOptionsImpl(); | |
| 1349 | |
| 1350 /** | |
| 1351 * The controller for sending [ContextsChangedEvent]s. | |
| 1352 */ | |
| 1353 StreamController<ContextsChangedEvent> _onContextsChangedController; | |
| 1354 | |
| 1355 /** | |
| 1356 * The [ResourceProvider] by which paths are converted into [Resource]s. | 1351 * The [ResourceProvider] by which paths are converted into [Resource]s. |
| 1357 */ | 1352 */ |
| 1358 final ResourceProvider resourceProvider; | 1353 final ResourceProvider resourceProvider; |
| 1359 | 1354 |
| 1360 ServerContextManagerCallbacks(this.analysisServer, this.resourceProvider) { | 1355 ServerContextManagerCallbacks(this.analysisServer, this.resourceProvider); |
| 1361 _onContextsChangedController = | |
| 1362 new StreamController<ContextsChangedEvent>.broadcast(); | |
| 1363 } | |
| 1364 | |
| 1365 /** | |
| 1366 * The stream that is notified when contexts are added or removed. | |
| 1367 * | |
| 1368 * TODO(paulberry): move this into AnalysisServer so that a cast isn't needed | |
| 1369 * to access it. | |
| 1370 */ | |
| 1371 Stream<ContextsChangedEvent> get onContextsChanged => | |
| 1372 _onContextsChangedController.stream; | |
| 1373 | 1356 |
| 1374 @override | 1357 @override |
| 1375 AnalysisContext addContext( | 1358 AnalysisContext addContext( |
| 1376 Folder folder, UriResolver packageUriResolver, Packages packages) { | 1359 Folder folder, UriResolver packageUriResolver, Packages packages) { |
| 1377 InternalAnalysisContext context = | 1360 InternalAnalysisContext context = |
| 1378 AnalysisEngine.instance.createAnalysisContext(); | 1361 AnalysisEngine.instance.createAnalysisContext(); |
| 1379 context.contentCache = analysisServer.overlayState; | 1362 context.contentCache = analysisServer.overlayState; |
| 1380 analysisServer.folderMap[folder] = context; | 1363 analysisServer.folderMap[folder] = context; |
| 1381 context.sourceFactory = _createSourceFactory(packageUriResolver, packages); | 1364 context.sourceFactory = _createSourceFactory(packageUriResolver, packages); |
| 1382 context.analysisOptions = new AnalysisOptionsImpl.from(defaultOptions); | 1365 context.analysisOptions = |
| 1383 _onContextsChangedController | 1366 new AnalysisOptionsImpl.from(analysisServer.defaultContextOptions); |
| 1367 analysisServer._onContextsChangedController |
| 1384 .add(new ContextsChangedEvent(added: [context])); | 1368 .add(new ContextsChangedEvent(added: [context])); |
| 1385 analysisServer.schedulePerformAnalysisOperation(context); | 1369 analysisServer.schedulePerformAnalysisOperation(context); |
| 1386 return context; | 1370 return context; |
| 1387 } | 1371 } |
| 1388 | 1372 |
| 1389 @override | 1373 @override |
| 1390 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet) { | 1374 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet) { |
| 1391 AnalysisContext context = analysisServer.folderMap[contextFolder]; | 1375 AnalysisContext context = analysisServer.folderMap[contextFolder]; |
| 1392 if (context != null) { | 1376 if (context != null) { |
| 1393 context.applyChanges(changeSet); | 1377 context.applyChanges(changeSet); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1412 | 1396 |
| 1413 @override | 1397 @override |
| 1414 void removeContext(Folder folder, List<String> flushedFiles) { | 1398 void removeContext(Folder folder, List<String> flushedFiles) { |
| 1415 AnalysisContext context = analysisServer.folderMap.remove(folder); | 1399 AnalysisContext context = analysisServer.folderMap.remove(folder); |
| 1416 sendAnalysisNotificationFlushResults(analysisServer, flushedFiles); | 1400 sendAnalysisNotificationFlushResults(analysisServer, flushedFiles); |
| 1417 | 1401 |
| 1418 if (analysisServer.index != null) { | 1402 if (analysisServer.index != null) { |
| 1419 analysisServer.index.removeContext(context); | 1403 analysisServer.index.removeContext(context); |
| 1420 } | 1404 } |
| 1421 analysisServer.operationQueue.contextRemoved(context); | 1405 analysisServer.operationQueue.contextRemoved(context); |
| 1422 _onContextsChangedController | 1406 analysisServer._onContextsChangedController |
| 1423 .add(new ContextsChangedEvent(removed: [context])); | 1407 .add(new ContextsChangedEvent(removed: [context])); |
| 1424 analysisServer.sendContextAnalysisDoneNotifications( | 1408 analysisServer.sendContextAnalysisDoneNotifications( |
| 1425 context, AnalysisDoneReason.CONTEXT_REMOVED); | 1409 context, AnalysisDoneReason.CONTEXT_REMOVED); |
| 1426 context.dispose(); | 1410 context.dispose(); |
| 1427 } | 1411 } |
| 1428 | 1412 |
| 1429 @override | 1413 @override |
| 1430 bool shouldFileBeAnalyzed(File file) { | 1414 bool shouldFileBeAnalyzed(File file) { |
| 1431 List<ShouldAnalyzeFile> functions = | 1415 List<ShouldAnalyzeFile> functions = |
| 1432 analysisServer.serverPlugin.analyzeFileFunctions; | 1416 analysisServer.serverPlugin.analyzeFileFunctions; |
| 1433 for (ShouldAnalyzeFile shouldAnalyzeFile in functions) { | 1417 for (ShouldAnalyzeFile shouldAnalyzeFile in functions) { |
| 1434 if (shouldAnalyzeFile(file)) { | 1418 if (shouldAnalyzeFile(file)) { |
| 1435 // Emacs creates dummy links to track the fact that a file is open for | 1419 // Emacs creates dummy links to track the fact that a file is open for |
| 1436 // editing and has unsaved changes (e.g. having unsaved changes to | 1420 // editing and has unsaved changes (e.g. having unsaved changes to |
| 1437 // 'foo.dart' causes a link '.#foo.dart' to be created, which points to | 1421 // 'foo.dart' causes a link '.#foo.dart' to be created, which points to |
| 1438 // the non-existent file 'username@hostname.pid'. To avoid these dummy | 1422 // the non-existent file 'username@hostname.pid'. To avoid these dummy |
| 1439 // links causing the analyzer to thrash, just ignore links to | 1423 // links causing the analyzer to thrash, just ignore links to |
| 1440 // non-existent files. | 1424 // non-existent files. |
| 1441 return file.exists; | 1425 return file.exists; |
| 1442 } | 1426 } |
| 1443 } | 1427 } |
| 1444 return false; | 1428 return false; |
| 1445 } | 1429 } |
| 1446 | 1430 |
| 1447 @override | 1431 @override |
| 1448 void updateContextPackageUriResolver( | 1432 void updateContextPackageUriResolver( |
| 1449 Folder contextFolder, UriResolver packageUriResolver, Packages packages) { | 1433 Folder contextFolder, UriResolver packageUriResolver, Packages packages) { |
| 1450 AnalysisContext context = analysisServer.folderMap[contextFolder]; | 1434 AnalysisContext context = analysisServer.folderMap[contextFolder]; |
| 1451 context.sourceFactory = _createSourceFactory(packageUriResolver, packages); | 1435 context.sourceFactory = _createSourceFactory(packageUriResolver, packages); |
| 1452 _onContextsChangedController | 1436 analysisServer._onContextsChangedController |
| 1453 .add(new ContextsChangedEvent(changed: [context])); | 1437 .add(new ContextsChangedEvent(changed: [context])); |
| 1454 analysisServer.schedulePerformAnalysisOperation(context); | 1438 analysisServer.schedulePerformAnalysisOperation(context); |
| 1455 } | 1439 } |
| 1456 | 1440 |
| 1457 void _computingPackageMap(bool computing) { | 1441 void _computingPackageMap(bool computing) { |
| 1458 if (analysisServer.serverServices.contains(ServerService.STATUS)) { | 1442 if (analysisServer.serverServices.contains(ServerService.STATUS)) { |
| 1459 PubStatus pubStatus = new PubStatus(computing); | 1443 PubStatus pubStatus = new PubStatus(computing); |
| 1460 ServerStatusParams params = new ServerStatusParams(pub: pubStatus); | 1444 ServerStatusParams params = new ServerStatusParams(pub: pubStatus); |
| 1461 analysisServer.sendNotification(params.toNotification()); | 1445 analysisServer.sendNotification(params.toNotification()); |
| 1462 } | 1446 } |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1580 /** | 1564 /** |
| 1581 * The [PerformanceTag] for time spent in server request handlers. | 1565 * The [PerformanceTag] for time spent in server request handlers. |
| 1582 */ | 1566 */ |
| 1583 static PerformanceTag serverRequests = new PerformanceTag('serverRequests'); | 1567 static PerformanceTag serverRequests = new PerformanceTag('serverRequests'); |
| 1584 | 1568 |
| 1585 /** | 1569 /** |
| 1586 * The [PerformanceTag] for time spent in split store microtasks. | 1570 * The [PerformanceTag] for time spent in split store microtasks. |
| 1587 */ | 1571 */ |
| 1588 static PerformanceTag splitStore = new PerformanceTag('splitStore'); | 1572 static PerformanceTag splitStore = new PerformanceTag('splitStore'); |
| 1589 } | 1573 } |
| OLD | NEW |