diff --git a/pkg/analysis_server/lib/analysis/navigation/navigation_core.dart b/pkg/analysis_server/lib/analysis/navigation_core.dart similarity index 95% rename from pkg/analysis_server/lib/analysis/navigation/navigation_core.dart rename to pkg/analysis_server/lib/analysis/navigation_core.dart index e8566f46b39..528d1cea18d 100644 --- a/pkg/analysis_server/lib/analysis/navigation/navigation_core.dart +++ b/pkg/analysis_server/lib/analysis/navigation_core.dart @@ -2,7 +2,7 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -library analysis_server.analysis.navigation.navigation_core; +library analysis_server.analysis.navigation_core; import 'package:analysis_server/src/protocol.dart' show ElementKind, Location, NavigationRegion, NavigationTarget; diff --git a/pkg/analysis_server/lib/analysis/occurrences_core.dart b/pkg/analysis_server/lib/analysis/occurrences_core.dart new file mode 100644 index 00000000000..2e24a9b3c79 --- /dev/null +++ b/pkg/analysis_server/lib/analysis/occurrences_core.dart @@ -0,0 +1,35 @@ +// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +library analysis_server.analysis.occurrences_core; + +import 'package:analysis_server/src/protocol.dart' show Element, Occurrences; +import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; +import 'package:analyzer/src/generated/source.dart' show Source; + +/** + * An object used to produce occurrences. + * + * Clients are expected to subtype this class when implementing plugins. + */ +abstract class OccurrencesContributor { + /** + * Contribute occurrences into the given [collector]. + * The [context] can be used to get analysis results. + */ + void computeOccurrences( + OccurrencesCollector collector, AnalysisContext context, Source source); +} + +/** + * An object that [OccurrencesContributor]s use to record occurrences into. + * + * Clients are not expected to subtype this class. + */ +abstract class OccurrencesCollector { + /** + * Record a new element occurrences. + */ + void addOccurrences(Occurrences occurrences); +} diff --git a/pkg/analysis_server/lib/plugin/navigation.dart b/pkg/analysis_server/lib/plugin/navigation.dart index 23603f06f64..ad4b482090d 100644 --- a/pkg/analysis_server/lib/plugin/navigation.dart +++ b/pkg/analysis_server/lib/plugin/navigation.dart @@ -8,7 +8,7 @@ */ library analysis_server.plugin.navigation; -import 'package:analysis_server/analysis/navigation/navigation_core.dart'; +import 'package:analysis_server/analysis/navigation_core.dart'; import 'package:analysis_server/src/plugin/server_plugin.dart'; import 'package:plugin/plugin.dart'; diff --git a/pkg/analysis_server/lib/plugin/occurrences.dart b/pkg/analysis_server/lib/plugin/occurrences.dart new file mode 100644 index 00000000000..5339ccc4cc0 --- /dev/null +++ b/pkg/analysis_server/lib/plugin/occurrences.dart @@ -0,0 +1,22 @@ +// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/** + * Support for client code that extends the analysis server by adding new + * occurrences contributors. + */ +library analysis_server.plugin.occurrences; + +import 'package:analysis_server/analysis/occurrences_core.dart'; +import 'package:analysis_server/src/plugin/server_plugin.dart'; +import 'package:plugin/plugin.dart'; + +/** + * The identifier of the extension point that allows plugins to register + * element occurrences. The object used as an extension must be + * a [OccurrencesContributor]. + */ +final String OCCURRENCES_CONTRIBUTOR_EXTENSION_POINT_ID = Plugin.join( + ServerPlugin.UNIQUE_IDENTIFIER, + ServerPlugin.OCCURRENCES_CONTRIBUTOR_EXTENSION_POINT); diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart index 4aea8bae27f..76dc86ef7ad 100644 --- a/pkg/analysis_server/lib/src/analysis_server.dart +++ b/pkg/analysis_server/lib/src/analysis_server.dart @@ -975,7 +975,7 @@ class AnalysisServer { sendAnalysisNotificationNavigation(this, context, source); break; case AnalysisService.OCCURRENCES: - sendAnalysisNotificationOccurrences(this, file, dartUnit); + sendAnalysisNotificationOccurrences(this, context, source); break; case AnalysisService.OUTLINE: AnalysisContext context = dartUnit.element.context; diff --git a/pkg/analysis_server/lib/src/computer/computer_occurrences.dart b/pkg/analysis_server/lib/src/computer/computer_occurrences.dart deleted file mode 100644 index 4897a1a5fb3..00000000000 --- a/pkg/analysis_server/lib/src/computer/computer_occurrences.dart +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library computer.occurrences; - -import 'dart:collection'; - -import 'package:analysis_server/src/protocol_server.dart' as protocol; -import 'package:analyzer/src/generated/ast.dart'; -import 'package:analyzer/src/generated/element.dart'; - -/** - * A computer for elements occurrences in a Dart [CompilationUnit]. - */ -class DartUnitOccurrencesComputer { - final CompilationUnit _unit; - - final Map> _elementsOffsets = - new HashMap>(); - - DartUnitOccurrencesComputer(this._unit); - - /** - * Returns the computed occurrences, not `null`. - */ - List compute() { - _unit.accept(new _DartUnitOccurrencesComputerVisitor(this)); - List occurrences = []; - _elementsOffsets.forEach((engineElement, offsets) { - var serverElement = protocol.newElement_fromEngine(engineElement); - var length = engineElement.displayName.length; - occurrences.add(new protocol.Occurrences(serverElement, offsets, length)); - }); - return occurrences; - } - - void _addOccurrence(Element element, int offset) { - element = _canonicalizeElement(element); - if (element == null || element == DynamicElementImpl.instance) { - return; - } - List offsets = _elementsOffsets[element]; - if (offsets == null) { - offsets = []; - _elementsOffsets[element] = offsets; - } - offsets.add(offset); - } - - Element _canonicalizeElement(Element element) { - if (element is FieldFormalParameterElement) { - element = (element as FieldFormalParameterElement).field; - } - if (element is PropertyAccessorElement) { - element = (element as PropertyAccessorElement).variable; - } - if (element is Member) { - element = (element as Member).baseElement; - } - return element; - } -} - -class _DartUnitOccurrencesComputerVisitor extends RecursiveAstVisitor { - final DartUnitOccurrencesComputer computer; - - _DartUnitOccurrencesComputerVisitor(this.computer); - - @override - visitSimpleIdentifier(SimpleIdentifier node) { - Element element = node.bestElement; - if (element != null) { - computer._addOccurrence(element, node.offset); - } - return super.visitSimpleIdentifier(node); - } -} diff --git a/pkg/analysis_server/lib/src/domain_analysis.dart b/pkg/analysis_server/lib/src/domain_analysis.dart index 8c6be5146b6..48dcc67b630 100644 --- a/pkg/analysis_server/lib/src/domain_analysis.dart +++ b/pkg/analysis_server/lib/src/domain_analysis.dart @@ -14,7 +14,10 @@ import 'package:analysis_server/src/constants.dart'; import 'package:analysis_server/src/context_manager.dart'; import 'package:analysis_server/src/domains/analysis/navigation.dart'; import 'package:analysis_server/src/operation/operation_analysis.dart' - show NavigationOperation, sendAnalysisNotificationNavigation; + show + NavigationOperation, + OccurrencesOperation, + sendAnalysisNotificationNavigation; import 'package:analysis_server/src/protocol_server.dart'; import 'package:analysis_server/src/services/dependencies/library_dependencies.dart'; import 'package:analyzer/file_system/file_system.dart'; @@ -352,6 +355,9 @@ class AnalysisDomainImpl implements AnalysisDomain { if (service == AnalysisService.NAVIGATION) { server.scheduleOperation(new NavigationOperation(context, source)); } + if (service == AnalysisService.OCCURRENCES) { + server.scheduleOperation(new OccurrencesOperation(context, source)); + } } } diff --git a/pkg/analysis_server/lib/src/domains/analysis/navigation.dart b/pkg/analysis_server/lib/src/domains/analysis/navigation.dart index f323b17bde9..cb21c3d9c5b 100644 --- a/pkg/analysis_server/lib/src/domains/analysis/navigation.dart +++ b/pkg/analysis_server/lib/src/domains/analysis/navigation.dart @@ -1,4 +1,4 @@ -// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file +// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. @@ -6,7 +6,7 @@ library domains.analysis.navigation; import 'dart:collection'; -import 'package:analysis_server/analysis/navigation/navigation_core.dart'; +import 'package:analysis_server/analysis/navigation_core.dart'; import 'package:analysis_server/src/analysis_server.dart'; import 'package:analysis_server/src/collections.dart'; import 'package:analysis_server/src/protocol_server.dart' as protocol; diff --git a/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart b/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart index fe6c18a54c8..182f7621196 100644 --- a/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart +++ b/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart @@ -1,10 +1,10 @@ -// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file +// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. library domains.analysis.navigation_dart; -import 'package:analysis_server/analysis/navigation/navigation_core.dart'; +import 'package:analysis_server/analysis/navigation_core.dart'; import 'package:analysis_server/src/protocol_server.dart' as protocol; import 'package:analyzer/src/generated/ast.dart'; import 'package:analyzer/src/generated/element.dart'; diff --git a/pkg/analysis_server/lib/src/domains/analysis/occurrences.dart b/pkg/analysis_server/lib/src/domains/analysis/occurrences.dart new file mode 100644 index 00000000000..561693e3bbc --- /dev/null +++ b/pkg/analysis_server/lib/src/domains/analysis/occurrences.dart @@ -0,0 +1,45 @@ +// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +library domains.analysis.occurrences; + +import 'package:analysis_server/analysis/occurrences_core.dart'; +import 'package:analysis_server/src/analysis_server.dart'; +import 'package:analysis_server/src/protocol_server.dart' as protocol; +import 'package:analyzer/src/generated/engine.dart' + show AnalysisContext, AnalysisEngine; +import 'package:analyzer/src/generated/java_engine.dart' show CaughtException; +import 'package:analyzer/src/generated/source.dart' show Source; + +/** + * Compute all known occurrences for the given [source]. + */ +OccurrencesCollectorImpl computeOccurrences( + AnalysisServer server, AnalysisContext context, Source source) { + OccurrencesCollectorImpl collector = new OccurrencesCollectorImpl(); + List contributors = + server.serverPlugin.occurrencesContributors; + for (OccurrencesContributor contributor in contributors) { + try { + contributor.computeOccurrences(collector, context, source); + } catch (exception, stackTrace) { + AnalysisEngine.instance.logger.logError( + 'Exception from occurrences contributor: ${contributor.runtimeType}', + new CaughtException(exception, stackTrace)); + } + } + return collector; +} + +/** + * A concrete implementation of [OccurrencesCollector]. + */ +class OccurrencesCollectorImpl implements OccurrencesCollector { + final List allOccurrences = []; + + @override + void addOccurrences(protocol.Occurrences occurrences) { + allOccurrences.add(occurrences); + } +} diff --git a/pkg/analysis_server/lib/src/domains/analysis/occurrences_dart.dart b/pkg/analysis_server/lib/src/domains/analysis/occurrences_dart.dart new file mode 100644 index 00000000000..ebefbfbaea9 --- /dev/null +++ b/pkg/analysis_server/lib/src/domains/analysis/occurrences_dart.dart @@ -0,0 +1,79 @@ +// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +library domains.analysis.occurrences_dart; + +import 'package:analysis_server/analysis/occurrences_core.dart'; +import 'package:analysis_server/src/protocol_server.dart' as protocol; +import 'package:analyzer/src/generated/ast.dart'; +import 'package:analyzer/src/generated/element.dart'; +import 'package:analyzer/src/generated/engine.dart'; +import 'package:analyzer/src/generated/source.dart'; + +/** + * A computer for occurrences in a Dart [CompilationUnit]. + */ +class DartOccurrencesComputer implements OccurrencesContributor { + @override + void computeOccurrences( + OccurrencesCollector collector, AnalysisContext context, Source source) { + List libraries = context.getLibrariesContaining(source); + if (libraries.isNotEmpty) { + CompilationUnit unit = + context.getResolvedCompilationUnit2(source, libraries.first); + if (unit != null) { + _DartUnitOccurrencesComputerVisitor visitor = + new _DartUnitOccurrencesComputerVisitor(); + unit.accept(visitor); + visitor.elementsOffsets.forEach((engineElement, offsets) { + int length = engineElement.displayName.length; + protocol.Element serverElement = + protocol.newElement_fromEngine(engineElement); + protocol.Occurrences occurrences = + new protocol.Occurrences(serverElement, offsets, length); + collector.addOccurrences(occurrences); + }); + } + } + } +} + +class _DartUnitOccurrencesComputerVisitor extends RecursiveAstVisitor { + final Map> elementsOffsets = >{}; + + @override + visitSimpleIdentifier(SimpleIdentifier node) { + Element element = node.bestElement; + if (element != null) { + _addOccurrence(element, node.offset); + } + return super.visitSimpleIdentifier(node); + } + + void _addOccurrence(Element element, int offset) { + element = _canonicalizeElement(element); + if (element == null || element == DynamicElementImpl.instance) { + return; + } + List offsets = elementsOffsets[element]; + if (offsets == null) { + offsets = []; + elementsOffsets[element] = offsets; + } + offsets.add(offset); + } + + Element _canonicalizeElement(Element element) { + if (element is FieldFormalParameterElement) { + element = (element as FieldFormalParameterElement).field; + } + if (element is PropertyAccessorElement) { + element = (element as PropertyAccessorElement).variable; + } + if (element is Member) { + element = (element as Member).baseElement; + } + return element; + } +} diff --git a/pkg/analysis_server/lib/src/operation/operation_analysis.dart b/pkg/analysis_server/lib/src/operation/operation_analysis.dart index 5cc1dadff80..0270b273fea 100644 --- a/pkg/analysis_server/lib/src/operation/operation_analysis.dart +++ b/pkg/analysis_server/lib/src/operation/operation_analysis.dart @@ -7,10 +7,10 @@ library operation.analysis; import 'package:analysis_server/src/analysis_server.dart'; import 'package:analysis_server/src/computer/computer_highlights.dart'; import 'package:analysis_server/src/computer/computer_highlights2.dart'; -import 'package:analysis_server/src/computer/computer_occurrences.dart'; import 'package:analysis_server/src/computer/computer_outline.dart'; import 'package:analysis_server/src/computer/computer_overrides.dart'; import 'package:analysis_server/src/domains/analysis/navigation.dart'; +import 'package:analysis_server/src/domains/analysis/occurrences.dart'; import 'package:analysis_server/src/operation/operation.dart'; import 'package:analysis_server/src/protocol_server.dart' as protocol; import 'package:analysis_server/src/services/dependencies/library_dependencies.dart'; @@ -82,8 +82,8 @@ void scheduleNotificationOperations( } if (server.hasAnalysisSubscription( protocol.AnalysisService.OCCURRENCES, file)) { - server.scheduleOperation( - new _DartOccurrencesOperation(context, file, resolvedDartUnit)); + Source source = resolvedDartUnit.element.source; + server.scheduleOperation(new OccurrencesOperation(context, source)); } if (server.hasAnalysisSubscription( protocol.AnalysisService.OVERRIDES, file)) { @@ -179,10 +179,13 @@ void sendAnalysisNotificationNavigation( } void sendAnalysisNotificationOccurrences( - AnalysisServer server, String file, CompilationUnit dartUnit) { + AnalysisServer server, AnalysisContext context, Source source) { _sendNotification(server, () { - var occurrences = new DartUnitOccurrencesComputer(dartUnit).compute(); - var params = new protocol.AnalysisOccurrencesParams(file, occurrences); + OccurrencesCollectorImpl collector = + computeOccurrences(server, context, source); + String file = source.fullName; + var params = + new protocol.AnalysisOccurrencesParams(file, collector.allOccurrences); server.sendNotification(params.toNotification()); }); } @@ -234,17 +237,35 @@ class NavigationOperation extends _NotificationOperation NavigationOperation(AnalysisContext context, Source source) : super(context, source); - @override - void perform(AnalysisServer server) { - sendAnalysisNotificationNavigation(server, context, source); - } - @override bool merge(ServerOperation other) { return other is NavigationOperation && other.context == context && other.source == source; } + + @override + void perform(AnalysisServer server) { + sendAnalysisNotificationNavigation(server, context, source); + } +} + +class OccurrencesOperation extends _NotificationOperation + implements MergeableOperation { + OccurrencesOperation(AnalysisContext context, Source source) + : super(context, source); + + @override + bool merge(ServerOperation other) { + return other is OccurrencesOperation && + other.context == context && + other.source == source; + } + + @override + void perform(AnalysisServer server) { + sendAnalysisNotificationOccurrences(server, context, source); + } } /** @@ -410,17 +431,6 @@ abstract class _DartNotificationOperation extends _SingleFileOperation { } } -class _DartOccurrencesOperation extends _DartNotificationOperation { - _DartOccurrencesOperation( - AnalysisContext context, String file, CompilationUnit unit) - : super(context, file, unit); - - @override - void perform(AnalysisServer server) { - sendAnalysisNotificationOccurrences(server, file, unit); - } -} - class _DartOutlineOperation extends _DartNotificationOperation { final LineInfo lineInfo; diff --git a/pkg/analysis_server/lib/src/plugin/server_plugin.dart b/pkg/analysis_server/lib/src/plugin/server_plugin.dart index c1deee025ca..14b8c33e5b7 100644 --- a/pkg/analysis_server/lib/src/plugin/server_plugin.dart +++ b/pkg/analysis_server/lib/src/plugin/server_plugin.dart @@ -6,7 +6,8 @@ library analysis_server.src.plugin.server_plugin; import 'package:analysis_server/analysis/analysis_domain.dart'; import 'package:analysis_server/analysis/index/index_core.dart'; -import 'package:analysis_server/analysis/navigation/navigation_core.dart'; +import 'package:analysis_server/analysis/navigation_core.dart'; +import 'package:analysis_server/analysis/occurrences_core.dart'; import 'package:analysis_server/completion/completion_core.dart'; import 'package:analysis_server/edit/assist/assist_core.dart'; import 'package:analysis_server/edit/fix/fix_core.dart'; @@ -14,12 +15,14 @@ import 'package:analysis_server/plugin/analyzed_files.dart'; import 'package:analysis_server/plugin/assist.dart'; import 'package:analysis_server/plugin/fix.dart'; import 'package:analysis_server/plugin/navigation.dart'; +import 'package:analysis_server/plugin/occurrences.dart'; import 'package:analysis_server/src/analysis_server.dart'; import 'package:analysis_server/src/domain_analysis.dart'; import 'package:analysis_server/src/domain_completion.dart'; import 'package:analysis_server/src/domain_execution.dart'; import 'package:analysis_server/src/domain_server.dart'; import 'package:analysis_server/src/domains/analysis/navigation_dart.dart'; +import 'package:analysis_server/src/domains/analysis/occurrences_dart.dart'; import 'package:analysis_server/src/edit/edit_domain.dart'; import 'package:analysis_server/src/protocol.dart'; import 'package:analysis_server/src/search/search_domain.dart'; @@ -84,6 +87,13 @@ class ServerPlugin implements Plugin { static const String NAVIGATION_CONTRIBUTOR_EXTENSION_POINT = 'navigationContributor'; + /** + * The simple identifier of the extension point that allows plugins to + * register element occurrences. + */ + static const String OCCURRENCES_CONTRIBUTOR_EXTENSION_POINT = + 'occurrencesContributor'; + /** * The simple identifier of the extension point that allows plugins to * register analysis result listeners. @@ -130,10 +140,17 @@ class ServerPlugin implements Plugin { ExtensionPoint indexContributorExtensionPoint; /** - * The extension point that allows plugins to register navigation contributors. + * The extension point that allows plugins to register navigation + * contributors. */ ExtensionPoint navigationContributorExtensionPoint; + /** + * The extension point that allows plugins to register occurrences + * contributors. + */ + ExtensionPoint occurrencesContributorExtensionPoint; + /** * The extension point that allows plugins to get access to the `analysis` * domain. @@ -186,6 +203,13 @@ class ServerPlugin implements Plugin { List get navigationContributors => navigationContributorExtensionPoint.extensions; + /** + * Return a list containing all of the occurrences contributors that were + * contributed. + */ + List get occurrencesContributors => + occurrencesContributorExtensionPoint.extensions; + /** * Return a list containing all of the receivers of the `analysis` domain * instance. @@ -231,6 +255,9 @@ class ServerPlugin implements Plugin { navigationContributorExtensionPoint = registerExtensionPoint( NAVIGATION_CONTRIBUTOR_EXTENSION_POINT, _validateNavigationContributorExtension); + occurrencesContributorExtensionPoint = registerExtensionPoint( + OCCURRENCES_CONTRIBUTOR_EXTENSION_POINT, + _validateOccurrencesContributorExtension); } @override @@ -253,10 +280,12 @@ class ServerPlugin implements Plugin { // TODO(brianwilkerson) Register the completion contributors. // registerExtension(COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID, ???); // - // Register navigation contributors. + // Register analysis contributors. // registerExtension(NAVIGATION_CONTRIBUTOR_EXTENSION_POINT_ID, new DartNavigationComputer()); + registerExtension(OCCURRENCES_CONTRIBUTOR_EXTENSION_POINT_ID, + new DartOccurrencesComputer()); // // Register domains. // @@ -367,6 +396,18 @@ class ServerPlugin implements Plugin { } } + /** + * Validate the given extension by throwing an [ExtensionError] if it is not a + * valid occurrences contributor. + */ + void _validateOccurrencesContributorExtension(Object extension) { + if (extension is! OccurrencesContributor) { + String id = occurrencesContributorExtensionPoint.uniqueIdentifier; + throw new ExtensionError( + 'Extensions to $id must be an OccurrencesContributor'); + } + } + /** * Validate the given extension by throwing an [ExtensionError] if it is not a * valid analysis domain receiver. diff --git a/pkg/analysis_server/test/plugin/set_analysis_domain_test.dart b/pkg/analysis_server/test/plugin/set_analysis_domain_test.dart index ba2488201af..a6ee01f9499 100644 --- a/pkg/analysis_server/test/plugin/set_analysis_domain_test.dart +++ b/pkg/analysis_server/test/plugin/set_analysis_domain_test.dart @@ -7,8 +7,10 @@ library test.plugin.analysis_contributor; import 'dart:async'; import 'package:analysis_server/analysis/analysis_domain.dart'; -import 'package:analysis_server/analysis/navigation/navigation_core.dart'; +import 'package:analysis_server/analysis/navigation_core.dart'; +import 'package:analysis_server/analysis/occurrences_core.dart'; import 'package:analysis_server/plugin/navigation.dart'; +import 'package:analysis_server/plugin/occurrences.dart'; import 'package:analysis_server/src/constants.dart'; import 'package:analysis_server/src/protocol.dart'; import 'package:analyzer/src/generated/engine.dart'; @@ -38,9 +40,8 @@ main() { class SetAnalysisDomainTest extends AbstractAnalysisTest { final Set parsedUnitFiles = new Set(); - List regions; - List targets; - List targetFiles; + AnalysisNavigationParams navigationParams; + AnalysisOccurrencesParams occurrencesParams; @override void addServerPlugins(List plugins) { @@ -53,9 +54,13 @@ class SetAnalysisDomainTest extends AbstractAnalysisTest { if (notification.event == ANALYSIS_NAVIGATION) { var params = new AnalysisNavigationParams.fromNotification(notification); if (params.file == testFile) { - regions = params.regions; - targets = params.targets; - targetFiles = params.files; + navigationParams = params; + } + } + if (notification.event == ANALYSIS_OCCURRENCES) { + var params = new AnalysisOccurrencesParams.fromNotification(notification); + if (params.file == testFile) { + occurrencesParams = params; } } } @@ -63,27 +68,38 @@ class SetAnalysisDomainTest extends AbstractAnalysisTest { Future test_contributorIsInvoked() async { createProject(); addAnalysisSubscription(AnalysisService.NAVIGATION, testFile); + addAnalysisSubscription(AnalysisService.OCCURRENCES, testFile); addTestFile('// usually no navigation'); await server.onAnalysisComplete; // we have PARSED_UNIT expect(parsedUnitFiles, contains(testFile)); // we have an additional navigation region/target - expect(regions, hasLength(1)); { - NavigationRegion region = regions.single; - expect(region.offset, 1); - expect(region.length, 5); - expect(region.targets.single, 0); + expect(navigationParams.regions, hasLength(1)); + { + NavigationRegion region = navigationParams.regions.single; + expect(region.offset, 1); + expect(region.length, 5); + expect(region.targets.single, 0); + } + { + NavigationTarget target = navigationParams.targets.single; + expect(target.fileIndex, 0); + expect(target.offset, 1); + expect(target.length, 2); + expect(target.startLine, 3); + expect(target.startColumn, 4); + } + expect(navigationParams.files.single, '/testLocation.dart'); } + // we have additional occurrences { - NavigationTarget target = targets.single; - expect(target.fileIndex, 0); - expect(target.offset, 1); - expect(target.length, 2); - expect(target.startLine, 3); - expect(target.startColumn, 4); + expect(occurrencesParams.occurrences, hasLength(1)); + Occurrences occurrences = occurrencesParams.occurrences.single; + expect(occurrences.element.name, 'TestElement'); + expect(occurrences.length, 5); + expect(occurrences.offsets, unorderedEquals([1, 2, 3])); } - expect(targetFiles.single, '/testLocation.dart'); } } @@ -100,6 +116,19 @@ class TestNavigationContributor implements NavigationContributor { } } +class TestOccurrencesContributor implements OccurrencesContributor { + final SetAnalysisDomainTest test; + + TestOccurrencesContributor(this.test); + + @override + void computeOccurrences( + OccurrencesCollector collector, AnalysisContext context, Source source) { + collector.addOccurrences(new Occurrences( + new Element(ElementKind.UNKNOWN, 'TestElement', 0), [1, 2, 3], 5)); + } +} + class TestSetAnalysisDomainPlugin implements Plugin { final SetAnalysisDomainTest test; @@ -116,6 +145,8 @@ class TestSetAnalysisDomainPlugin implements Plugin { register(SET_ANALYSIS_DOMAIN_EXTENSION_POINT_ID, _setAnalysisDomain); register(NAVIGATION_CONTRIBUTOR_EXTENSION_POINT_ID, new TestNavigationContributor(test)); + register(OCCURRENCES_CONTRIBUTOR_EXTENSION_POINT_ID, + new TestOccurrencesContributor(test)); } void _setAnalysisDomain(AnalysisDomain domain) { @@ -127,6 +158,8 @@ class TestSetAnalysisDomainPlugin implements Plugin { test.parsedUnitFiles.add(source.fullName); domain.scheduleNotification( result.context, source, AnalysisService.NAVIGATION); + domain.scheduleNotification( + result.context, source, AnalysisService.OCCURRENCES); }); } }