| 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 | 8 |
| 9 import 'package:analysis_server/src/analysis_logger.dart'; | 9 import 'package:analysis_server/src/analysis_logger.dart'; |
| 10 import 'package:analysis_server/src/channel.dart'; | 10 import 'package:analysis_server/src/channel.dart'; |
| 11 import 'package:analysis_server/src/constants.dart'; | 11 import 'package:analysis_server/src/constants.dart'; |
| 12 import 'package:analysis_server/src/context_directory_manager.dart'; | 12 import 'package:analysis_server/src/context_directory_manager.dart'; |
| 13 import 'package:analysis_server/src/domain_analysis.dart'; | 13 import 'package:analysis_server/src/domain_analysis.dart'; |
| 14 import 'package:analysis_server/src/operation/operation_analysis.dart'; |
| 14 import 'package:analysis_server/src/operation/operation.dart'; | 15 import 'package:analysis_server/src/operation/operation.dart'; |
| 15 import 'package:analysis_server/src/operation/operation_queue.dart'; | 16 import 'package:analysis_server/src/operation/operation_queue.dart'; |
| 16 import 'package:analysis_server/src/protocol.dart'; | 17 import 'package:analysis_server/src/protocol.dart'; |
| 17 import 'package:analysis_server/src/resource.dart'; | 18 import 'package:analysis_server/src/resource.dart'; |
| 18 import 'package:analyzer/src/generated/ast.dart'; | 19 import 'package:analyzer/src/generated/ast.dart'; |
| 19 import 'package:analyzer/src/generated/engine.dart'; | 20 import 'package:analyzer/src/generated/engine.dart'; |
| 20 import 'package:analyzer/src/generated/error.dart'; | 21 import 'package:analyzer/src/generated/error.dart'; |
| 21 import 'package:analyzer/src/generated/java_core.dart'; | |
| 22 import 'package:analyzer/src/generated/source.dart'; | 22 import 'package:analyzer/src/generated/source.dart'; |
| 23 import 'package:analyzer/src/generated/sdk.dart'; | 23 import 'package:analyzer/src/generated/sdk.dart'; |
| 24 import 'package:analyzer/src/generated/sdk_io.dart'; | 24 import 'package:analyzer/src/generated/sdk_io.dart'; |
| 25 import 'package:analyzer/src/generated/source_io.dart'; | 25 import 'package:analyzer/src/generated/source_io.dart'; |
| 26 import 'package:analysis_server/src/computers.dart'; | 26 import 'package:analysis_server/src/computers.dart'; |
| 27 | 27 |
| 28 | 28 |
| 29 /** | 29 /** |
| 30 * An instance of [DirectoryBasedDartSdk] that is shared between | 30 * An instance of [DirectoryBasedDartSdk] that is shared between |
| 31 * [AnalysisServer] instances to improve performance. | 31 * [AnalysisServer] instances to improve performance. |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 129 */ | 129 */ |
| 130 void schedulePerformAnalysisOperation(AnalysisContext context) { | 130 void schedulePerformAnalysisOperation(AnalysisContext context) { |
| 131 scheduleOperation(new PerformAnalysisOperation(context, false)); | 131 scheduleOperation(new PerformAnalysisOperation(context, false)); |
| 132 } | 132 } |
| 133 | 133 |
| 134 /** | 134 /** |
| 135 * Schedules execution of the given [ServerOperation]. | 135 * Schedules execution of the given [ServerOperation]. |
| 136 */ | 136 */ |
| 137 void scheduleOperation(ServerOperation operation) { | 137 void scheduleOperation(ServerOperation operation) { |
| 138 bool wasEmpty = operationQueue.isEmpty; | 138 bool wasEmpty = operationQueue.isEmpty; |
| 139 operationQueue.add(operation); | 139 addOperation(operation); |
| 140 if (wasEmpty) { | 140 if (wasEmpty) { |
| 141 _schedulePerformOperation(); | 141 _schedulePerformOperation(); |
| 142 } | 142 } |
| 143 } | 143 } |
| 144 | 144 |
| 145 /** | 145 /** |
| 146 * Adds the given [ServerOperation] to the queue, but does not schedule |
| 147 * operations execution. |
| 148 */ |
| 149 void addOperation(ServerOperation operation) { |
| 150 operationQueue.add(operation); |
| 151 } |
| 152 |
| 153 /** |
| 146 * The socket from which requests are being read has been closed. | 154 * The socket from which requests are being read has been closed. |
| 147 */ | 155 */ |
| 148 void done() { | 156 void done() { |
| 149 running = false; | 157 running = false; |
| 150 } | 158 } |
| 151 | 159 |
| 152 /** | 160 /** |
| 153 * There was an error related to the socket from which requests are being | 161 * There was an error related to the socket from which requests are being |
| 154 * read. | 162 * read. |
| 155 */ | 163 */ |
| (...skipping 15 matching lines...) Expand all Loading... |
| 171 } | 179 } |
| 172 } on RequestFailure catch (exception) { | 180 } on RequestFailure catch (exception) { |
| 173 channel.sendResponse(exception.response); | 181 channel.sendResponse(exception.response); |
| 174 return; | 182 return; |
| 175 } | 183 } |
| 176 } | 184 } |
| 177 channel.sendResponse(new Response.unknownRequest(request)); | 185 channel.sendResponse(new Response.unknownRequest(request)); |
| 178 } | 186 } |
| 179 | 187 |
| 180 /** | 188 /** |
| 189 * Returns `true` if there is a subscription for the given [server] and [file]
. |
| 190 */ |
| 191 bool hasAnalysisSubscription(AnalysisService service, String file) { |
| 192 Set<String> files = analysisServices[service]; |
| 193 return files != null && files.contains(file); |
| 194 } |
| 195 |
| 196 /** |
| 181 * Returns `true` if the given [AnalysisContext] is a priority one. | 197 * Returns `true` if the given [AnalysisContext] is a priority one. |
| 182 */ | 198 */ |
| 183 bool isPriorityContext(AnalysisContext context) { | 199 bool isPriorityContext(AnalysisContext context) { |
| 184 // TODO(scheglov) implement support for priority sources/contexts | 200 // TODO(scheglov) implement support for priority sources/contexts |
| 185 return false; | 201 return false; |
| 186 } | 202 } |
| 187 | 203 |
| 188 /** | 204 /** |
| 189 * Perform the next available [ServerOperation]. | 205 * Perform the next available [ServerOperation]. |
| 190 */ | 206 */ |
| (...skipping 15 matching lines...) Expand all Loading... |
| 206 } finally { | 222 } finally { |
| 207 if (!operationQueue.isEmpty) { | 223 if (!operationQueue.isEmpty) { |
| 208 _schedulePerformOperation(); | 224 _schedulePerformOperation(); |
| 209 } else { | 225 } else { |
| 210 sendStatusNotification(null); | 226 sendStatusNotification(null); |
| 211 } | 227 } |
| 212 } | 228 } |
| 213 } | 229 } |
| 214 | 230 |
| 215 /** | 231 /** |
| 216 * Perform analysis in the given [AnalysisContext]. | |
| 217 */ | |
| 218 void internalPerformAnalysis(AnalysisContext context) { | |
| 219 // | |
| 220 // TODO(brianwilkerson) Add an optional function-valued parameter to | |
| 221 // performAnalysisTask that will be called when the task has been computed | |
| 222 // but before it is performed and send notification in the function: | |
| 223 // | |
| 224 // AnalysisResult result = context.performAnalysisTask((taskDescription) { | |
| 225 // sendStatusNotification(context.toString(), taskDescription); | |
| 226 // }); | |
| 227 // prepare results | |
| 228 AnalysisResult result = context.performAnalysisTask(); | |
| 229 List<ChangeNotice> notices = result.changeNotices; | |
| 230 if (notices == null) { | |
| 231 return; | |
| 232 } | |
| 233 // TODO(scheglov) remember known sources | |
| 234 // TODO(scheglov) index units | |
| 235 // TODO(scheglov) schedule notifications | |
| 236 sendNotices(notices); | |
| 237 // continue analysis | |
| 238 operationQueue.add(new PerformAnalysisOperation(context, true)); | |
| 239 } | |
| 240 | |
| 241 /** | |
| 242 * Send the information in the given list of notices back to the client. | |
| 243 */ | |
| 244 void sendNotices(List<ChangeNotice> notices) { | |
| 245 for (int i = 0; i < notices.length; i++) { | |
| 246 ChangeNotice notice = notices[i]; | |
| 247 Source source = notice.source; | |
| 248 CompilationUnit dartUnit = notice.compilationUnit; | |
| 249 // TODO(scheglov) use default subscriptions | |
| 250 String file = source.fullName; | |
| 251 if (dartUnit != null) { | |
| 252 Set<String> files = analysisServices[AnalysisService.HIGHLIGHTS]; | |
| 253 if (files != null && files.contains(file)) { | |
| 254 sendAnalysisNotificationHighlights(file, dartUnit); | |
| 255 } | |
| 256 } | |
| 257 if (!source.isInSystemLibrary) { | |
| 258 // errors | |
| 259 sendAnalysisNotificationErrors(file, notice.errors); | |
| 260 } | |
| 261 } | |
| 262 } | |
| 263 | |
| 264 void sendAnalysisNotificationErrors(String file, List<AnalysisError> errors) { | |
| 265 Notification notification = new Notification(NOTIFICATION_ERRORS); | |
| 266 notification.setParameter(FILE, file); | |
| 267 notification.setParameter(ERRORS, errors.map(errorToJson).toList()); | |
| 268 sendNotification(notification); | |
| 269 } | |
| 270 | |
| 271 void sendAnalysisNotificationHighlights(String file, CompilationUnit dartUnit)
{ | |
| 272 Notification notification = new Notification(NOTIFICATION_HIGHLIGHTS); | |
| 273 notification.setParameter(FILE, file); | |
| 274 notification.setParameter( | |
| 275 REGIONS, | |
| 276 new DartUnitHighlightsComputer(dartUnit).compute()); | |
| 277 sendNotification(notification); | |
| 278 } | |
| 279 | |
| 280 /** | |
| 281 * Send status notification to the client. The `contextId` indicates | 232 * Send status notification to the client. The `contextId` indicates |
| 282 * the current context being analyzed or `null` if analysis is complete. | 233 * the current context being analyzed or `null` if analysis is complete. |
| 283 */ | 234 */ |
| 284 void sendStatusNotification(String contextId) { | 235 void sendStatusNotification(String contextId) { |
| 285 // if (contextId == lastStatusNotificationContextId) { | 236 // if (contextId == lastStatusNotificationContextId) { |
| 286 // return; | 237 // return; |
| 287 // } | 238 // } |
| 288 // lastStatusNotificationContextId = contextId; | 239 // lastStatusNotificationContextId = contextId; |
| 289 Notification notification = new Notification(NOTIFICATION_STATUS); | 240 Notification notification = new Notification(NOTIFICATION_STATUS); |
| 290 Map<String, Object> analysis = new Map(); | 241 Map<String, Object> analysis = new Map(); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 348 void setAnalysisSubscriptions(Map<AnalysisService, Set<String>> subscriptions)
{ | 299 void setAnalysisSubscriptions(Map<AnalysisService, Set<String>> subscriptions)
{ |
| 349 // send notifications for already analyzed sources | 300 // send notifications for already analyzed sources |
| 350 subscriptions.forEach((service, Set<String> newFiles) { | 301 subscriptions.forEach((service, Set<String> newFiles) { |
| 351 Set<String> oldFiles = analysisServices[service]; | 302 Set<String> oldFiles = analysisServices[service]; |
| 352 Set<String> todoFiles = oldFiles != null ? newFiles.difference(oldFiles) :
newFiles; | 303 Set<String> todoFiles = oldFiles != null ? newFiles.difference(oldFiles) :
newFiles; |
| 353 for (String file in todoFiles) { | 304 for (String file in todoFiles) { |
| 354 if (service == AnalysisService.ERRORS) { | 305 if (service == AnalysisService.ERRORS) { |
| 355 Source source = _getSource(file); | 306 Source source = _getSource(file); |
| 356 AnalysisContext analysisContext = _getAnalysisContext(file); | 307 AnalysisContext analysisContext = _getAnalysisContext(file); |
| 357 List<AnalysisError> errors = analysisContext.getErrors(source).errors; | 308 List<AnalysisError> errors = analysisContext.getErrors(source).errors; |
| 358 sendAnalysisNotificationErrors(file, errors); | 309 sendAnalysisNotificationErrors(this, file, errors); |
| 359 } | 310 } |
| 360 if (service == AnalysisService.HIGHLIGHTS) { | 311 if (service == AnalysisService.HIGHLIGHTS) { |
| 361 CompilationUnit dartUnit = test_getResolvedCompilationUnit(file); | 312 CompilationUnit dartUnit = test_getResolvedCompilationUnit(file); |
| 362 if (dartUnit != null) { | 313 if (dartUnit != null) { |
| 363 sendAnalysisNotificationHighlights(file, dartUnit); | 314 sendAnalysisNotificationHighlights(this, file, dartUnit); |
| 364 } | 315 } |
| 365 } | 316 } |
| 366 } | 317 } |
| 367 }); | 318 }); |
| 368 // remember new subscriptions | 319 // remember new subscriptions |
| 369 this.analysisServices = subscriptions; | 320 this.analysisServices = subscriptions; |
| 370 } | 321 } |
| 371 | 322 |
| 372 /** | 323 /** |
| 373 * Return the [AnalysisContext] that is used to analyze the given [path]. | 324 * Return the [AnalysisContext] that is used to analyze the given [path]. |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 410 return context.getResolvedCompilationUnit2(unitSource, librarySources[0]); | 361 return context.getResolvedCompilationUnit2(unitSource, librarySources[0]); |
| 411 } | 362 } |
| 412 | 363 |
| 413 /** | 364 /** |
| 414 * Return `true` if all operations have been performed in this [AnalysisServer
]. | 365 * Return `true` if all operations have been performed in this [AnalysisServer
]. |
| 415 */ | 366 */ |
| 416 bool test_areOperationsFinished() { | 367 bool test_areOperationsFinished() { |
| 417 return operationQueue.isEmpty; | 368 return operationQueue.isEmpty; |
| 418 } | 369 } |
| 419 | 370 |
| 420 static Map<String, Object> errorToJson(AnalysisError analysisError) { | |
| 421 // TODO(paulberry): move this function into the AnalysisError class. | |
| 422 ErrorCode errorCode = analysisError.errorCode; | |
| 423 Map<String, Object> result = { | |
| 424 'file': analysisError.source.fullName, | |
| 425 // TODO(scheglov) add Enum.fullName ? | |
| 426 'errorCode': '${errorCode.runtimeType}.${(errorCode as Enum).name}', | |
| 427 'offset': analysisError.offset, | |
| 428 'length': analysisError.length, | |
| 429 'message': analysisError.message | |
| 430 }; | |
| 431 if (analysisError.correction != null) { | |
| 432 result['correction'] = analysisError.correction; | |
| 433 } | |
| 434 return result; | |
| 435 } | |
| 436 | |
| 437 /** | 371 /** |
| 438 * Send the given [notification] to the client. | 372 * Send the given [notification] to the client. |
| 439 */ | 373 */ |
| 440 void sendNotification(Notification notification) { | 374 void sendNotification(Notification notification) { |
| 441 channel.sendNotification(notification); | 375 channel.sendNotification(notification); |
| 442 } | 376 } |
| 443 | 377 |
| 444 /** | 378 /** |
| 445 * Schedules [performOperation] exection. | 379 * Schedules [performOperation] exection. |
| 446 */ | 380 */ |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 515 /** | 449 /** |
| 516 * An enumeration of the services provided by the server domain. | 450 * An enumeration of the services provided by the server domain. |
| 517 */ | 451 */ |
| 518 class ServerService extends Enum2<ServerService> { | 452 class ServerService extends Enum2<ServerService> { |
| 519 static const ServerService STATUS = const ServerService('STATUS', 0); | 453 static const ServerService STATUS = const ServerService('STATUS', 0); |
| 520 | 454 |
| 521 static const List<ServerService> VALUES = const [STATUS]; | 455 static const List<ServerService> VALUES = const [STATUS]; |
| 522 | 456 |
| 523 const ServerService(String name, int ordinal) : super(name, ordinal); | 457 const ServerService(String name, int ordinal) : super(name, ordinal); |
| 524 } | 458 } |
| OLD | NEW |