| 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 | 9 |
| 10 import 'package:analyzer/file_system/file_system.dart'; | 10 import 'package:analyzer/file_system/file_system.dart'; |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 173 final DartSdk defaultSdk; | 173 final DartSdk defaultSdk; |
| 174 | 174 |
| 175 /** | 175 /** |
| 176 * A table mapping [Folder]s to the [AnalysisContext]s associated with them. | 176 * A table mapping [Folder]s to the [AnalysisContext]s associated with them. |
| 177 */ | 177 */ |
| 178 final Map<Folder, AnalysisContext> folderMap = | 178 final Map<Folder, AnalysisContext> folderMap = |
| 179 new HashMap<Folder, AnalysisContext>(); | 179 new HashMap<Folder, AnalysisContext>(); |
| 180 | 180 |
| 181 /** | 181 /** |
| 182 * A queue of the operations to perform in this server. | 182 * A queue of the operations to perform in this server. |
| 183 * | |
| 184 * Invariant: when this queue is non-empty, there is exactly one pending call | |
| 185 * to [performOperation] on the event queue. When this list is empty, there a
re | |
| 186 * no calls to [performOperation] on the event queue. | |
| 187 */ | 183 */ |
| 188 ServerOperationQueue operationQueue; | 184 ServerOperationQueue operationQueue; |
| 189 | 185 |
| 190 /** | 186 /** |
| 187 * True if there is a pending future which will execute [performOperation]. |
| 188 */ |
| 189 bool performOperationPending = false; |
| 190 |
| 191 /** |
| 191 * A set of the [ServerService]s to send notifications for. | 192 * A set of the [ServerService]s to send notifications for. |
| 192 */ | 193 */ |
| 193 Set<ServerService> serverServices = new HashSet<ServerService>(); | 194 Set<ServerService> serverServices = new HashSet<ServerService>(); |
| 194 | 195 |
| 195 /** | 196 /** |
| 196 * A table mapping [AnalysisService]s to the file paths for which these | 197 * A table mapping [AnalysisService]s to the file paths for which these |
| 197 * notifications should be sent. | 198 * notifications should be sent. |
| 198 */ | 199 */ |
| 199 Map<AnalysisService, Set<String>> analysisServices = | 200 Map<AnalysisService, Set<String>> analysisServices = |
| 200 new HashMap<AnalysisService, Set<String>>(); | 201 new HashMap<AnalysisService, Set<String>>(); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 void fileAnalyzed(ChangeNotice notice) { | 262 void fileAnalyzed(ChangeNotice notice) { |
| 262 if (contextDirectoryManager.isInAnalysisRoot(notice.source.fullName)) { | 263 if (contextDirectoryManager.isInAnalysisRoot(notice.source.fullName)) { |
| 263 _onFileAnalyzedController.add(notice); | 264 _onFileAnalyzedController.add(notice); |
| 264 } | 265 } |
| 265 } | 266 } |
| 266 | 267 |
| 267 /** | 268 /** |
| 268 * Schedules execution of the given [ServerOperation]. | 269 * Schedules execution of the given [ServerOperation]. |
| 269 */ | 270 */ |
| 270 void scheduleOperation(ServerOperation operation) { | 271 void scheduleOperation(ServerOperation operation) { |
| 271 bool wasEmpty = operationQueue.isEmpty; | |
| 272 addOperation(operation); | 272 addOperation(operation); |
| 273 if (wasEmpty) { | 273 if (!performOperationPending) { |
| 274 _schedulePerformOperation(); | 274 _schedulePerformOperation(); |
| 275 } | 275 } |
| 276 } | 276 } |
| 277 | 277 |
| 278 /** | 278 /** |
| 279 * Schedules analysis of the given context. | 279 * Schedules analysis of the given context. |
| 280 */ | 280 */ |
| 281 void schedulePerformAnalysisOperation(AnalysisContext context) { | 281 void schedulePerformAnalysisOperation(AnalysisContext context) { |
| 282 _onAnalysisStartedController.add(context); | 282 _onAnalysisStartedController.add(context); |
| 283 scheduleOperation(new PerformAnalysisOperation(context, false)); | 283 scheduleOperation(new PerformAnalysisOperation(context, false)); |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 478 */ | 478 */ |
| 479 bool isPriorityContext(AnalysisContext context) { | 479 bool isPriorityContext(AnalysisContext context) { |
| 480 // TODO(scheglov) implement support for priority sources/contexts | 480 // TODO(scheglov) implement support for priority sources/contexts |
| 481 return false; | 481 return false; |
| 482 } | 482 } |
| 483 | 483 |
| 484 /** | 484 /** |
| 485 * Perform the next available [ServerOperation]. | 485 * Perform the next available [ServerOperation]. |
| 486 */ | 486 */ |
| 487 void performOperation() { | 487 void performOperation() { |
| 488 assert(performOperationPending); |
| 489 performOperationPending = false; |
| 488 if (!running) { | 490 if (!running) { |
| 489 // An error has occurred, or the connection to the client has been | 491 // An error has occurred, or the connection to the client has been |
| 490 // closed, since this method was scheduled on the event queue. So | 492 // closed, since this method was scheduled on the event queue. So |
| 491 // don't do anything. Instead clear the operation queue. | 493 // don't do anything. Instead clear the operation queue. |
| 492 operationQueue.clear(); | 494 operationQueue.clear(); |
| 493 return; | 495 return; |
| 494 } | 496 } |
| 495 // prepare next operation | 497 // prepare next operation |
| 496 ServerOperation operation = operationQueue.take(); | 498 ServerOperation operation = operationQueue.take(); |
| 499 if (operation == null) { |
| 500 // This can happen if the operation queue is cleared while the operation |
| 501 // loop is in progress. No problem; we just need to exit the operation |
| 502 // loop and wait for the next operation to be added. |
| 503 return; |
| 504 } |
| 497 sendStatusNotification(operation); | 505 sendStatusNotification(operation); |
| 498 // perform the operation | 506 // perform the operation |
| 499 try { | 507 try { |
| 500 operation.perform(this); | 508 operation.perform(this); |
| 501 } catch (exception, stackTrace) { | 509 } catch (exception, stackTrace) { |
| 502 AnalysisEngine.instance.logger.logError("${exception}\n${stackTrace}"); | 510 AnalysisEngine.instance.logger.logError("${exception}\n${stackTrace}"); |
| 503 if (rethrowExceptions) { | 511 if (rethrowExceptions) { |
| 504 throw new AnalysisException( | 512 throw new AnalysisException( |
| 505 'Unexpected exception during analysis', | 513 'Unexpected exception during analysis', |
| 506 new CaughtException(exception, stackTrace)); | 514 new CaughtException(exception, stackTrace)); |
| (...skipping 397 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 904 index.stop(); | 912 index.stop(); |
| 905 } | 913 } |
| 906 // Defer closing the channel so that the shutdown response can be sent. | 914 // Defer closing the channel so that the shutdown response can be sent. |
| 907 new Future(channel.close); | 915 new Future(channel.close); |
| 908 } | 916 } |
| 909 | 917 |
| 910 /** | 918 /** |
| 911 * Schedules [performOperation] exection. | 919 * Schedules [performOperation] exection. |
| 912 */ | 920 */ |
| 913 void _schedulePerformOperation() { | 921 void _schedulePerformOperation() { |
| 922 assert (!performOperationPending); |
| 914 new Future(performOperation); | 923 new Future(performOperation); |
| 924 performOperationPending = true; |
| 915 } | 925 } |
| 916 | 926 |
| 917 /** | 927 /** |
| 918 * Sends a fatal `server.error` notification. | 928 * Sends a fatal `server.error` notification. |
| 919 */ | 929 */ |
| 920 void _sendServerErrorNotification(exception, stackTrace) { | 930 void _sendServerErrorNotification(exception, stackTrace) { |
| 921 // prepare exception.toString() | 931 // prepare exception.toString() |
| 922 String exceptionString; | 932 String exceptionString; |
| 923 if (exception != null) { | 933 if (exception != null) { |
| 924 exceptionString = exception.toString(); | 934 exceptionString = exception.toString(); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 935 // send the notification | 945 // send the notification |
| 936 channel.sendNotification( | 946 channel.sendNotification( |
| 937 new ServerErrorParams( | 947 new ServerErrorParams( |
| 938 true, | 948 true, |
| 939 exceptionString, | 949 exceptionString, |
| 940 stackTraceString).toNotification()); | 950 stackTraceString).toNotification()); |
| 941 } | 951 } |
| 942 } | 952 } |
| 943 | 953 |
| 944 typedef void OptionUpdater(AnalysisOptionsImpl options); | 954 typedef void OptionUpdater(AnalysisOptionsImpl options); |
| OLD | NEW |