Chromium Code Reviews| 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:analysis_server/src/analysis_logger.dart'; | 10 import 'package:analysis_server/src/analysis_logger.dart'; |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 156 * The controller that is notified when analysis is complete. | 156 * The controller that is notified when analysis is complete. |
| 157 */ | 157 */ |
| 158 StreamController _onAnalysisCompleteController; | 158 StreamController _onAnalysisCompleteController; |
| 159 | 159 |
| 160 /** | 160 /** |
| 161 * The controller that is notified when a single file has been analyzed. | 161 * The controller that is notified when a single file has been analyzed. |
| 162 */ | 162 */ |
| 163 StreamController<ChangeNotice> _onFileAnalyzedController; | 163 StreamController<ChangeNotice> _onFileAnalyzedController; |
| 164 | 164 |
| 165 /** | 165 /** |
| 166 * The controller used to notify others when priority sources change. | |
| 167 */ | |
| 168 StreamController<PriorityChangeEvent> _onPriorityChangeController; | |
| 169 | |
| 170 /** | |
| 166 * True if any exceptions thrown by analysis should be propagated up the call | 171 * True if any exceptions thrown by analysis should be propagated up the call |
| 167 * stack. | 172 * stack. |
| 168 */ | 173 */ |
| 169 bool rethrowExceptions; | 174 bool rethrowExceptions; |
| 170 | 175 |
| 171 /** | 176 /** |
| 172 * The stream that is notified when contexts are added or removed. | 177 * The stream that is notified when contexts are added or removed. |
| 173 */ | 178 */ |
| 174 Stream<ContextsChangedEvent> onContextsChanged; | 179 Stream<ContextsChangedEvent> onContextsChanged; |
| 175 | 180 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 188 searchEngine = createSearchEngine(index); | 193 searchEngine = createSearchEngine(index); |
| 189 operationQueue = new ServerOperationQueue(this); | 194 operationQueue = new ServerOperationQueue(this); |
| 190 contextDirectoryManager = | 195 contextDirectoryManager = |
| 191 new ServerContextManager(this, resourceProvider, packageMapProvider); | 196 new ServerContextManager(this, resourceProvider, packageMapProvider); |
| 192 onContextsChanged = | 197 onContextsChanged = |
| 193 contextDirectoryManager.onContextsChanged.asBroadcastStream(); | 198 contextDirectoryManager.onContextsChanged.asBroadcastStream(); |
| 194 AnalysisEngine.instance.logger = new AnalysisLogger(); | 199 AnalysisEngine.instance.logger = new AnalysisLogger(); |
| 195 _onAnalysisStartedController = new StreamController.broadcast(); | 200 _onAnalysisStartedController = new StreamController.broadcast(); |
| 196 _onAnalysisCompleteController = new StreamController.broadcast(); | 201 _onAnalysisCompleteController = new StreamController.broadcast(); |
| 197 _onFileAnalyzedController = new StreamController.broadcast(); | 202 _onFileAnalyzedController = new StreamController.broadcast(); |
| 203 _onPriorityChangeController = | |
| 204 new StreamController<PriorityChangeEvent>.broadcast(); | |
| 198 running = true; | 205 running = true; |
| 199 Notification notification = new ServerConnectedParams().toNotification(); | 206 Notification notification = new ServerConnectedParams().toNotification(); |
| 200 channel.sendNotification(notification); | 207 channel.sendNotification(notification); |
| 201 channel.listen(handleRequest, onDone: done, onError: error); | 208 channel.listen(handleRequest, onDone: done, onError: error); |
| 202 } | 209 } |
| 203 | 210 |
| 204 /** | 211 /** |
| 205 * The stream that is notified when analysis is complete. | 212 * The stream that is notified when analysis is complete. |
| 206 */ | 213 */ |
| 207 Stream get onAnalysisComplete => _onAnalysisCompleteController.stream; | 214 Stream get onAnalysisComplete => _onAnalysisCompleteController.stream; |
| 208 | 215 |
| 209 /** | 216 /** |
| 210 * The stream that is notified when analysis of a context is started. | 217 * The stream that is notified when analysis of a context is started. |
| 211 */ | 218 */ |
| 212 Stream<AnalysisContext> get onAnalysisStarted { | 219 Stream<AnalysisContext> get onAnalysisStarted { |
| 213 return _onAnalysisStartedController.stream; | 220 return _onAnalysisStartedController.stream; |
| 214 } | 221 } |
| 215 | 222 |
| 216 /** | 223 /** |
| 217 * The stream that is notified when a single file has been analyzed. | 224 * The stream that is notified when a single file has been analyzed. |
| 218 */ | 225 */ |
| 219 Stream get onFileAnalyzed => _onFileAnalyzedController.stream; | 226 Stream get onFileAnalyzed => _onFileAnalyzedController.stream; |
| 220 | 227 |
| 221 /** | 228 /** |
| 229 * The stream that is notified when priority sources change. | |
| 230 */ | |
| 231 Stream<PriorityChangeEvent> get onPriorityChange => | |
| 232 _onPriorityChangeController.stream; | |
| 233 | |
| 234 /** | |
| 222 * Adds the given [ServerOperation] to the queue, but does not schedule | 235 * Adds the given [ServerOperation] to the queue, but does not schedule |
| 223 * operations execution. | 236 * operations execution. |
| 224 */ | 237 */ |
| 225 void addOperation(ServerOperation operation) { | 238 void addOperation(ServerOperation operation) { |
| 226 operationQueue.add(operation); | 239 operationQueue.add(operation); |
| 227 } | 240 } |
| 228 | 241 |
| 229 /** | 242 /** |
| 230 * The socket from which requests are being read has been closed. | 243 * The socket from which requests are being read has been closed. |
| 231 */ | 244 */ |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 339 } | 352 } |
| 340 // prepare Source | 353 // prepare Source |
| 341 Source source = getSource(file); | 354 Source source = getSource(file); |
| 342 if (context.getKindOf(source) == SourceKind.UNKNOWN) { | 355 if (context.getKindOf(source) == SourceKind.UNKNOWN) { |
| 343 return null; | 356 return null; |
| 344 } | 357 } |
| 345 // get errors for the file | 358 // get errors for the file |
| 346 return context.getErrors(source); | 359 return context.getErrors(source); |
| 347 } | 360 } |
| 348 | 361 |
| 349 /** | |
| 350 * Returns resolved [AstNode]s at the given [offset] of the given [file]. | |
| 351 * | |
| 352 * May be empty, but not `null`. | |
| 353 */ | |
| 354 List<AstNode> getNodesAtOffset(String file, int offset) { | |
| 355 List<CompilationUnit> units = getResolvedCompilationUnits(file); | |
| 356 List<AstNode> nodes = <AstNode>[]; | |
| 357 for (CompilationUnit unit in units) { | |
| 358 AstNode node = new NodeLocator.con1(offset).searchWithin(unit); | |
| 359 if (node != null) { | |
| 360 nodes.add(node); | |
| 361 } | |
| 362 } | |
| 363 return nodes; | |
| 364 } | |
| 365 | |
| 366 // TODO(brianwilkerson) Add the following method after 'prioritySources' has | 362 // TODO(brianwilkerson) Add the following method after 'prioritySources' has |
| 367 // been added to InternalAnalysisContext. | 363 // been added to InternalAnalysisContext. |
| 368 // /** | 364 // /** |
| 369 // * Return a list containing the full names of all of the sources that are | 365 // * Return a list containing the full names of all of the sources that are |
| 370 // * priority sources. | 366 // * priority sources. |
| 371 // */ | 367 // */ |
| 372 // List<String> getPriorityFiles() { | 368 // List<String> getPriorityFiles() { |
| 373 // List<String> priorityFiles = new List<String>(); | 369 // List<String> priorityFiles = new List<String>(); |
| 374 // folderMap.values.forEach((ContextDirectory directory) { | 370 // folderMap.values.forEach((ContextDirectory directory) { |
| 375 // InternalAnalysisContext context = directory.context; | 371 // InternalAnalysisContext context = directory.context; |
| 376 // context.prioritySources.forEach((Source source) { | 372 // context.prioritySources.forEach((Source source) { |
| 377 // priorityFiles.add(source.fullName); | 373 // priorityFiles.add(source.fullName); |
| 378 // }); | 374 // }); |
| 379 // }); | 375 // }); |
| 380 // return priorityFiles; | 376 // return priorityFiles; |
| 381 // } | 377 // } |
| 382 | 378 |
| 383 /** | 379 /** |
| 384 * Returns resolved [CompilationUnit]s of the Dart file with the given [path]. | 380 * Returns resolved [AstNode]s at the given [offset] of the given [file]. |
| 385 * | 381 * |
| 386 * May be empty, but not `null`. | 382 * May be empty, but not `null`. |
| 387 */ | 383 */ |
| 388 List<CompilationUnit> getResolvedCompilationUnits(String path) { | 384 List<AstNode> getNodesAtOffset(String file, int offset) { |
| 389 List<CompilationUnit> units = <CompilationUnit>[]; | 385 List<CompilationUnit> units = getResolvedCompilationUnits(file); |
| 390 // prepare AnalysisContext | 386 List<AstNode> nodes = <AstNode>[]; |
| 391 AnalysisContext context = getAnalysisContext(path); | 387 for (CompilationUnit unit in units) { |
| 392 if (context == null) { | 388 AstNode node = new NodeLocator.con1(offset).searchWithin(unit); |
| 393 return units; | 389 if (node != null) { |
| 394 } | 390 nodes.add(node); |
| 395 // add a unit for each unit/library combination | |
| 396 Source unitSource = getSource(path); | |
| 397 List<Source> librarySources = context.getLibrariesContaining(unitSource); | |
| 398 for (Source librarySource in librarySources) { | |
| 399 CompilationUnit unit = | |
| 400 context.resolveCompilationUnit2(unitSource, librarySource); | |
| 401 if (unit != null) { | |
| 402 units.add(unit); | |
| 403 } | 391 } |
| 404 } | 392 } |
| 405 // done | 393 return nodes; |
| 406 return units; | |
| 407 } | 394 } |
| 408 | 395 |
| 409 /** | 396 /** |
| 410 * Returns the [CompilationUnit] of the Dart file with the given [path] that | 397 * Returns the [CompilationUnit] of the Dart file with the given [path] that |
| 411 * should be used to resend notifications for already resolved unit. | 398 * should be used to resend notifications for already resolved unit. |
| 412 * Returns `null` if the file is not a part of any context, library has not | 399 * Returns `null` if the file is not a part of any context, library has not |
| 413 * been yet resolved, or any problem happened. | 400 * been yet resolved, or any problem happened. |
| 414 */ | 401 */ |
| 415 CompilationUnit getResolvedCompilationUnitToResendNotification(String path) { | 402 CompilationUnit getResolvedCompilationUnitToResendNotification(String path) { |
| 416 // prepare AnalysisContext | 403 // prepare AnalysisContext |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 427 // if library has not been resolved yet, the unit will be resolved later | 414 // if library has not been resolved yet, the unit will be resolved later |
| 428 Source librarySource = librarySources[0]; | 415 Source librarySource = librarySources[0]; |
| 429 if (context.getLibraryElement(librarySource) == null) { | 416 if (context.getLibraryElement(librarySource) == null) { |
| 430 return null; | 417 return null; |
| 431 } | 418 } |
| 432 // if library has been already resolved, resolve unit | 419 // if library has been already resolved, resolve unit |
| 433 return context.resolveCompilationUnit2(unitSource, librarySource); | 420 return context.resolveCompilationUnit2(unitSource, librarySource); |
| 434 } | 421 } |
| 435 | 422 |
| 436 /** | 423 /** |
| 424 * Returns resolved [CompilationUnit]s of the Dart file with the given [path]. | |
| 425 * | |
| 426 * May be empty, but not `null`. | |
| 427 */ | |
| 428 List<CompilationUnit> getResolvedCompilationUnits(String path) { | |
| 429 List<CompilationUnit> units = <CompilationUnit>[]; | |
| 430 // prepare AnalysisContext | |
| 431 AnalysisContext context = getAnalysisContext(path); | |
| 432 if (context == null) { | |
| 433 return units; | |
| 434 } | |
| 435 // add a unit for each unit/library combination | |
| 436 Source unitSource = getSource(path); | |
| 437 List<Source> librarySources = context.getLibrariesContaining(unitSource); | |
| 438 for (Source librarySource in librarySources) { | |
| 439 CompilationUnit unit = | |
| 440 context.resolveCompilationUnit2(unitSource, librarySource); | |
| 441 if (unit != null) { | |
| 442 units.add(unit); | |
| 443 } | |
| 444 } | |
| 445 // done | |
| 446 return units; | |
| 447 } | |
| 448 | |
| 449 /** | |
| 437 * Return the [Source] of the Dart file with the given [path]. | 450 * Return the [Source] of the Dart file with the given [path]. |
| 438 */ | 451 */ |
| 439 Source getSource(String path) { | 452 Source getSource(String path) { |
| 440 // try SDK | 453 // try SDK |
| 441 { | 454 { |
| 442 Uri uri = resourceProvider.pathContext.toUri(path); | 455 Uri uri = resourceProvider.pathContext.toUri(path); |
| 443 Source sdkSource = defaultSdk.fromFileUri(uri); | 456 Source sdkSource = defaultSdk.fromFileUri(uri); |
| 444 if (sdkSource != null) { | 457 if (sdkSource != null) { |
| 445 return sdkSource; | 458 return sdkSource; |
| 446 } | 459 } |
| (...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 734 } | 747 } |
| 735 } | 748 } |
| 736 }); | 749 }); |
| 737 // remember new subscriptions | 750 // remember new subscriptions |
| 738 this.analysisServices = subscriptions; | 751 this.analysisServices = subscriptions; |
| 739 } | 752 } |
| 740 | 753 |
| 741 /** | 754 /** |
| 742 * Set the priority files to the given [files]. | 755 * Set the priority files to the given [files]. |
| 743 */ | 756 */ |
| 744 void setPriorityFiles(Request request, List<String> files) { | 757 void setPriorityFiles(String requestId, List<String> files) { |
| 745 Map<AnalysisContext, List<Source>> sourceMap = | 758 Map<AnalysisContext, List<Source>> sourceMap = |
| 746 new HashMap<AnalysisContext, List<Source>>(); | 759 new HashMap<AnalysisContext, List<Source>>(); |
| 747 List<String> unanalyzed = new List<String>(); | 760 List<String> unanalyzed = new List<String>(); |
| 748 files.forEach((file) { | 761 files.forEach((file) { |
| 749 AnalysisContext analysisContext = getAnalysisContext(file); | 762 AnalysisContext analysisContext = getAnalysisContext(file); |
| 750 if (analysisContext == null) { | 763 if (analysisContext == null) { |
| 751 unanalyzed.add(file); | 764 unanalyzed.add(file); |
| 752 } else { | 765 } else { |
| 753 List<Source> sourceList = sourceMap[analysisContext]; | 766 List<Source> sourceList = sourceMap[analysisContext]; |
| 754 if (sourceList == null) { | 767 if (sourceList == null) { |
| 755 sourceList = <Source>[]; | 768 sourceList = <Source>[]; |
| 756 sourceMap[analysisContext] = sourceList; | 769 sourceMap[analysisContext] = sourceList; |
| 757 } | 770 } |
| 758 sourceList.add(getSource(file)); | 771 sourceList.add(getSource(file)); |
| 759 } | 772 } |
| 760 }); | 773 }); |
| 761 if (unanalyzed.isNotEmpty) { | 774 if (unanalyzed.isNotEmpty) { |
| 762 StringBuffer buffer = new StringBuffer(); | 775 StringBuffer buffer = new StringBuffer(); |
| 763 buffer.writeAll(unanalyzed, ', '); | 776 buffer.writeAll(unanalyzed, ', '); |
| 764 throw new RequestFailure( | 777 throw new RequestFailure( |
| 765 new Response.unanalyzedPriorityFiles(request, buffer.toString())); | 778 new Response.unanalyzedPriorityFiles(requestId, buffer.toString())); |
| 766 } | 779 } |
| 767 folderMap.forEach((Folder folder, AnalysisContext context) { | 780 folderMap.forEach((Folder folder, AnalysisContext context) { |
| 768 List<Source> sourceList = sourceMap[context]; | 781 List<Source> sourceList = sourceMap[context]; |
| 769 if (sourceList == null) { | 782 if (sourceList == null) { |
| 770 sourceList = Source.EMPTY_ARRAY; | 783 sourceList = Source.EMPTY_ARRAY; |
| 771 } | 784 } |
| 772 context.analysisPriorityOrder = sourceList; | 785 context.analysisPriorityOrder = sourceList; |
| 773 }); | 786 }); |
| 787 Source firstSource = files.length > 0 ? getSource(files[0]) : null; | |
| 788 _onPriorityChangeController.add(new PriorityChangeEvent(firstSource)); | |
| 774 } | 789 } |
| 775 | 790 |
| 776 /** | 791 /** |
| 777 * Returns `true` if errors should be reported for [file] with the given | 792 * Returns `true` if errors should be reported for [file] with the given |
| 778 * absolute path. | 793 * absolute path. |
| 779 */ | 794 */ |
| 780 bool shouldSendErrorsNotificationFor(String file) { | 795 bool shouldSendErrorsNotificationFor(String file) { |
| 781 // TODO(scheglov) add support for the "--no-error-notification" flag. | 796 // TODO(scheglov) add support for the "--no-error-notification" flag. |
| 782 return contextDirectoryManager.isInAnalysisRoot(file); | 797 return contextDirectoryManager.isInAnalysisRoot(file); |
| 783 } | 798 } |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 919 | 934 |
| 920 /** | 935 /** |
| 921 * The contexts that were removed from the server. | 936 * The contexts that were removed from the server. |
| 922 */ | 937 */ |
| 923 final List<AnalysisContext> removed; | 938 final List<AnalysisContext> removed; |
| 924 | 939 |
| 925 ContextsChangedEvent({this.added: AnalysisContext.EMPTY_LIST, this.changed: | 940 ContextsChangedEvent({this.added: AnalysisContext.EMPTY_LIST, this.changed: |
| 926 AnalysisContext.EMPTY_LIST, this.removed: AnalysisContext.EMPTY_LIST}); | 941 AnalysisContext.EMPTY_LIST, this.removed: AnalysisContext.EMPTY_LIST}); |
| 927 } | 942 } |
| 928 | 943 |
| 944 /** | |
| 945 * A [PriorityChangeEvent] indicates which sources are currently prioritized | |
|
Brian Wilkerson
2014/11/24 16:17:11
I think it indicates that the list of priority cha
danrubel
2014/11/24 17:54:06
Cleaned up.
| |
| 946 * and should be analyzed before other sources. | |
| 947 */ | |
| 948 class PriorityChangeEvent { | |
| 949 final Source firstSource; | |
|
Brian Wilkerson
2014/11/24 16:17:11
Shouldn't this be a List<Source>? Or possibly a Ma
danrubel
2014/11/24 17:54:05
I only need the first source if there is one and I
Brian Wilkerson
2014/11/24 18:14:38
Understood, and in general I agree with only doing
| |
| 950 | |
| 951 PriorityChangeEvent(this.firstSource); | |
| 952 } | |
| 953 | |
| 929 class ServerContextManager extends ContextManager { | 954 class ServerContextManager extends ContextManager { |
| 930 final AnalysisServer analysisServer; | 955 final AnalysisServer analysisServer; |
| 931 | 956 |
| 932 /** | 957 /** |
| 933 * The default options used to create new analysis contexts. | 958 * The default options used to create new analysis contexts. |
| 934 */ | 959 */ |
| 935 AnalysisOptionsImpl defaultOptions = new AnalysisOptionsImpl(); | 960 AnalysisOptionsImpl defaultOptions = new AnalysisOptionsImpl(); |
| 936 | 961 |
| 937 /** | 962 /** |
| 938 * The controller for sending [ContextsChangedEvent]s. | 963 * The controller for sending [ContextsChangedEvent]s. |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 999 * [packageUriResolver]. | 1024 * [packageUriResolver]. |
| 1000 */ | 1025 */ |
| 1001 SourceFactory _createSourceFactory(UriResolver packageUriResolver) { | 1026 SourceFactory _createSourceFactory(UriResolver packageUriResolver) { |
| 1002 List<UriResolver> resolvers = <UriResolver>[ | 1027 List<UriResolver> resolvers = <UriResolver>[ |
| 1003 new DartUriResolver(analysisServer.defaultSdk), | 1028 new DartUriResolver(analysisServer.defaultSdk), |
| 1004 new ResourceUriResolver(resourceProvider), | 1029 new ResourceUriResolver(resourceProvider), |
| 1005 packageUriResolver]; | 1030 packageUriResolver]; |
| 1006 return new SourceFactory(resolvers); | 1031 return new SourceFactory(resolvers); |
| 1007 } | 1032 } |
| 1008 } | 1033 } |
| OLD | NEW |