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 import 'dart:async'; | 5 import 'dart:async'; |
6 import 'dart:collection'; | 6 import 'dart:collection'; |
7 import 'dart:core'; | 7 import 'dart:core'; |
8 import 'dart:io' as io; | 8 import 'dart:io' as io; |
9 import 'dart:math' show max; | 9 import 'dart:math' show max; |
10 | 10 |
(...skipping 17 matching lines...) Expand all Loading... |
28 import 'package:analysis_server/src/operation/operation_queue.dart'; | 28 import 'package:analysis_server/src/operation/operation_queue.dart'; |
29 import 'package:analysis_server/src/plugin/notification_manager.dart'; | 29 import 'package:analysis_server/src/plugin/notification_manager.dart'; |
30 import 'package:analysis_server/src/plugin/plugin_manager.dart'; | 30 import 'package:analysis_server/src/plugin/plugin_manager.dart'; |
31 import 'package:analysis_server/src/plugin/plugin_watcher.dart'; | 31 import 'package:analysis_server/src/plugin/plugin_watcher.dart'; |
32 import 'package:analysis_server/src/plugin/server_plugin.dart'; | 32 import 'package:analysis_server/src/plugin/server_plugin.dart'; |
33 import 'package:analysis_server/src/protocol_server.dart' as server; | 33 import 'package:analysis_server/src/protocol_server.dart' as server; |
34 import 'package:analysis_server/src/server/diagnostic_server.dart'; | 34 import 'package:analysis_server/src/server/diagnostic_server.dart'; |
35 import 'package:analysis_server/src/services/correction/namespace.dart'; | 35 import 'package:analysis_server/src/services/correction/namespace.dart'; |
36 import 'package:analysis_server/src/services/index/index.dart'; | 36 import 'package:analysis_server/src/services/index/index.dart'; |
37 import 'package:analysis_server/src/services/search/search_engine.dart'; | 37 import 'package:analysis_server/src/services/search/search_engine.dart'; |
38 import 'package:analysis_server/src/services/search/search_engine_internal.dart'
; | |
39 import 'package:analysis_server/src/services/search/search_engine_internal2.dart
'; | 38 import 'package:analysis_server/src/services/search/search_engine_internal2.dart
'; |
40 import 'package:analysis_server/src/single_context_manager.dart'; | 39 import 'package:analysis_server/src/single_context_manager.dart'; |
41 import 'package:analysis_server/src/utilities/null_string_sink.dart'; | 40 import 'package:analysis_server/src/utilities/null_string_sink.dart'; |
42 import 'package:analyzer/context/context_root.dart'; | 41 import 'package:analyzer/context/context_root.dart'; |
43 import 'package:analyzer/dart/ast/ast.dart'; | 42 import 'package:analyzer/dart/ast/ast.dart'; |
44 import 'package:analyzer/dart/ast/standard_resolution_map.dart'; | |
45 import 'package:analyzer/dart/element/element.dart'; | 43 import 'package:analyzer/dart/element/element.dart'; |
46 import 'package:analyzer/exception/exception.dart'; | 44 import 'package:analyzer/exception/exception.dart'; |
47 import 'package:analyzer/file_system/file_system.dart'; | 45 import 'package:analyzer/file_system/file_system.dart'; |
48 import 'package:analyzer/file_system/physical_file_system.dart'; | 46 import 'package:analyzer/file_system/physical_file_system.dart'; |
49 import 'package:analyzer/instrumentation/instrumentation.dart'; | 47 import 'package:analyzer/instrumentation/instrumentation.dart'; |
50 import 'package:analyzer/plugin/resolver_provider.dart'; | 48 import 'package:analyzer/plugin/resolver_provider.dart'; |
51 import 'package:analyzer/source/pub_package_map_provider.dart'; | 49 import 'package:analyzer/source/pub_package_map_provider.dart'; |
52 import 'package:analyzer/src/context/builder.dart'; | 50 import 'package:analyzer/src/context/builder.dart'; |
53 import 'package:analyzer/src/dart/analysis/ast_provider_context.dart'; | |
54 import 'package:analyzer/src/dart/analysis/ast_provider_driver.dart'; | 51 import 'package:analyzer/src/dart/analysis/ast_provider_driver.dart'; |
55 import 'package:analyzer/src/dart/analysis/driver.dart' as nd; | 52 import 'package:analyzer/src/dart/analysis/driver.dart' as nd; |
56 import 'package:analyzer/src/dart/analysis/file_state.dart' as nd; | 53 import 'package:analyzer/src/dart/analysis/file_state.dart' as nd; |
57 import 'package:analyzer/src/dart/analysis/status.dart' as nd; | 54 import 'package:analyzer/src/dart/analysis/status.dart' as nd; |
58 import 'package:analyzer/src/dart/ast/utilities.dart'; | 55 import 'package:analyzer/src/dart/ast/utilities.dart'; |
59 import 'package:analyzer/src/dart/element/ast_provider.dart'; | 56 import 'package:analyzer/src/dart/element/ast_provider.dart'; |
60 import 'package:analyzer/src/generated/engine.dart'; | 57 import 'package:analyzer/src/generated/engine.dart'; |
61 import 'package:analyzer/src/generated/sdk.dart'; | 58 import 'package:analyzer/src/generated/sdk.dart'; |
62 import 'package:analyzer/src/generated/source.dart'; | 59 import 'package:analyzer/src/generated/source.dart'; |
63 import 'package:analyzer/src/generated/source_io.dart'; | 60 import 'package:analyzer/src/generated/source_io.dart'; |
64 import 'package:analyzer/src/generated/utilities_general.dart'; | 61 import 'package:analyzer/src/generated/utilities_general.dart'; |
65 import 'package:analyzer/src/task/dart.dart'; | |
66 import 'package:analyzer/src/util/glob.dart'; | 62 import 'package:analyzer/src/util/glob.dart'; |
67 import 'package:analyzer/task/dart.dart'; | |
68 import 'package:analyzer_plugin/protocol/protocol_common.dart' hide Element; | 63 import 'package:analyzer_plugin/protocol/protocol_common.dart' hide Element; |
69 import 'package:front_end/src/base/performace_logger.dart'; | 64 import 'package:front_end/src/base/performace_logger.dart'; |
70 import 'package:front_end/src/incremental/byte_store.dart'; | 65 import 'package:front_end/src/incremental/byte_store.dart'; |
71 import 'package:front_end/src/incremental/file_byte_store.dart'; | 66 import 'package:front_end/src/incremental/file_byte_store.dart'; |
72 import 'package:plugin/plugin.dart'; | 67 import 'package:plugin/plugin.dart'; |
73 import 'package:watcher/watcher.dart'; | 68 import 'package:watcher/watcher.dart'; |
74 | 69 |
75 typedef void OptionUpdater(AnalysisOptionsImpl options); | 70 typedef void OptionUpdater(AnalysisOptionsImpl options); |
76 | 71 |
77 /** | 72 /** |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 * The controller that is notified when analysis is started. | 269 * The controller that is notified when analysis is started. |
275 */ | 270 */ |
276 StreamController<bool> _onAnalysisStartedController; | 271 StreamController<bool> _onAnalysisStartedController; |
277 | 272 |
278 /** | 273 /** |
279 * The controller that is notified when a single file has been analyzed. | 274 * The controller that is notified when a single file has been analyzed. |
280 */ | 275 */ |
281 StreamController<ChangeNotice> _onFileAnalyzedController; | 276 StreamController<ChangeNotice> _onFileAnalyzedController; |
282 | 277 |
283 /** | 278 /** |
284 * The controller used to notify others when priority sources change. | |
285 */ | |
286 StreamController<PriorityChangeEvent> _onPriorityChangeController; | |
287 | |
288 /** | |
289 * True if any exceptions thrown by analysis should be propagated up the call | 279 * True if any exceptions thrown by analysis should be propagated up the call |
290 * stack. | 280 * stack. |
291 */ | 281 */ |
292 bool rethrowExceptions; | 282 bool rethrowExceptions; |
293 | 283 |
294 /** | 284 /** |
295 * The next time (milliseconds since epoch) after which the analysis server | 285 * The next time (milliseconds since epoch) after which the analysis server |
296 * should pause so that pending requests can be fetched by the system. | 286 * should pause so that pending requests can be fetched by the system. |
297 */ | 287 */ |
298 // Add 1 sec to prevent delay from impacting short running tests | 288 // Add 1 sec to prevent delay from impacting short running tests |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
462 contextManager = new SingleContextManager(resourceProvider, sdkManager, | 452 contextManager = new SingleContextManager(resourceProvider, sdkManager, |
463 packageResolverProvider, analyzedFilesGlobs, defaultContextOptions); | 453 packageResolverProvider, analyzedFilesGlobs, defaultContextOptions); |
464 } else { | 454 } else { |
465 contextManager = new ContextManagerImpl( | 455 contextManager = new ContextManagerImpl( |
466 resourceProvider, | 456 resourceProvider, |
467 sdkManager, | 457 sdkManager, |
468 packageResolverProvider, | 458 packageResolverProvider, |
469 packageMapProvider, | 459 packageMapProvider, |
470 analyzedFilesGlobs, | 460 analyzedFilesGlobs, |
471 instrumentationService, | 461 instrumentationService, |
472 defaultContextOptions, | 462 defaultContextOptions); |
473 options.enableNewAnalysisDriver); | |
474 } | 463 } |
475 this.fileResolverProvider = fileResolverProvider; | 464 this.fileResolverProvider = fileResolverProvider; |
476 this.packageResolverProvider = packageResolverProvider; | 465 this.packageResolverProvider = packageResolverProvider; |
477 ServerContextManagerCallbacks contextManagerCallbacks = | 466 ServerContextManagerCallbacks contextManagerCallbacks = |
478 new ServerContextManagerCallbacks(this, resourceProvider); | 467 new ServerContextManagerCallbacks(this, resourceProvider); |
479 contextManager.callbacks = contextManagerCallbacks; | 468 contextManager.callbacks = contextManagerCallbacks; |
480 AnalysisEngine.instance.logger = new AnalysisLogger(this); | 469 AnalysisEngine.instance.logger = new AnalysisLogger(this); |
481 _onAnalysisStartedController = new StreamController.broadcast(); | 470 _onAnalysisStartedController = new StreamController.broadcast(); |
482 _onFileAnalyzedController = new StreamController.broadcast(); | 471 _onFileAnalyzedController = new StreamController.broadcast(); |
483 // temporary plugin support: | 472 // temporary plugin support: |
484 _onFileAddedController = new StreamController.broadcast(); | 473 _onFileAddedController = new StreamController.broadcast(); |
485 // temporary plugin support: | 474 // temporary plugin support: |
486 _onFileChangedController = new StreamController.broadcast(); | 475 _onFileChangedController = new StreamController.broadcast(); |
487 _onPriorityChangeController = | |
488 new StreamController<PriorityChangeEvent>.broadcast(); | |
489 running = true; | 476 running = true; |
490 onAnalysisStarted.first.then((_) { | 477 onAnalysisStarted.first.then((_) { |
491 onAnalysisComplete.then((_) { | 478 onAnalysisComplete.then((_) { |
492 performanceAfterStartup = new ServerPerformance(); | 479 performanceAfterStartup = new ServerPerformance(); |
493 _performance = performanceAfterStartup; | 480 _performance = performanceAfterStartup; |
494 }); | 481 }); |
495 }); | 482 }); |
496 _setupIndexInvalidation(); | 483 _setupIndexInvalidation(); |
497 if (options.enableNewAnalysisDriver) { | 484 searchEngine = new SearchEngineImpl2(driverMap.values); |
498 searchEngine = new SearchEngineImpl2(driverMap.values); | |
499 } else if (index != null) { | |
500 searchEngine = new SearchEngineImpl(index, getAstProvider); | |
501 } | |
502 Notification notification = new ServerConnectedParams(VERSION, io.pid, | 485 Notification notification = new ServerConnectedParams(VERSION, io.pid, |
503 sessionId: instrumentationService.sessionId) | 486 sessionId: instrumentationService.sessionId) |
504 .toNotification(); | 487 .toNotification(); |
505 channel.sendNotification(notification); | 488 channel.sendNotification(notification); |
506 channel.listen(handleRequest, onDone: done, onError: error); | 489 channel.listen(handleRequest, onDone: done, onError: error); |
507 handlers = serverPlugin.createDomains(this); | 490 handlers = serverPlugin.createDomains(this); |
508 } | 491 } |
509 | 492 |
510 /** | 493 /** |
511 * Return the [AnalysisContext]s that are being used to analyze the analysis | 494 * Return the [AnalysisContext]s that are being used to analyze the analysis |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
585 Stream get onFileAnalyzed => _onFileAnalyzedController.stream; | 568 Stream get onFileAnalyzed => _onFileAnalyzedController.stream; |
586 | 569 |
587 /** | 570 /** |
588 * The stream that is notified when a single file has been changed. This | 571 * The stream that is notified when a single file has been changed. This |
589 * exists as a temporary stopgap for plugins, until the official plugin API is | 572 * exists as a temporary stopgap for plugins, until the official plugin API is |
590 * complete. | 573 * complete. |
591 */ | 574 */ |
592 Stream get onFileChanged => _onFileChangedController.stream; | 575 Stream get onFileChanged => _onFileChangedController.stream; |
593 | 576 |
594 /** | 577 /** |
595 * The stream that is notified when priority sources change. | |
596 */ | |
597 Stream<PriorityChangeEvent> get onPriorityChange => | |
598 _onPriorityChangeController.stream; | |
599 | |
600 /** | |
601 * The [Future] that completes when the next operation is performed. | 578 * The [Future] that completes when the next operation is performed. |
602 */ | 579 */ |
603 Future get test_onOperationPerformed { | 580 Future get test_onOperationPerformed { |
604 if (_test_onOperationPerformedCompleter == null) { | 581 if (_test_onOperationPerformedCompleter == null) { |
605 _test_onOperationPerformedCompleter = new Completer(); | 582 _test_onOperationPerformedCompleter = new Completer(); |
606 } | 583 } |
607 return _test_onOperationPerformedCompleter.future; | 584 return _test_onOperationPerformedCompleter.future; |
608 } | 585 } |
609 | 586 |
610 /** | 587 /** |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
658 DartSdk findSdk() { | 635 DartSdk findSdk() { |
659 DartSdk sdk = sdkManager.anySdk; | 636 DartSdk sdk = sdkManager.anySdk; |
660 if (sdk != null) { | 637 if (sdk != null) { |
661 return sdk; | 638 return sdk; |
662 } | 639 } |
663 // TODO(brianwilkerson) Should we create an SDK using the default options? | 640 // TODO(brianwilkerson) Should we create an SDK using the default options? |
664 return null; | 641 return null; |
665 } | 642 } |
666 | 643 |
667 /** | 644 /** |
668 * Return the preferred [AnalysisContext] for analyzing the given [path]. | |
669 * This will be the context that explicitly contains the path, if any such | |
670 * context exists, otherwise it will be the first analysis context that | |
671 * implicitly analyzes it. Return `null` if no context is analyzing the | |
672 * path. | |
673 */ | |
674 AnalysisContext getAnalysisContext(String path) { | |
675 return getContextSourcePair(path).context; | |
676 } | |
677 | |
678 /** | |
679 * Return any [AnalysisContext] that is analyzing the given [source], either | |
680 * explicitly or implicitly. Return `null` if there is no such context. | |
681 */ | |
682 AnalysisContext getAnalysisContextForSource(Source source) { | |
683 for (AnalysisContext context in analysisContexts) { | |
684 SourceKind kind = context.getKindOf(source); | |
685 if (kind != SourceKind.UNKNOWN) { | |
686 return context; | |
687 } | |
688 } | |
689 return null; | |
690 } | |
691 | |
692 /** | |
693 * Return an analysis driver to which the file with the given [path] is | 645 * Return an analysis driver to which the file with the given [path] is |
694 * added if one exists, otherwise a driver in which the file was analyzed if | 646 * added if one exists, otherwise a driver in which the file was analyzed if |
695 * one exists, otherwise the first driver, otherwise `null`. | 647 * one exists, otherwise the first driver, otherwise `null`. |
696 */ | 648 */ |
697 nd.AnalysisDriver getAnalysisDriver(String path) { | 649 nd.AnalysisDriver getAnalysisDriver(String path) { |
698 List<nd.AnalysisDriver> drivers = driverMap.values.toList(); | 650 List<nd.AnalysisDriver> drivers = driverMap.values.toList(); |
699 if (drivers.isNotEmpty) { | 651 if (drivers.isNotEmpty) { |
700 // Sort the drivers so that more deeply nested contexts will be checked | 652 // Sort the drivers so that more deeply nested contexts will be checked |
701 // before enclosing contexts. | 653 // before enclosing contexts. |
702 drivers.sort((first, second) => | 654 drivers.sort((first, second) => |
(...skipping 27 matching lines...) Expand all Loading... |
730 // Ignore the exception. | 682 // Ignore the exception. |
731 // We don't want to log the same exception again and again. | 683 // We don't want to log the same exception again and again. |
732 return null; | 684 return null; |
733 } | 685 } |
734 } | 686 } |
735 | 687 |
736 /** | 688 /** |
737 * Return the [AstProvider] for the given [path]. | 689 * Return the [AstProvider] for the given [path]. |
738 */ | 690 */ |
739 AstProvider getAstProvider(String path) { | 691 AstProvider getAstProvider(String path) { |
740 if (options.enableNewAnalysisDriver) { | 692 nd.AnalysisDriver analysisDriver = getAnalysisDriver(path); |
741 var analysisDriver = getAnalysisDriver(path); | 693 return new AstProviderForDriver(analysisDriver); |
742 return new AstProviderForDriver(analysisDriver); | |
743 } else { | |
744 var analysisContext = getAnalysisContext(path); | |
745 return new AstProviderForContext(analysisContext); | |
746 } | |
747 } | |
748 | |
749 CompilationUnitElement getCompilationUnitElement(String file) { | |
750 ContextSourcePair pair = getContextSourcePair(file); | |
751 if (pair == null) { | |
752 return null; | |
753 } | |
754 // prepare AnalysisContext and Source | |
755 AnalysisContext context = pair.context; | |
756 Source unitSource = pair.source; | |
757 if (context == null || unitSource == null) { | |
758 return null; | |
759 } | |
760 // get element in the first library | |
761 List<Source> librarySources = context.getLibrariesContaining(unitSource); | |
762 if (!librarySources.isNotEmpty) { | |
763 return null; | |
764 } | |
765 Source librarySource = librarySources.first; | |
766 return context.getCompilationUnitElement(unitSource, librarySource); | |
767 } | 694 } |
768 | 695 |
769 /** | 696 /** |
770 * Return the [AnalysisContext] for the "innermost" context whose associated | 697 * Return the [AnalysisContext] for the "innermost" context whose associated |
771 * folder is or contains the given path. ("innermost" refers to the nesting | 698 * folder is or contains the given path. ("innermost" refers to the nesting |
772 * of contexts, so if there is a context for path /foo and a context for | 699 * of contexts, so if there is a context for path /foo and a context for |
773 * path /foo/bar, then the innermost context containing /foo/bar/baz.dart is | 700 * path /foo/bar, then the innermost context containing /foo/bar/baz.dart is |
774 * the context for /foo/bar.) | 701 * the context for /foo/bar.) |
775 * | 702 * |
776 * If no context contains the given path, `null` is returned. | 703 * If no context contains the given path, `null` is returned. |
777 */ | 704 */ |
778 AnalysisContext getContainingContext(String path) { | 705 AnalysisContext getContainingContext(String path) { |
779 return contextManager.getContextFor(path); | 706 return contextManager.getContextFor(path); |
780 } | 707 } |
781 | 708 |
782 /** | 709 /** |
783 * Return the [nd.AnalysisDriver] for the "innermost" context whose associated | 710 * Return the [nd.AnalysisDriver] for the "innermost" context whose associated |
784 * folder is or contains the given path. ("innermost" refers to the nesting | 711 * folder is or contains the given path. ("innermost" refers to the nesting |
785 * of contexts, so if there is a context for path /foo and a context for | 712 * of contexts, so if there is a context for path /foo and a context for |
786 * path /foo/bar, then the innermost context containing /foo/bar/baz.dart is | 713 * path /foo/bar, then the innermost context containing /foo/bar/baz.dart is |
787 * the context for /foo/bar.) | 714 * the context for /foo/bar.) |
788 * | 715 * |
789 * If no context contains the given path, `null` is returned. | 716 * If no context contains the given path, `null` is returned. |
790 */ | 717 */ |
791 nd.AnalysisDriver getContainingDriver(String path) { | 718 nd.AnalysisDriver getContainingDriver(String path) { |
792 return contextManager.getDriverFor(path); | 719 return contextManager.getDriverFor(path); |
793 } | 720 } |
794 | 721 |
795 /** | 722 /** |
796 * Return the primary [ContextSourcePair] representing the given [path]. | |
797 * | |
798 * The [AnalysisContext] of this pair will be the context that explicitly | |
799 * contains the path, if any such context exists, otherwise it will be the | |
800 * first context that implicitly analyzes it. | |
801 * | |
802 * If the [path] is not analyzed by any context, a [ContextSourcePair] with | |
803 * a `null` context and a `file` [Source] is returned. | |
804 * | |
805 * If the [path] doesn't represent a file, a [ContextSourcePair] with a `null` | |
806 * context and `null` [Source] is returned. | |
807 * | |
808 * Does not return `null`. | |
809 */ | |
810 ContextSourcePair getContextSourcePair(String path) { | |
811 // try SDK | |
812 { | |
813 DartSdk sdk = findSdk(); | |
814 if (sdk != null) { | |
815 Uri uri = resourceProvider.pathContext.toUri(path); | |
816 Source sdkSource = sdk.fromFileUri(uri); | |
817 if (sdkSource != null) { | |
818 return new ContextSourcePair(sdk.context, sdkSource); | |
819 } | |
820 } | |
821 } | |
822 // try to find the deep-most containing context | |
823 Resource resource = resourceProvider.getResource(path); | |
824 if (resource is! File) { | |
825 return new ContextSourcePair(null, null); | |
826 } | |
827 File file = resource; | |
828 { | |
829 AnalysisContext containingContext = getContainingContext(path); | |
830 if (containingContext != null) { | |
831 Source source = | |
832 ContextManagerImpl.createSourceInContext(containingContext, file); | |
833 return new ContextSourcePair(containingContext, source); | |
834 } | |
835 } | |
836 // try to find a context that analysed the file | |
837 for (AnalysisContext context in analysisContexts) { | |
838 Source source = ContextManagerImpl.createSourceInContext(context, file); | |
839 SourceKind kind = context.getKindOf(source); | |
840 if (kind != SourceKind.UNKNOWN) { | |
841 return new ContextSourcePair(context, source); | |
842 } | |
843 } | |
844 // try to find a context for which the file is a priority source | |
845 for (InternalAnalysisContext context in analysisContexts) { | |
846 List<Source> sources = context.getSourcesWithFullName(path); | |
847 if (sources.isNotEmpty) { | |
848 Source source = sources.first; | |
849 return new ContextSourcePair(context, source); | |
850 } | |
851 } | |
852 // file-based source | |
853 Source fileSource = file.createSource(); | |
854 return new ContextSourcePair(null, fileSource); | |
855 } | |
856 | |
857 /** | |
858 * Return a [Future] that completes with the [Element] at the given | 723 * Return a [Future] that completes with the [Element] at the given |
859 * [offset] of the given [file], or with `null` if there is no node at the | 724 * [offset] of the given [file], or with `null` if there is no node at the |
860 * [offset] or the node does not have an element. | 725 * [offset] or the node does not have an element. |
861 */ | 726 */ |
862 Future<Element> getElementAtOffset(String file, int offset) async { | 727 Future<Element> getElementAtOffset(String file, int offset) async { |
863 AstNode node = await getNodeAtOffset(file, offset); | 728 AstNode node = await getNodeAtOffset(file, offset); |
864 return getElementOfNode(node); | 729 return getElementOfNode(node); |
865 } | 730 } |
866 | 731 |
867 /** | 732 /** |
(...skipping 14 matching lines...) Expand all Loading... |
882 return null; | 747 return null; |
883 } | 748 } |
884 Element element = ElementLocator.locate(node); | 749 Element element = ElementLocator.locate(node); |
885 if (node is SimpleIdentifier && element is PrefixElement) { | 750 if (node is SimpleIdentifier && element is PrefixElement) { |
886 element = getImportElement(node); | 751 element = getImportElement(node); |
887 } | 752 } |
888 return element; | 753 return element; |
889 } | 754 } |
890 | 755 |
891 /** | 756 /** |
892 * Return an analysis error info containing the array of all of the errors and | |
893 * the line info associated with [file]. | |
894 * | |
895 * Returns `null` if [file] does not belong to any [AnalysisContext], or the | |
896 * file does not exist. | |
897 * | |
898 * The array of errors will be empty if there are no errors in [file]. The | |
899 * errors contained in the array can be incomplete. | |
900 * | |
901 * This method does not wait for all errors to be computed, and returns just | |
902 * the current state. | |
903 */ | |
904 AnalysisErrorInfo getErrors(String file) { | |
905 ContextSourcePair contextSource = getContextSourcePair(file); | |
906 AnalysisContext context = contextSource.context; | |
907 Source source = contextSource.source; | |
908 if (context == null) { | |
909 return null; | |
910 } | |
911 if (!context.exists(source)) { | |
912 return null; | |
913 } | |
914 return context.getErrors(source); | |
915 } | |
916 | |
917 /** | |
918 * Return a [Future] that completes with the resolved [AstNode] at the | 757 * Return a [Future] that completes with the resolved [AstNode] at the |
919 * given [offset] of the given [file], or with `null` if there is no node as | 758 * given [offset] of the given [file], or with `null` if there is no node as |
920 * the [offset]. | 759 * the [offset]. |
921 */ | 760 */ |
922 Future<AstNode> getNodeAtOffset(String file, int offset) async { | 761 Future<AstNode> getNodeAtOffset(String file, int offset) async { |
923 CompilationUnit unit; | 762 nd.AnalysisResult result = await getAnalysisResult(file); |
924 if (options.enableNewAnalysisDriver) { | 763 CompilationUnit unit = result?.unit; |
925 nd.AnalysisResult result = await getAnalysisResult(file); | |
926 unit = result?.unit; | |
927 } else { | |
928 unit = await getResolvedCompilationUnit(file); | |
929 } | |
930 if (unit != null) { | 764 if (unit != null) { |
931 return new NodeLocator(offset).searchWithin(unit); | 765 return new NodeLocator(offset).searchWithin(unit); |
932 } | 766 } |
933 return null; | 767 return null; |
934 } | 768 } |
935 | 769 |
936 /** | 770 /** |
937 * Return a [Future] that completes with the resolved [CompilationUnit] for | 771 * Return a [Future] that completes with the resolved [CompilationUnit] for |
938 * the Dart file with the given [path], or with `null` if the file is not a | 772 * the Dart file with the given [path], or with `null` if the file is not a |
939 * Dart file or cannot be resolved. | 773 * Dart file or cannot be resolved. |
940 */ | 774 */ |
941 Future<CompilationUnit> getResolvedCompilationUnit(String path) async { | 775 Future<CompilationUnit> getResolvedCompilationUnit(String path) async { |
942 if (options.enableNewAnalysisDriver) { | 776 nd.AnalysisResult result = await getAnalysisResult(path); |
943 nd.AnalysisResult result = await getAnalysisResult(path); | 777 return result?.unit; |
944 return result?.unit; | |
945 } | |
946 ContextSourcePair contextSource = getContextSourcePair(path); | |
947 AnalysisContext context = contextSource.context; | |
948 if (context == null) { | |
949 return null; | |
950 } | |
951 return runWithActiveContext(context, () { | |
952 Source unitSource = contextSource.source; | |
953 List<Source> librarySources = context.getLibrariesContaining(unitSource); | |
954 for (Source librarySource in librarySources) { | |
955 return context.resolveCompilationUnit2(unitSource, librarySource); | |
956 } | |
957 return null; | |
958 }); | |
959 } | 778 } |
960 | 779 |
961 // TODO(brianwilkerson) Add the following method after 'prioritySources' has | 780 // TODO(brianwilkerson) Add the following method after 'prioritySources' has |
962 // been added to InternalAnalysisContext. | 781 // been added to InternalAnalysisContext. |
963 // /** | 782 // /** |
964 // * Return a list containing the full names of all of the sources that are | 783 // * Return a list containing the full names of all of the sources that are |
965 // * priority sources. | 784 // * priority sources. |
966 // */ | 785 // */ |
967 // List<String> getPriorityFiles() { | 786 // List<String> getPriorityFiles() { |
968 // List<String> priorityFiles = new List<String>(); | 787 // List<String> priorityFiles = new List<String>(); |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1037 /** | 856 /** |
1038 * Return `true` if the given path is a valid `FilePath`. | 857 * Return `true` if the given path is a valid `FilePath`. |
1039 * | 858 * |
1040 * This means that it is absolute and normalized. | 859 * This means that it is absolute and normalized. |
1041 */ | 860 */ |
1042 bool isValidFilePath(String path) { | 861 bool isValidFilePath(String path) { |
1043 return resourceProvider.absolutePathContext.isValid(path); | 862 return resourceProvider.absolutePathContext.isValid(path); |
1044 } | 863 } |
1045 | 864 |
1046 /** | 865 /** |
1047 * Returns a [Future] completing when [file] has been completely analyzed, in | |
1048 * particular, all its errors have been computed. The future is completed | |
1049 * with an [AnalysisDoneReason] indicating what caused the file's analysis to | |
1050 * be considered complete. | |
1051 * | |
1052 * If the given file doesn't belong to any context, null is returned. | |
1053 * | |
1054 * TODO(scheglov) this method should be improved. | |
1055 * | |
1056 * 1. The analysis context should be told to analyze this particular file ASAP
. | |
1057 * | |
1058 * 2. We should complete the future as soon as the file is analyzed (not wait | |
1059 * until the context is completely finished) | |
1060 */ | |
1061 Future<AnalysisDoneReason> onFileAnalysisComplete(String file) { | |
1062 // prepare AnalysisContext | |
1063 AnalysisContext context = getAnalysisContext(file); | |
1064 if (context == null) { | |
1065 return null; | |
1066 } | |
1067 // done if everything is already analyzed | |
1068 if (isAnalysisComplete()) { | |
1069 return new Future.value(AnalysisDoneReason.COMPLETE); | |
1070 } | |
1071 // schedule context analysis | |
1072 schedulePerformAnalysisOperation(context); | |
1073 // associate with the context completer | |
1074 Completer<AnalysisDoneReason> completer = | |
1075 contextAnalysisDoneCompleters[context]; | |
1076 if (completer == null) { | |
1077 completer = new Completer<AnalysisDoneReason>(); | |
1078 contextAnalysisDoneCompleters[context] = completer; | |
1079 } | |
1080 return completer.future; | |
1081 } | |
1082 | |
1083 /** | |
1084 * Perform the next available [ServerOperation]. | 866 * Perform the next available [ServerOperation]. |
1085 */ | 867 */ |
1086 void performOperation() { | 868 void performOperation() { |
1087 assert(performOperationPending); | 869 assert(performOperationPending); |
1088 PerformanceTag.unknown.makeCurrent(); | 870 PerformanceTag.unknown.makeCurrent(); |
1089 performOperationPending = false; | 871 performOperationPending = false; |
1090 if (!running) { | 872 if (!running) { |
1091 // An error has occurred, or the connection to the client has been | 873 // An error has occurred, or the connection to the client has been |
1092 // closed, since this method was scheduled on the event queue. So | 874 // closed, since this method was scheduled on the event queue. So |
1093 // don't do anything. Instead clear the operation queue. | 875 // don't do anything. Instead clear the operation queue. |
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1334 } | 1116 } |
1335 | 1117 |
1336 /** | 1118 /** |
1337 * Implementation for `analysis.setSubscriptions`. | 1119 * Implementation for `analysis.setSubscriptions`. |
1338 */ | 1120 */ |
1339 void setAnalysisSubscriptions( | 1121 void setAnalysisSubscriptions( |
1340 Map<AnalysisService, Set<String>> subscriptions) { | 1122 Map<AnalysisService, Set<String>> subscriptions) { |
1341 if (notificationManager != null) { | 1123 if (notificationManager != null) { |
1342 notificationManager.setSubscriptions(subscriptions); | 1124 notificationManager.setSubscriptions(subscriptions); |
1343 } | 1125 } |
1344 if (options.enableNewAnalysisDriver) { | 1126 this.analysisServices = subscriptions; |
1345 this.analysisServices = subscriptions; | 1127 Set<String> allNewFiles = |
1346 Set<String> allNewFiles = | 1128 subscriptions.values.expand((files) => files).toSet(); |
1347 subscriptions.values.expand((files) => files).toSet(); | 1129 for (String file in allNewFiles) { |
1348 for (String file in allNewFiles) { | 1130 // The result will be produced by the "results" stream with |
1349 // The result will be produced by the "results" stream with | 1131 // the fully resolved unit, and processed with sending analysis |
1350 // the fully resolved unit, and processed with sending analysis | 1132 // notifications as it happens after content changes. |
1351 // notifications as it happens after content changes. | 1133 if (AnalysisEngine.isDartFileName(file)) { |
1352 if (AnalysisEngine.isDartFileName(file)) { | 1134 getAnalysisResult(file); |
1353 getAnalysisResult(file); | |
1354 } | |
1355 } | 1135 } |
1356 return; | |
1357 } | |
1358 // send notifications for already analyzed sources | |
1359 subscriptions.forEach((service, Set<String> newFiles) { | |
1360 Set<String> oldFiles = analysisServices[service]; | |
1361 Set<String> todoFiles = | |
1362 oldFiles != null ? newFiles.difference(oldFiles) : newFiles; | |
1363 for (String file in todoFiles) { | |
1364 if (contextManager.isIgnored(file)) { | |
1365 continue; | |
1366 } | |
1367 // prepare context | |
1368 ContextSourcePair contextSource = getContextSourcePair(file); | |
1369 AnalysisContext context = contextSource.context; | |
1370 if (context == null) { | |
1371 continue; | |
1372 } | |
1373 Source source = contextSource.source; | |
1374 // Ensure that if the AST is flushed / not ready, it will be | |
1375 // computed eventually. | |
1376 if (AnalysisEngine.isDartFileName(file)) { | |
1377 (context as InternalAnalysisContext).ensureResolvedDartUnits(source); | |
1378 } | |
1379 // Send notifications that don't directly take an AST. | |
1380 switch (service) { | |
1381 case AnalysisService.NAVIGATION: | |
1382 sendAnalysisNotificationNavigation(this, context, source); | |
1383 continue; | |
1384 case AnalysisService.OCCURRENCES: | |
1385 sendAnalysisNotificationOccurrences(this, context, source); | |
1386 continue; | |
1387 } | |
1388 // Dart unit notifications. | |
1389 if (AnalysisEngine.isDartFileName(file)) { | |
1390 // TODO(scheglov) This way to get resolved information is very Dart | |
1391 // specific. OTOH as it is planned now Angular results are not | |
1392 // flushable. | |
1393 CompilationUnit dartUnit = | |
1394 _getResolvedCompilationUnitToResendNotification(context, source); | |
1395 if (dartUnit != null) { | |
1396 switch (service) { | |
1397 case AnalysisService.HIGHLIGHTS: | |
1398 sendAnalysisNotificationHighlights(this, file, dartUnit); | |
1399 break; | |
1400 case AnalysisService.OUTLINE: | |
1401 AnalysisContext context = resolutionMap | |
1402 .elementDeclaredByCompilationUnit(dartUnit) | |
1403 .context; | |
1404 LineInfo lineInfo = context.getLineInfo(source); | |
1405 SourceKind kind = context.getKindOf(source); | |
1406 sendAnalysisNotificationOutline( | |
1407 this, file, lineInfo, kind, dartUnit); | |
1408 break; | |
1409 case AnalysisService.OVERRIDES: | |
1410 sendAnalysisNotificationOverrides(this, file, dartUnit); | |
1411 break; | |
1412 } | |
1413 } | |
1414 } | |
1415 } | |
1416 }); | |
1417 // remember new subscriptions | |
1418 this.analysisServices = subscriptions; | |
1419 // special case for implemented elements | |
1420 if (analysisServices.containsKey(AnalysisService.IMPLEMENTED) && | |
1421 isAnalysisComplete()) { | |
1422 _scheduleAnalysisImplementedNotification(); | |
1423 } | 1136 } |
1424 } | 1137 } |
1425 | 1138 |
1426 /** | 1139 /** |
1427 * Implementation for `analysis.setGeneralSubscriptions`. | 1140 * Implementation for `analysis.setGeneralSubscriptions`. |
1428 */ | 1141 */ |
1429 void setGeneralAnalysisSubscriptions( | 1142 void setGeneralAnalysisSubscriptions( |
1430 List<GeneralAnalysisService> subscriptions) { | 1143 List<GeneralAnalysisService> subscriptions) { |
1431 Set<GeneralAnalysisService> newServices = subscriptions.toSet(); | 1144 Set<GeneralAnalysisService> newServices = subscriptions.toSet(); |
1432 if (newServices.contains(GeneralAnalysisService.ANALYZED_FILES) && | 1145 if (newServices.contains(GeneralAnalysisService.ANALYZED_FILES) && |
1433 !generalAnalysisServices | 1146 !generalAnalysisServices |
1434 .contains(GeneralAnalysisService.ANALYZED_FILES) && | 1147 .contains(GeneralAnalysisService.ANALYZED_FILES) && |
1435 isAnalysisComplete()) { | 1148 isAnalysisComplete()) { |
1436 sendAnalysisNotificationAnalyzedFiles(this); | 1149 sendAnalysisNotificationAnalyzedFiles(this); |
1437 } else if (!newServices.contains(GeneralAnalysisService.ANALYZED_FILES) && | 1150 } else if (!newServices.contains(GeneralAnalysisService.ANALYZED_FILES) && |
1438 generalAnalysisServices | 1151 generalAnalysisServices |
1439 .contains(GeneralAnalysisService.ANALYZED_FILES)) { | 1152 .contains(GeneralAnalysisService.ANALYZED_FILES)) { |
1440 prevAnalyzedFiles = null; | 1153 prevAnalyzedFiles = null; |
1441 } | 1154 } |
1442 generalAnalysisServices = newServices; | 1155 generalAnalysisServices = newServices; |
1443 } | 1156 } |
1444 | 1157 |
1445 /** | 1158 /** |
1446 * Set the priority files to the given [files]. | 1159 * Set the priority files to the given [files]. |
1447 */ | 1160 */ |
1448 void setPriorityFiles(String requestId, List<String> files) { | 1161 void setPriorityFiles(String requestId, List<String> files) { |
1449 if (options.enableNewAnalysisDriver) { | 1162 priorityFiles.clear(); |
1450 priorityFiles.clear(); | 1163 priorityFiles.addAll(files); |
1451 priorityFiles.addAll(files); | 1164 // Set priority files in drivers. |
1452 // Set priority files in drivers. | 1165 driverMap.values.forEach((driver) { |
1453 driverMap.values.forEach((driver) { | 1166 driver.priorityFiles = files; |
1454 driver.priorityFiles = files; | |
1455 }); | |
1456 return; | |
1457 } | |
1458 // Note: when a file is a priority file, that information needs to be | |
1459 // propagated to all contexts that analyze the file, so that all contexts | |
1460 // will be able to do incremental resolution of the file. See | |
1461 // dartbug.com/22209. | |
1462 Map<AnalysisContext, List<Source>> sourceMap = | |
1463 new HashMap<AnalysisContext, List<Source>>(); | |
1464 List<String> unanalyzed = new List<String>(); | |
1465 Source firstSource = null; | |
1466 files.forEach((String file) { | |
1467 if (contextManager.isIgnored(file)) { | |
1468 unanalyzed.add(file); | |
1469 return; | |
1470 } | |
1471 // Prepare the context/source pair. | |
1472 ContextSourcePair contextSource = getContextSourcePair(file); | |
1473 AnalysisContext preferredContext = contextSource.context; | |
1474 Source source = contextSource.source; | |
1475 // Try to make the file analyzable. | |
1476 // If it is not in any context yet, add it to the first one which | |
1477 // could use it, e.g. imports its package, even if not the library. | |
1478 if (preferredContext == null) { | |
1479 Resource resource = resourceProvider.getResource(file); | |
1480 if (resource is File && resource.exists) { | |
1481 for (AnalysisContext context in analysisContexts) { | |
1482 Uri uri = context.sourceFactory.restoreUri(source); | |
1483 if (uri.scheme != 'file') { | |
1484 preferredContext = context; | |
1485 source = | |
1486 ContextManagerImpl.createSourceInContext(context, resource); | |
1487 break; | |
1488 } | |
1489 } | |
1490 } | |
1491 } | |
1492 // Fill the source map. | |
1493 bool contextFound = false; | |
1494 if (preferredContext != null) { | |
1495 sourceMap.putIfAbsent(preferredContext, () => <Source>[]).add(source); | |
1496 contextFound = true; | |
1497 } | |
1498 for (AnalysisContext context in analysisContexts) { | |
1499 if (context != preferredContext && | |
1500 context.getKindOf(source) != SourceKind.UNKNOWN) { | |
1501 sourceMap.putIfAbsent(context, () => <Source>[]).add(source); | |
1502 contextFound = true; | |
1503 } | |
1504 } | |
1505 if (firstSource == null) { | |
1506 firstSource = source; | |
1507 } | |
1508 if (!contextFound) { | |
1509 unanalyzed.add(file); | |
1510 } | |
1511 }); | 1167 }); |
1512 if (unanalyzed.isNotEmpty) { | |
1513 StringBuffer buffer = new StringBuffer(); | |
1514 buffer.writeAll(unanalyzed, ', '); | |
1515 throw new RequestFailure( | |
1516 new Response.unanalyzedPriorityFiles(requestId, buffer.toString())); | |
1517 } | |
1518 sourceMap.forEach((context, List<Source> sourceList) { | |
1519 context.analysisPriorityOrder = sourceList; | |
1520 // Schedule the context for analysis so that it has the opportunity to | |
1521 // cache the AST's for the priority sources as soon as possible. | |
1522 schedulePerformAnalysisOperation(context); | |
1523 }); | |
1524 operationQueue.reschedule(); | |
1525 _onPriorityChangeController.add(new PriorityChangeEvent(firstSource)); | |
1526 } | 1168 } |
1527 | 1169 |
1528 /** | 1170 /** |
1529 * Returns `true` if errors should be reported for [file] with the given | 1171 * Returns `true` if errors should be reported for [file] with the given |
1530 * absolute path. | 1172 * absolute path. |
1531 */ | 1173 */ |
1532 bool shouldSendErrorsNotificationFor(String file) { | 1174 bool shouldSendErrorsNotificationFor(String file) { |
1533 return contextManager.isInAnalysisRoot(file); | 1175 return contextManager.isInAnalysisRoot(file); |
1534 } | 1176 } |
1535 | 1177 |
1536 void shutdown() { | 1178 void shutdown() { |
1537 running = false; | 1179 running = false; |
1538 if (index != null) { | 1180 if (index != null) { |
1539 index.stop(); | 1181 index.stop(); |
1540 } | 1182 } |
1541 // Defer closing the channel and shutting down the instrumentation server so | 1183 // Defer closing the channel and shutting down the instrumentation server so |
1542 // that the shutdown response can be sent and logged. | 1184 // that the shutdown response can be sent and logged. |
1543 new Future(() { | 1185 new Future(() { |
1544 instrumentationService.shutdown(); | 1186 instrumentationService.shutdown(); |
1545 channel.close(); | 1187 channel.close(); |
1546 }); | 1188 }); |
1547 } | 1189 } |
1548 | 1190 |
1549 void test_flushAstStructures(String file) { | |
1550 if (AnalysisEngine.isDartFileName(file)) { | |
1551 ContextSourcePair contextSource = getContextSourcePair(file); | |
1552 InternalAnalysisContext context = contextSource.context; | |
1553 Source source = contextSource.source; | |
1554 context.test_flushAstStructures(source); | |
1555 } | |
1556 } | |
1557 | |
1558 /** | 1191 /** |
1559 * Performs all scheduled analysis operations. | 1192 * Performs all scheduled analysis operations. |
1560 */ | 1193 */ |
1561 void test_performAllAnalysisOperations() { | 1194 void test_performAllAnalysisOperations() { |
1562 while (true) { | 1195 while (true) { |
1563 ServerOperation operation = operationQueue.takeIf((operation) { | 1196 ServerOperation operation = operationQueue.takeIf((operation) { |
1564 return operation is PerformAnalysisOperation; | 1197 return operation is PerformAnalysisOperation; |
1565 }); | 1198 }); |
1566 if (operation == null) { | 1199 if (operation == null) { |
1567 break; | 1200 break; |
1568 } | 1201 } |
1569 operation.perform(this); | 1202 operation.perform(this); |
1570 } | 1203 } |
1571 } | 1204 } |
1572 | 1205 |
1573 /** | 1206 /** |
1574 * Implementation for `analysis.updateContent`. | 1207 * Implementation for `analysis.updateContent`. |
1575 */ | 1208 */ |
1576 void updateContent(String id, Map<String, dynamic> changes) { | 1209 void updateContent(String id, Map<String, dynamic> changes) { |
1577 if (options.enableNewAnalysisDriver) { | |
1578 changes.forEach((file, change) { | |
1579 // Prepare the new contents. | |
1580 String oldContents = fileContentOverlay[file]; | |
1581 String newContents; | |
1582 if (change is AddContentOverlay) { | |
1583 newContents = change.content; | |
1584 } else if (change is ChangeContentOverlay) { | |
1585 if (oldContents == null) { | |
1586 // The client may only send a ChangeContentOverlay if there is | |
1587 // already an existing overlay for the source. | |
1588 throw new RequestFailure(new Response(id, | |
1589 error: new RequestError(RequestErrorCode.INVALID_OVERLAY_CHANGE, | |
1590 'Invalid overlay change'))); | |
1591 } | |
1592 try { | |
1593 newContents = SourceEdit.applySequence(oldContents, change.edits); | |
1594 } on RangeError { | |
1595 throw new RequestFailure(new Response(id, | |
1596 error: new RequestError(RequestErrorCode.INVALID_OVERLAY_CHANGE, | |
1597 'Invalid overlay change'))); | |
1598 } | |
1599 } else if (change is RemoveContentOverlay) { | |
1600 newContents = null; | |
1601 } else { | |
1602 // Protocol parsing should have ensured that we never get here. | |
1603 throw new AnalysisException('Illegal change type'); | |
1604 } | |
1605 | |
1606 fileContentOverlay[file] = newContents; | |
1607 | |
1608 driverMap.values.forEach((driver) { | |
1609 driver.changeFile(file); | |
1610 }); | |
1611 | |
1612 // temporary plugin support: | |
1613 _onFileChangedController.add(file); | |
1614 | |
1615 // If the file did not exist, and is "overlay only", it still should be | |
1616 // analyzed. Add it to driver to which it should have been added. | |
1617 contextManager.getDriverFor(file)?.addFile(file); | |
1618 | |
1619 // TODO(scheglov) implement other cases | |
1620 }); | |
1621 return; | |
1622 } | |
1623 changes.forEach((file, change) { | 1210 changes.forEach((file, change) { |
1624 ContextSourcePair contextSource = getContextSourcePair(file); | |
1625 Source source = contextSource.source; | |
1626 operationQueue.sourceAboutToChange(source); | |
1627 // Prepare the new contents. | 1211 // Prepare the new contents. |
1628 String oldContents = overlayState.getContents(source); | 1212 String oldContents = fileContentOverlay[file]; |
1629 String newContents; | 1213 String newContents; |
1630 if (change is AddContentOverlay) { | 1214 if (change is AddContentOverlay) { |
1631 newContents = change.content; | 1215 newContents = change.content; |
1632 } else if (change is ChangeContentOverlay) { | 1216 } else if (change is ChangeContentOverlay) { |
1633 if (oldContents == null) { | 1217 if (oldContents == null) { |
1634 // The client may only send a ChangeContentOverlay if there is | 1218 // The client may only send a ChangeContentOverlay if there is |
1635 // already an existing overlay for the source. | 1219 // already an existing overlay for the source. |
1636 throw new RequestFailure(new Response(id, | 1220 throw new RequestFailure(new Response(id, |
1637 error: new RequestError(RequestErrorCode.INVALID_OVERLAY_CHANGE, | 1221 error: new RequestError(RequestErrorCode.INVALID_OVERLAY_CHANGE, |
1638 'Invalid overlay change'))); | 1222 'Invalid overlay change'))); |
1639 } | 1223 } |
1640 try { | 1224 try { |
1641 newContents = SourceEdit.applySequence(oldContents, change.edits); | 1225 newContents = SourceEdit.applySequence(oldContents, change.edits); |
1642 } on RangeError { | 1226 } on RangeError { |
1643 throw new RequestFailure(new Response(id, | 1227 throw new RequestFailure(new Response(id, |
1644 error: new RequestError(RequestErrorCode.INVALID_OVERLAY_CHANGE, | 1228 error: new RequestError(RequestErrorCode.INVALID_OVERLAY_CHANGE, |
1645 'Invalid overlay change'))); | 1229 'Invalid overlay change'))); |
1646 } | 1230 } |
1647 } else if (change is RemoveContentOverlay) { | 1231 } else if (change is RemoveContentOverlay) { |
1648 newContents = null; | 1232 newContents = null; |
1649 } else { | 1233 } else { |
1650 // Protocol parsing should have ensured that we never get here. | 1234 // Protocol parsing should have ensured that we never get here. |
1651 throw new AnalysisException('Illegal change type'); | 1235 throw new AnalysisException('Illegal change type'); |
1652 } | 1236 } |
1653 | 1237 |
1654 AnalysisContext containingContext = getContainingContext(file); | 1238 fileContentOverlay[file] = newContents; |
1655 | 1239 |
1656 // Check for an implicitly added but missing source. | 1240 driverMap.values.forEach((driver) { |
1657 // (For example, the target of an import might not exist yet.) | 1241 driver.changeFile(file); |
1658 // We need to do this before setContents, which changes the stamp. | 1242 }); |
1659 bool wasMissing = containingContext?.getModificationStamp(source) == -1; | |
1660 | 1243 |
1661 overlayState.setContents(source, newContents); | 1244 // temporary plugin support: |
1662 // If the source does not exist, then it was an overlay-only one. | 1245 _onFileChangedController.add(file); |
1663 // Remove it from contexts. | 1246 |
1664 if (newContents == null && !source.exists()) { | 1247 // If the file did not exist, and is "overlay only", it still should be |
1665 for (InternalAnalysisContext context in analysisContexts) { | 1248 // analyzed. Add it to driver to which it should have been added. |
1666 List<Source> sources = context.getSourcesWithFullName(file); | 1249 contextManager.getDriverFor(file)?.addFile(file); |
1667 ChangeSet changeSet = new ChangeSet(); | 1250 |
1668 sources.forEach(changeSet.removedSource); | 1251 // TODO(scheglov) implement other cases |
1669 context.applyChanges(changeSet); | |
1670 schedulePerformAnalysisOperation(context); | |
1671 } | |
1672 return; | |
1673 } | |
1674 // Update all contexts. | |
1675 bool anyContextUpdated = false; | |
1676 for (InternalAnalysisContext context in analysisContexts) { | |
1677 List<Source> sources = context.getSourcesWithFullName(file); | |
1678 sources.forEach((Source source) { | |
1679 anyContextUpdated = true; | |
1680 if (context == containingContext && wasMissing) { | |
1681 // Promote missing source to an explicitly added Source. | |
1682 context.applyChanges(new ChangeSet()..addedSource(source)); | |
1683 schedulePerformAnalysisOperation(context); | |
1684 } | |
1685 if (context.handleContentsChanged( | |
1686 source, oldContents, newContents, true)) { | |
1687 schedulePerformAnalysisOperation(context); | |
1688 } else { | |
1689 // When the client sends any change for a source, we should resend | |
1690 // subscribed notifications, even if there were no changes in the | |
1691 // source contents. | |
1692 // TODO(scheglov) consider checking if there are subscriptions. | |
1693 if (AnalysisEngine.isDartFileName(file)) { | |
1694 List<CompilationUnit> dartUnits = | |
1695 context.ensureResolvedDartUnits(source); | |
1696 if (dartUnits != null) { | |
1697 AnalysisErrorInfo errorInfo = context.getErrors(source); | |
1698 for (var dartUnit in dartUnits) { | |
1699 scheduleNotificationOperations( | |
1700 this, | |
1701 source, | |
1702 file, | |
1703 errorInfo.lineInfo, | |
1704 context, | |
1705 null, | |
1706 dartUnit, | |
1707 errorInfo.errors); | |
1708 scheduleIndexOperation(this, file, dartUnit); | |
1709 } | |
1710 } else { | |
1711 schedulePerformAnalysisOperation(context); | |
1712 } | |
1713 } | |
1714 } | |
1715 }); | |
1716 } | |
1717 // The source is not analyzed by any context, add to the containing one. | |
1718 if (!anyContextUpdated) { | |
1719 AnalysisContext context = contextSource.context; | |
1720 if (context != null && source != null) { | |
1721 ChangeSet changeSet = new ChangeSet(); | |
1722 changeSet.addedSource(source); | |
1723 context.applyChanges(changeSet); | |
1724 schedulePerformAnalysisOperation(context); | |
1725 } | |
1726 } | |
1727 }); | 1252 }); |
1728 } | 1253 } |
1729 | 1254 |
1730 /** | 1255 /** |
1731 * Use the given updaters to update the values of the options in every | 1256 * Use the given updaters to update the values of the options in every |
1732 * existing analysis context. | 1257 * existing analysis context. |
1733 */ | 1258 */ |
1734 void updateOptions(List<OptionUpdater> optionUpdaters) { | 1259 void updateOptions(List<OptionUpdater> optionUpdaters) { |
1735 if (options.enableNewAnalysisDriver) { | 1260 // TODO(scheglov) implement for the new analysis driver |
1736 // TODO(scheglov) implement for the new analysis driver | 1261 // // |
1737 return; | 1262 // // Update existing contexts. |
1738 } | 1263 // // |
1739 // | 1264 // for (AnalysisContext context in analysisContexts) { |
1740 // Update existing contexts. | 1265 // AnalysisOptionsImpl options = |
1741 // | 1266 // new AnalysisOptionsImpl.from(context.analysisOptions); |
1742 for (AnalysisContext context in analysisContexts) { | 1267 // optionUpdaters.forEach((OptionUpdater optionUpdater) { |
1743 AnalysisOptionsImpl options = | 1268 // optionUpdater(options); |
1744 new AnalysisOptionsImpl.from(context.analysisOptions); | 1269 // }); |
1745 optionUpdaters.forEach((OptionUpdater optionUpdater) { | 1270 // context.analysisOptions = options; |
1746 optionUpdater(options); | 1271 // // TODO(brianwilkerson) As far as I can tell, this doesn't cause analysi
s |
1747 }); | 1272 // // to be scheduled for this context. |
1748 context.analysisOptions = options; | 1273 // } |
1749 // TODO(brianwilkerson) As far as I can tell, this doesn't cause analysis | 1274 // // |
1750 // to be scheduled for this context. | 1275 // // Update the defaults used to create new contexts. |
1751 } | 1276 // // |
1752 // | 1277 // optionUpdaters.forEach((OptionUpdater optionUpdater) { |
1753 // Update the defaults used to create new contexts. | 1278 // optionUpdater(defaultContextOptions); |
1754 // | 1279 // }); |
1755 optionUpdaters.forEach((OptionUpdater optionUpdater) { | |
1756 optionUpdater(defaultContextOptions); | |
1757 }); | |
1758 } | 1280 } |
1759 | 1281 |
1760 void _computingPackageMap(bool computing) { | 1282 void _computingPackageMap(bool computing) { |
1761 if (serverServices.contains(ServerService.STATUS)) { | 1283 if (serverServices.contains(ServerService.STATUS)) { |
1762 PubStatus pubStatus = new PubStatus(computing); | 1284 PubStatus pubStatus = new PubStatus(computing); |
1763 ServerStatusParams params = new ServerStatusParams(pub: pubStatus); | 1285 ServerStatusParams params = new ServerStatusParams(pub: pubStatus); |
1764 sendNotification(params.toNotification()); | 1286 sendNotification(params.toNotification()); |
1765 } | 1287 } |
1766 } | 1288 } |
1767 | 1289 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1805 Set<AnalysisContext> _getContexts(List<Resource> resources) { | 1327 Set<AnalysisContext> _getContexts(List<Resource> resources) { |
1806 Set<AnalysisContext> contexts = new HashSet<AnalysisContext>(); | 1328 Set<AnalysisContext> contexts = new HashSet<AnalysisContext>(); |
1807 resources.forEach((Resource resource) { | 1329 resources.forEach((Resource resource) { |
1808 if (resource is Folder) { | 1330 if (resource is Folder) { |
1809 contexts.addAll(contextManager.contextsInAnalysisRoot(resource)); | 1331 contexts.addAll(contextManager.contextsInAnalysisRoot(resource)); |
1810 } | 1332 } |
1811 }); | 1333 }); |
1812 return contexts; | 1334 return contexts; |
1813 } | 1335 } |
1814 | 1336 |
1815 /** | |
1816 * Returns the [CompilationUnit] of the Dart file with the given [source] that | |
1817 * should be used to resend notifications for already resolved unit. | |
1818 * Returns `null` if the file is not a part of any context, library has not | |
1819 * been yet resolved, or any problem happened. | |
1820 */ | |
1821 CompilationUnit _getResolvedCompilationUnitToResendNotification( | |
1822 AnalysisContext context, Source source) { | |
1823 List<Source> librarySources = context.getLibrariesContaining(source); | |
1824 if (librarySources.isEmpty) { | |
1825 return null; | |
1826 } | |
1827 // if library has not been resolved yet, the unit will be resolved later | |
1828 Source librarySource = librarySources[0]; | |
1829 if (context.getResult(librarySource, LIBRARY_ELEMENT6) == null) { | |
1830 return null; | |
1831 } | |
1832 // if library has been already resolved, resolve unit | |
1833 return runWithActiveContext(context, () { | |
1834 return context.resolveCompilationUnit2(source, librarySource); | |
1835 }); | |
1836 } | |
1837 | |
1838 bool _hasAnalysisServiceSubscription(AnalysisService service, String file) { | 1337 bool _hasAnalysisServiceSubscription(AnalysisService service, String file) { |
1839 return analysisServices[service]?.contains(file) ?? false; | 1338 return analysisServices[service]?.contains(file) ?? false; |
1840 } | 1339 } |
1841 | 1340 |
1842 _scheduleAnalysisImplementedNotification() async { | 1341 _scheduleAnalysisImplementedNotification() async { |
1843 Set<String> files = analysisServices[AnalysisService.IMPLEMENTED]; | 1342 Set<String> files = analysisServices[AnalysisService.IMPLEMENTED]; |
1844 if (files != null) { | 1343 if (files != null) { |
1845 scheduleImplementedNotification(this, files); | 1344 scheduleImplementedNotification(this, files); |
1846 } | 1345 } |
1847 } | 1346 } |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1879 * | 1378 * |
1880 * It is possible that this method will do more in the future, e.g. listening | 1379 * It is possible that this method will do more in the future, e.g. listening |
1881 * for summary information and linking pre-indexed packages into the index, | 1380 * for summary information and linking pre-indexed packages into the index, |
1882 * but for now we only invalidate project specific index information. | 1381 * but for now we only invalidate project specific index information. |
1883 */ | 1382 */ |
1884 void _setupIndexInvalidation() { | 1383 void _setupIndexInvalidation() { |
1885 if (index == null) { | 1384 if (index == null) { |
1886 return; | 1385 return; |
1887 } | 1386 } |
1888 onContextsChanged.listen((ContextsChangedEvent event) { | 1387 onContextsChanged.listen((ContextsChangedEvent event) { |
1889 for (AnalysisContext context in event.added) { | 1388 // TODO(brianwilkerson) `onContextsChanged` should never have anything |
1890 context | 1389 // written to it. Figure out whether we need something like this under the |
1891 .onResultChanged(RESOLVED_UNIT3) | 1390 // new analysis driver, and remove this method if not. |
1892 .listen((ResultChangedEvent event) { | 1391 // for (AnalysisContext context in event.added) { |
1893 if (event.wasComputed) { | 1392 // context |
1894 Object value = event.value; | 1393 // .onResultChanged(RESOLVED_UNIT3) |
1895 if (value is CompilationUnit) { | 1394 // .listen((ResultChangedEvent event) { |
1896 index.indexDeclarations(value); | 1395 // if (event.wasComputed) { |
1897 } | 1396 // Object value = event.value; |
1898 } | 1397 // if (value is CompilationUnit) { |
1899 }); | 1398 // index.indexDeclarations(value); |
1900 context | 1399 // } |
1901 .onResultChanged(RESOLVED_UNIT) | 1400 // } |
1902 .listen((ResultChangedEvent event) { | 1401 // }); |
1903 if (event.wasInvalidated) { | 1402 // context |
1904 LibrarySpecificUnit target = event.target; | 1403 // .onResultChanged(RESOLVED_UNIT) |
1905 index.removeUnit(event.context, target.library, target.unit); | 1404 // .listen((ResultChangedEvent event) { |
1906 } | 1405 // if (event.wasInvalidated) { |
1907 }); | 1406 // LibrarySpecificUnit target = event.target; |
1908 } | 1407 // index.removeUnit(event.context, target.library, target.unit); |
1909 for (AnalysisContext context in event.removed) { | 1408 // } |
1910 index.removeContext(context); | 1409 // }); |
1911 } | 1410 // } |
| 1411 // for (AnalysisContext context in event.removed) { |
| 1412 // index.removeContext(context); |
| 1413 // } |
1912 }); | 1414 }); |
1913 } | 1415 } |
1914 } | 1416 } |
1915 | 1417 |
1916 class AnalysisServerOptions { | 1418 class AnalysisServerOptions { |
1917 bool enableIncrementalResolutionApi = false; | 1419 bool enableIncrementalResolutionApi = false; |
1918 bool enableIncrementalResolutionValidation = false; | 1420 bool enableIncrementalResolutionValidation = false; |
1919 bool enableNewAnalysisDriver = false; | |
1920 bool useAnalysisHighlight2 = false; | 1421 bool useAnalysisHighlight2 = false; |
1921 String fileReadMode = 'as-is'; | 1422 String fileReadMode = 'as-is'; |
1922 String newAnalysisDriverLog; | 1423 String newAnalysisDriverLog; |
1923 | 1424 |
1924 String clientId; | 1425 String clientId; |
1925 String clientVersion; | 1426 String clientVersion; |
1926 | 1427 |
1927 // IDE options | 1428 // IDE options |
1928 bool enableVerboseFlutterCompletions = false; | 1429 bool enableVerboseFlutterCompletions = false; |
1929 } | 1430 } |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2088 analysisServer.folderMap[folder] = context; | 1589 analysisServer.folderMap[folder] = context; |
2089 analysisServer._onContextsChangedController | 1590 analysisServer._onContextsChangedController |
2090 .add(new ContextsChangedEvent(added: [context])); | 1591 .add(new ContextsChangedEvent(added: [context])); |
2091 analysisServer.schedulePerformAnalysisOperation(context); | 1592 analysisServer.schedulePerformAnalysisOperation(context); |
2092 | 1593 |
2093 return context; | 1594 return context; |
2094 } | 1595 } |
2095 | 1596 |
2096 @override | 1597 @override |
2097 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet) { | 1598 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet) { |
2098 if (analysisServer.options.enableNewAnalysisDriver) { | 1599 nd.AnalysisDriver analysisDriver = analysisServer.driverMap[contextFolder]; |
2099 nd.AnalysisDriver analysisDriver = | 1600 if (analysisDriver != null) { |
2100 analysisServer.driverMap[contextFolder]; | 1601 changeSet.addedSources.forEach((source) { |
2101 if (analysisDriver != null) { | 1602 analysisDriver.addFile(source.fullName); |
2102 changeSet.addedSources.forEach((source) { | 1603 // temporary plugin support: |
2103 analysisDriver.addFile(source.fullName); | 1604 analysisServer._onFileAddedController.add(source.fullName); |
2104 // temporary plugin support: | 1605 }); |
2105 analysisServer._onFileAddedController.add(source.fullName); | 1606 changeSet.changedSources.forEach((source) { |
2106 }); | 1607 analysisDriver.changeFile(source.fullName); |
2107 changeSet.changedSources.forEach((source) { | 1608 // temporary plugin support: |
2108 analysisDriver.changeFile(source.fullName); | 1609 analysisServer._onFileChangedController.add(source.fullName); |
2109 // temporary plugin support: | 1610 }); |
2110 analysisServer._onFileChangedController.add(source.fullName); | 1611 changeSet.removedSources.forEach((source) { |
2111 }); | 1612 analysisDriver.removeFile(source.fullName); |
2112 changeSet.removedSources.forEach((source) { | 1613 }); |
2113 analysisDriver.removeFile(source.fullName); | |
2114 }); | |
2115 } | |
2116 } else { | |
2117 AnalysisContext context = analysisServer.folderMap[contextFolder]; | |
2118 if (context != null) { | |
2119 context.applyChanges(changeSet); | |
2120 analysisServer.schedulePerformAnalysisOperation(context); | |
2121 List<String> flushedFiles = new List<String>(); | |
2122 for (Source source in changeSet.removedSources) { | |
2123 flushedFiles.add(source.fullName); | |
2124 } | |
2125 sendAnalysisNotificationFlushResults(analysisServer, flushedFiles); | |
2126 } | |
2127 } | 1614 } |
2128 } | 1615 } |
2129 | 1616 |
2130 @override | 1617 @override |
2131 void applyFileRemoved(nd.AnalysisDriver driver, String file) { | 1618 void applyFileRemoved(nd.AnalysisDriver driver, String file) { |
2132 driver.removeFile(file); | 1619 driver.removeFile(file); |
2133 sendAnalysisNotificationFlushResults(analysisServer, [file]); | 1620 sendAnalysisNotificationFlushResults(analysisServer, [file]); |
2134 } | 1621 } |
2135 | 1622 |
2136 @override | 1623 @override |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2177 | 1664 |
2178 @override | 1665 @override |
2179 void moveContext(Folder from, Folder to) { | 1666 void moveContext(Folder from, Folder to) { |
2180 // There is nothing to do. | 1667 // There is nothing to do. |
2181 // This method is mostly for tests. | 1668 // This method is mostly for tests. |
2182 // Context managers manage folders and contexts themselves. | 1669 // Context managers manage folders and contexts themselves. |
2183 } | 1670 } |
2184 | 1671 |
2185 @override | 1672 @override |
2186 void removeContext(Folder folder, List<String> flushedFiles) { | 1673 void removeContext(Folder folder, List<String> flushedFiles) { |
2187 if (analysisServer.options.enableNewAnalysisDriver) { | 1674 sendAnalysisNotificationFlushResults(analysisServer, flushedFiles); |
2188 sendAnalysisNotificationFlushResults(analysisServer, flushedFiles); | 1675 nd.AnalysisDriver driver = analysisServer.driverMap.remove(folder); |
2189 nd.AnalysisDriver driver = analysisServer.driverMap.remove(folder); | 1676 driver.dispose(); |
2190 driver.dispose(); | |
2191 } else { | |
2192 AnalysisContext context = analysisServer.folderMap.remove(folder); | |
2193 sendAnalysisNotificationFlushResults(analysisServer, flushedFiles); | |
2194 | |
2195 analysisServer.operationQueue.contextRemoved(context); | |
2196 analysisServer._onContextsChangedController | |
2197 .add(new ContextsChangedEvent(removed: [context])); | |
2198 analysisServer.sendContextAnalysisDoneNotifications( | |
2199 context, AnalysisDoneReason.CONTEXT_REMOVED); | |
2200 context.dispose(); | |
2201 } | |
2202 } | 1677 } |
2203 | 1678 |
2204 @override | 1679 @override |
2205 void updateContextPackageUriResolver(AnalysisContext context) { | 1680 void updateContextPackageUriResolver(AnalysisContext context) { |
2206 analysisServer._onContextsChangedController | 1681 analysisServer._onContextsChangedController |
2207 .add(new ContextsChangedEvent(changed: [context])); | 1682 .add(new ContextsChangedEvent(changed: [context])); |
2208 analysisServer.schedulePerformAnalysisOperation(context); | 1683 analysisServer.schedulePerformAnalysisOperation(context); |
2209 } | 1684 } |
2210 | 1685 |
2211 List<HighlightRegion> _computeHighlightRegions(CompilationUnit unit) { | 1686 List<HighlightRegion> _computeHighlightRegions(CompilationUnit unit) { |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2401 /** | 1876 /** |
2402 * The [PerformanceTag] for time spent in server request handlers. | 1877 * The [PerformanceTag] for time spent in server request handlers. |
2403 */ | 1878 */ |
2404 static PerformanceTag serverRequests = server.createChild('requests'); | 1879 static PerformanceTag serverRequests = server.createChild('requests'); |
2405 | 1880 |
2406 /** | 1881 /** |
2407 * The [PerformanceTag] for time spent in split store microtasks. | 1882 * The [PerformanceTag] for time spent in split store microtasks. |
2408 */ | 1883 */ |
2409 static PerformanceTag splitStore = new PerformanceTag('splitStore'); | 1884 static PerformanceTag splitStore = new PerformanceTag('splitStore'); |
2410 } | 1885 } |
OLD | NEW |