blob: 23709a33b0a48f762e96e95febff161b3355dd29 [file] [log] [blame]
// Copyright (c) 2017, 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.
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/generated/source.dart' show SourceRange;
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/utilities/navigation/navigation.dart';
import 'package:analyzer_plugin/utilities/pair.dart';
/// A concrete implementation of [DartNavigationRequest].
class DartNavigationRequestImpl implements DartNavigationRequest {
@override
final ResourceProvider resourceProvider;
@override
final int length;
@override
final int offset;
@override
final ResolvedUnitResult result;
/// Initialize a newly create request with the given data.
DartNavigationRequestImpl(
this.resourceProvider, this.offset, this.length, this.result);
@override
String get path => result.path;
}
/// A concrete implementation of [NavigationCollector].
class NavigationCollectorImpl implements NavigationCollector {
/// Whether the collector is collecting target code locations. Computers can
/// skip computing these if this is false.
@override
final bool collectCodeLocations;
/// A list of navigation regions.
final List<NavigationRegion> regions = <NavigationRegion>[];
final Map<SourceRange, List<int>> regionMap = <SourceRange, List<int>>{};
/// All the unique targets referenced by [regions].
final List<NavigationTarget> targets = <NavigationTarget>[];
final Map<Pair<ElementKind, Location>, int> targetMap =
<Pair<ElementKind, Location>, int>{};
/// All the unique files referenced by [targets].
final List<String> files = <String>[];
final Map<String, int> fileMap = <String, int>{};
NavigationCollectorImpl({this.collectCodeLocations = false});
@override
void addRange(
SourceRange range, ElementKind targetKind, Location targetLocation,
{Location? targetCodeLocation}) {
addRegion(range.offset, range.length, targetKind, targetLocation,
targetCodeLocation: targetCodeLocation);
}
@override
void addRegion(
int offset, int length, ElementKind targetKind, Location targetLocation,
{Location? targetCodeLocation}) {
var range = SourceRange(offset, length);
// add new target
var targets = regionMap.putIfAbsent(range, () => <int>[]);
var targetIndex =
_addTarget(targetKind, targetLocation, targetCodeLocation);
targets.add(targetIndex);
}
void createRegions() {
regionMap.forEach((range, targets) {
var region = NavigationRegion(range.offset, range.length, targets);
regions.add(region);
});
regions.sort((NavigationRegion first, NavigationRegion second) {
return first.offset - second.offset;
});
}
int _addFile(String file) {
var index = fileMap[file];
if (index == null) {
index = files.length;
files.add(file);
fileMap[file] = index;
}
return index;
}
int _addTarget(ElementKind kind, Location location, Location? codeLocation) {
var pair = Pair<ElementKind, Location>(kind, location);
var index = targetMap[pair];
if (index == null) {
var file = location.file;
var fileIndex = _addFile(file);
index = targets.length;
var target = NavigationTarget(kind, fileIndex, location.offset,
location.length, location.startLine, location.startColumn,
codeOffset: collectCodeLocations ? codeLocation?.offset : null,
codeLength: collectCodeLocations ? codeLocation?.length : null);
targets.add(target);
targetMap[pair] = index;
}
return index;
}
}