blob: 73f8b73b65969fb14460ea0bbc15dcf686ac3e99 [file] [log] [blame]
// 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;
import 'dart:collection';
import 'package:analysis_server/plugin/analysis/navigation/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;
import 'package:analyzer/exception/exception.dart';
import 'package:analyzer/src/generated/engine.dart'
show AnalysisContext, AnalysisEngine;
import 'package:analyzer/src/generated/source.dart' show Source, SourceRange;
/**
* Compute all known navigation information for the given part of [source].
*/
NavigationCollectorImpl computeNavigation(AnalysisServer server,
AnalysisContext context, Source source, int offset, int length) {
NavigationCollectorImpl collector = new NavigationCollectorImpl();
List<NavigationContributor> contributors =
server.serverPlugin.navigationContributors;
for (NavigationContributor contributor in contributors) {
try {
contributor.computeNavigation(collector, context, source, offset, length);
} catch (exception, stackTrace) {
AnalysisEngine.instance.logger.logError(
'Exception from navigation contributor: ${contributor.runtimeType}',
new CaughtException(exception, stackTrace));
}
}
collector.createRegions();
return collector;
}
/**
* A concrete implementation of [NavigationCollector].
*/
class NavigationCollectorImpl implements NavigationCollector {
/**
* A list of navigation regions.
*/
final List<protocol.NavigationRegion> regions = <protocol.NavigationRegion>[];
final Map<SourceRange, List<int>> regionMap =
new HashMap<SourceRange, List<int>>();
/**
* All the unique targets referenced by [regions].
*/
final List<protocol.NavigationTarget> targets = <protocol.NavigationTarget>[];
final Map<Pair<protocol.ElementKind, protocol.Location>, int> targetMap =
new HashMap<Pair<protocol.ElementKind, protocol.Location>, int>();
/**
* All the unique files referenced by [targets].
*/
final List<String> files = <String>[];
final Map<String, int> fileMap = new HashMap<String, int>();
@override
void addRegion(int offset, int length, protocol.ElementKind targetKind,
protocol.Location targetLocation) {
SourceRange range = new SourceRange(offset, length);
// prepare targets
List<int> targets = regionMap[range];
if (targets == null) {
targets = <int>[];
regionMap[range] = targets;
}
// add new target
int targetIndex = _addTarget(targetKind, targetLocation);
targets.add(targetIndex);
}
void createRegions() {
regionMap.forEach((range, targets) {
protocol.NavigationRegion region =
new protocol.NavigationRegion(range.offset, range.length, targets);
regions.add(region);
});
regions.sort((a, b) {
return a.offset - b.offset;
});
}
int _addFile(String file) {
int index = fileMap[file];
if (index == null) {
index = files.length;
files.add(file);
fileMap[file] = index;
}
return index;
}
int _addTarget(protocol.ElementKind kind, protocol.Location location) {
var pair =
new Pair<protocol.ElementKind, protocol.Location>(kind, location);
int index = targetMap[pair];
if (index == null) {
String file = location.file;
int fileIndex = _addFile(file);
index = targets.length;
protocol.NavigationTarget target = new protocol.NavigationTarget(
kind,
fileIndex,
location.offset,
location.length,
location.startLine,
location.startColumn);
targets.add(target);
targetMap[pair] = index;
}
return index;
}
}