Skip to content

Commit 76623a6

Browse files
DanTupCommit Queue
authored andcommitted
[analysis_server] Extract TypeHierarchyItemLocation as ElementLocation2 and use for completion resolution
This moves completion resolution off `ElementLocation` onto the class recently created as `TypeHierarchyItemLocation`, which is now renamed to `ElementLocation2` and extracted to its own file. Change-Id: I1f0b831ded7b08d6c09f97fcfd66f38f1dd4750e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/401021 Reviewed-by: Konstantin Shcheglov <[email protected]> Commit-Queue: Brian Wilkerson <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]>
1 parent 466fa55 commit 76623a6

File tree

7 files changed

+201
-122
lines changed

7 files changed

+201
-122
lines changed

pkg/analysis_server/lib/src/computer/computer_lazy_type_hierarchy.dart

Lines changed: 76 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,14 @@
66
library;
77

88
import 'package:analysis_server/src/services/search/search_engine.dart';
9+
import 'package:analysis_server/src/utilities/element_location2.dart';
910
import 'package:analyzer/dart/analysis/results.dart';
10-
import 'package:analyzer/dart/analysis/session.dart';
1111
import 'package:analyzer/dart/ast/ast.dart';
1212
import 'package:analyzer/dart/element/element2.dart';
1313
import 'package:analyzer/dart/element/type.dart';
1414
import 'package:analyzer/source/source_range.dart';
1515
import 'package:analyzer/src/dart/element/element.dart';
1616
import 'package:analyzer/src/utilities/extensions/ast.dart';
17-
import 'package:collection/collection.dart';
1817

1918
/// A lazy computer for Type Hierarchies.
2019
///
@@ -36,9 +35,9 @@ class DartLazyTypeHierarchyComputer {
3635

3736
DartLazyTypeHierarchyComputer(this._result);
3837

39-
/// Finds subtypes for [Element] at [location].
38+
/// Finds subtypes for the [Element2] at [location].
4039
Future<List<TypeHierarchyRelatedItem>?> findSubtypes(
41-
TypeHierarchyItemLocation location,
40+
ElementLocation2 location,
4241
SearchEngine searchEngine,
4342
) async {
4443
var targetElement = await _findTargetElement(location);
@@ -49,7 +48,7 @@ class DartLazyTypeHierarchyComputer {
4948
return _getSubtypes(targetElement, searchEngine);
5049
}
5150

52-
/// Finds supertypes for the [Element] at [location].
51+
/// Finds supertypes for the [Element2] at [location].
5352
///
5453
/// If [anchor] is provided, it will be used to navigate to the element at
5554
/// [location] to preserve type arguments that have been provided along the
@@ -58,7 +57,7 @@ class DartLazyTypeHierarchyComputer {
5857
/// Anchors are included in returned types (where necessary to preserve type
5958
/// arguments) that can be used when calling for the next level of types.
6059
Future<List<TypeHierarchyRelatedItem>?> findSupertypes(
61-
TypeHierarchyItemLocation location, {
60+
ElementLocation2 location, {
6261
TypeHierarchyAnchor? anchor,
6362
}) async {
6463
var targetElement = await _findTargetElement(location);
@@ -105,11 +104,11 @@ class DartLazyTypeHierarchyComputer {
105104
return type is InterfaceType ? TypeHierarchyItem.forType(type) : null;
106105
}
107106

108-
/// Locate the [Element] referenced by [location].
107+
/// Locate the [Element2] referenced by [location].
109108
Future<InterfaceElement2?> _findTargetElement(
110-
TypeHierarchyItemLocation location,
109+
ElementLocation2 location,
111110
) async {
112-
var element = await location._locateIn(_result.session);
111+
var element = await location.locateIn(_result.session);
113112
return element is InterfaceElement2 ? element : null;
114113
}
115114

@@ -119,7 +118,7 @@ class DartLazyTypeHierarchyComputer {
119118
SearchEngine searchEngine,
120119
) async {
121120
/// Helper to convert a [SearchMatch] to a [TypeHierarchyRelatedItem].
122-
TypeHierarchyRelatedItem toHierarchyItem(SearchMatch match) {
121+
TypeHierarchyRelatedItem? toHierarchyItem(SearchMatch match) {
123122
var element = match.element2 as InterfaceElement2;
124123
var type = element.thisType;
125124
switch (match.kind) {
@@ -145,6 +144,7 @@ class DartLazyTypeHierarchyComputer {
145144
return matches
146145
.where((match) => seenElements.add(match.element2))
147146
.map(toHierarchyItem)
147+
.nonNulls
148148
.toList();
149149
}
150150

@@ -162,12 +162,13 @@ class DartLazyTypeHierarchyComputer {
162162
var mixins = type.mixins;
163163
var superclassConstraints = type.superclassConstraints;
164164

165-
var supertypes = [
166-
if (supertype != null) TypeHierarchyRelatedItem.extends_(supertype),
167-
...superclassConstraints.map(TypeHierarchyRelatedItem.constrainedTo),
168-
...interfaces.map(TypeHierarchyRelatedItem.implements),
169-
...mixins.map(TypeHierarchyRelatedItem.mixesIn),
170-
];
165+
var supertypes =
166+
[
167+
if (supertype != null) TypeHierarchyRelatedItem.extends_(supertype),
168+
...superclassConstraints.map(TypeHierarchyRelatedItem.constrainedTo),
169+
...interfaces.map(TypeHierarchyRelatedItem.implements),
170+
...mixins.map(TypeHierarchyRelatedItem.mixesIn),
171+
].nonNulls.toList();
171172

172173
if (anchor != null) {
173174
for (var (index, item) in supertypes.indexed) {
@@ -219,7 +220,7 @@ class DartLazyTypeHierarchyComputer {
219220

220221
class TypeHierarchyAnchor {
221222
/// The location of the anchor element.
222-
final TypeHierarchyItemLocation location;
223+
final ElementLocation2 location;
223224

224225
/// The supertype path from [location] to the target element.
225226
final List<int> path;
@@ -238,7 +239,7 @@ class TypeHierarchyItem {
238239
/// `findSubtypes`/`findSupertypes` so that if code has been modified since
239240
/// the `findTarget` call the element can still be located (provided the
240241
/// names/identifiers have not changed).
241-
final TypeHierarchyItemLocation location;
242+
final ElementLocation2 location;
242243

243244
/// The type being displayed.
244245
final InterfaceType _type;
@@ -261,15 +262,21 @@ class TypeHierarchyItem {
261262
required this.codeRange,
262263
}) : _type = type;
263264

264-
TypeHierarchyItem.forType(InterfaceType type)
265-
: this(
266-
type: type,
267-
displayName: _displayNameForType(type),
268-
location: TypeHierarchyItemLocation.forElement(type.element3),
269-
nameRange: _nameRangeForElement(type.element3),
270-
codeRange: _codeRangeForElement(type.element3),
271-
file: type.element3.firstFragment.libraryFragment.source.fullName,
272-
);
265+
TypeHierarchyItem._forType({
266+
required InterfaceType type,
267+
required this.location,
268+
}) : _type = type,
269+
displayName = _displayNameForType(type),
270+
nameRange = _nameRangeForElement(type.element3),
271+
codeRange = _codeRangeForElement(type.element3),
272+
file = type.element3.firstFragment.libraryFragment.source.fullName;
273+
274+
static TypeHierarchyItem? forType(InterfaceType type) {
275+
var location = ElementLocation2.forElement(type.element3);
276+
if (location == null) return null;
277+
278+
return TypeHierarchyItem._forType(type: type, location: location);
279+
}
273280

274281
/// Returns the [SourceRange] of the code for [element].
275282
static SourceRange _codeRangeForElement(Element2 element) {
@@ -296,58 +303,6 @@ class TypeHierarchyItem {
296303
}
297304
}
298305

299-
/// Represents the location of an item that can appear in Type Hierarchy that
300-
/// can be encoded to/from a [String] for round-tripping to the client.
301-
class TypeHierarchyItemLocation {
302-
/// The URI of the Library that contains this type.
303-
final String _libraryUri;
304-
305-
/// The [Element2.name3] for this type.
306-
final String _name;
307-
308-
factory TypeHierarchyItemLocation.decode(String encoded) {
309-
var parts = encoded.split(';');
310-
if (parts.length != 2) {
311-
throw ArgumentError(
312-
"Encoded string should be in format 'libraryUri;name' encoded",
313-
);
314-
}
315-
return TypeHierarchyItemLocation._(libraryUri: parts[0], name: parts[1]);
316-
}
317-
318-
factory TypeHierarchyItemLocation.forElement(InterfaceElement2 element) {
319-
var name = element.name3;
320-
321-
if (name == null) {
322-
throw ArgumentError(
323-
'Cannot create TypeHierarchyItemLocation for an element with no name: $element',
324-
);
325-
}
326-
327-
return TypeHierarchyItemLocation._(
328-
libraryUri: element.library2.uri.toString(),
329-
name: name,
330-
);
331-
}
332-
333-
TypeHierarchyItemLocation._({
334-
required String libraryUri,
335-
required String name,
336-
}) : _name = name,
337-
_libraryUri = libraryUri;
338-
339-
String get encoding => '$_libraryUri;$_name';
340-
341-
Future<InterfaceElement2?> _locateIn(AnalysisSession session) async {
342-
var result = await session.getLibraryByUri(_libraryUri);
343-
return result is LibraryElementResult
344-
? result.element2.children2
345-
.whereType<InterfaceElement2>()
346-
.firstWhereOrNull((element2) => element2.name3 == _name)
347-
: null;
348-
}
349-
}
350-
351306
enum TypeHierarchyItemRelationship {
352307
unknown,
353308
implements,
@@ -363,29 +318,51 @@ class TypeHierarchyRelatedItem extends TypeHierarchyItem {
363318

364319
TypeHierarchyAnchor? _anchor;
365320

366-
TypeHierarchyRelatedItem.constrainedTo(InterfaceType type)
367-
: this._forType(
368-
type,
369-
relationship: TypeHierarchyItemRelationship.constrainedTo,
370-
);
371-
TypeHierarchyRelatedItem.extends_(InterfaceType type)
372-
: this._forType(type, relationship: TypeHierarchyItemRelationship.extends_);
321+
TypeHierarchyRelatedItem({
322+
required super.type,
323+
required this.relationship,
324+
required super.displayName,
325+
required super.location,
326+
required super.file,
327+
required super.nameRange,
328+
required super.codeRange,
329+
});
330+
331+
TypeHierarchyRelatedItem.forType({
332+
required super.type,
333+
required this.relationship,
334+
required super.location,
335+
}) : super._forType();
373336

374-
TypeHierarchyRelatedItem.implements(InterfaceType type)
375-
: this._forType(
376-
type,
377-
relationship: TypeHierarchyItemRelationship.implements,
378-
);
337+
/// An optional anchor element used to preserve type args.
338+
TypeHierarchyAnchor? get anchor => _anchor;
379339

380-
TypeHierarchyRelatedItem.mixesIn(InterfaceType type)
381-
: this._forType(type, relationship: TypeHierarchyItemRelationship.mixesIn);
340+
static TypeHierarchyRelatedItem? constrainedTo(InterfaceType type) =>
341+
_forType(type, relationship: TypeHierarchyItemRelationship.constrainedTo);
382342

383-
TypeHierarchyRelatedItem.unknown(InterfaceType type)
384-
: this._forType(type, relationship: TypeHierarchyItemRelationship.unknown);
343+
static TypeHierarchyRelatedItem? extends_(InterfaceType type) =>
344+
_forType(type, relationship: TypeHierarchyItemRelationship.extends_);
385345

386-
TypeHierarchyRelatedItem._forType(super.type, {required this.relationship})
387-
: super.forType();
346+
static TypeHierarchyRelatedItem? implements(InterfaceType type) =>
347+
_forType(type, relationship: TypeHierarchyItemRelationship.implements);
388348

389-
/// An optional anchor element used to preserve type args.
390-
TypeHierarchyAnchor? get anchor => _anchor;
349+
static TypeHierarchyRelatedItem? mixesIn(InterfaceType type) =>
350+
_forType(type, relationship: TypeHierarchyItemRelationship.mixesIn);
351+
352+
static TypeHierarchyRelatedItem? unknown(InterfaceType type) =>
353+
_forType(type, relationship: TypeHierarchyItemRelationship.unknown);
354+
355+
static TypeHierarchyRelatedItem? _forType(
356+
InterfaceType type, {
357+
required TypeHierarchyItemRelationship relationship,
358+
}) {
359+
var location = ElementLocation2.forElement(type.element3);
360+
if (location == null) return null;
361+
362+
return TypeHierarchyRelatedItem.forType(
363+
type: type,
364+
relationship: relationship,
365+
location: location,
366+
);
367+
}
391368
}

pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ import 'package:analysis_server/src/services/completion/yaml/pubspec_generator.d
2323
import 'package:analysis_server/src/services/completion/yaml/yaml_completion_generator.dart';
2424
import 'package:analysis_server/src/services/snippets/dart_snippet_request.dart';
2525
import 'package:analysis_server/src/services/snippets/snippet_manager.dart';
26+
import 'package:analysis_server/src/utilities/element_location2.dart';
2627
import 'package:analyzer/dart/analysis/results.dart';
2728
import 'package:analyzer/dart/analysis/session.dart';
2829
import 'package:analyzer/dart/ast/ast.dart' as ast;
2930
import 'package:analyzer/source/line_info.dart';
3031
import 'package:analyzer/src/util/file_paths.dart' as file_paths;
3132
import 'package:analyzer/src/util/performance/operation_performance.dart';
32-
import 'package:analyzer/src/utilities/extensions/element.dart';
3333
import 'package:analyzer/src/utilities/fuzzy_matcher.dart';
3434
import 'package:analyzer_plugin/protocol/protocol_common.dart';
3535
import 'package:analyzer_plugin/src/utilities/completion/completion_target.dart';
@@ -478,27 +478,26 @@ class CompletionHandler
478478
CompletionItemResolutionInfo? resolutionInfo;
479479

480480
if (item is ElementBasedSuggestion && item is ImportableSuggestion) {
481-
var elementLocation =
482-
(item as ElementBasedSuggestion).element.asElement!.location;
483-
var importUri = item.importData?.libraryUri;
481+
var element = (item as ElementBasedSuggestion).element;
484482

483+
var importUri = item.importData?.libraryUri;
485484
if (importUri != null) {
486485
resolutionInfo = DartCompletionResolutionInfo(
487486
file: unit.path,
488487
importUris: [importUri.toString()],
489-
ref: elementLocation?.encoding,
488+
ref: ElementLocation2.forElement(element)?.encoding,
490489
);
491490
}
492491
} else if (item is OverrideSuggestion) {
493492
var overrideData = item.data;
494493
if (overrideData != null && overrideData.imports.isNotEmpty) {
495-
var elementLocation =
496-
(item as ElementBasedSuggestion).element.location;
494+
var element = (item as ElementBasedSuggestion).element;
495+
497496
var importUris = overrideData.imports;
498497
resolutionInfo = DartCompletionResolutionInfo(
499498
file: unit.path,
500499
importUris: importUris.map((uri) => uri.toString()).toList(),
501-
ref: elementLocation?.encoding,
500+
ref: ElementLocation2.forElement(element)?.encoding,
502501
);
503502
}
504503
}

pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,9 @@ import 'package:analysis_server/src/lsp/constants.dart';
99
import 'package:analysis_server/src/lsp/error_or.dart';
1010
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
1111
import 'package:analysis_server/src/lsp/mapping.dart';
12+
import 'package:analysis_server/src/utilities/element_location2.dart';
1213
import 'package:analyzer/dart/analysis/results.dart';
1314
import 'package:analyzer/dart/analysis/session.dart';
14-
import 'package:analyzer/src/dart/element/element.dart';
15-
import 'package:analyzer/src/utilities/extensions/analysis_session.dart';
16-
import 'package:analyzer/src/utilities/extensions/element.dart';
1715
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
1816

1917
class CompletionResolveHandler
@@ -63,11 +61,7 @@ class CompletionResolveHandler
6361
) async {
6462
var file = data.file;
6563
var importUris = data.importUris.map(Uri.parse).toList();
66-
var elementLocationReference = data.ref;
67-
var elementLocation =
68-
elementLocationReference != null
69-
? ElementLocationImpl.con2(elementLocationReference)
70-
: null;
64+
var elementReference = data.ref;
7165

7266
const timeout = Duration(milliseconds: 1000);
7367
var timer = Stopwatch()..start();
@@ -130,8 +124,10 @@ class CompletionResolveHandler
130124
// Look up documentation if we can get an element for this item.
131125
Either2<MarkupContent, String>? documentation;
132126
var element =
133-
elementLocation != null
134-
? (await session.locateElement(elementLocation)).asElement2
127+
elementReference != null
128+
? await ElementLocation2.decode(
129+
elementReference,
130+
).locateIn(session)
135131
: null;
136132
if (element != null) {
137133
var formats = clientCapabilities.completionDocumentationFormats;

0 commit comments

Comments
 (0)