Skip to content

Commit 823947b

Browse files
DanTupCommit Queue
authored andcommitted
[analysis_server] Always show type parameters in LSP type hierarchy, not type arguments
The change at 27ba8fc (to fix Dart-Code/Dart-Code#4217) added type arguments to the LSP Type Hierarchy (before, neither type args or type params were shown). Showing type arguments seemed reasonable when looking at supertypes, but behaves oddly for subtypes (and also when invoked on a type with arguments), so this partly reverts that and shows type parameters in all cases instead. This simplified the code a bit and removed the `TypeHierarchyAnchor` class we were round-tripping in order to preserve the type arguments. Fixes #60549 Change-Id: I4e0e92d4c73712fde7a9526c51699ecdae0f4ab1 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/423020 Reviewed-by: Brian Wilkerson <[email protected]> Reviewed-by: Konstantin Shcheglov <[email protected]> Commit-Queue: Brian Wilkerson <[email protected]>
1 parent 5b8b524 commit 823947b

File tree

8 files changed

+68
-330
lines changed

8 files changed

+68
-330
lines changed

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

Lines changed: 49 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -49,36 +49,16 @@ class DartLazyTypeHierarchyComputer {
4949
}
5050

5151
/// Finds supertypes for the [Element2] at [location].
52-
///
53-
/// If [anchor] is provided, it will be used to navigate to the element at
54-
/// [location] to preserve type arguments that have been provided along the
55-
/// way.
56-
///
57-
/// Anchors are included in returned types (where necessary to preserve type
58-
/// arguments) that can be used when calling for the next level of types.
5952
Future<List<TypeHierarchyRelatedItem>?> findSupertypes(
60-
ElementLocation location, {
61-
TypeHierarchyAnchor? anchor,
62-
}) async {
53+
ElementLocation location,
54+
) async {
6355
var targetElement = await _findTargetElement(location);
6456
if (targetElement == null) {
6557
return null;
6658
}
6759
var targetType = targetElement.thisType;
6860

69-
// If we were provided an anchor, use it to re-locate the target type so
70-
// that any type arguments supplied along the way will be preserved in the
71-
// new node.
72-
if (anchor != null) {
73-
targetType =
74-
await _locateTargetFromAnchor(anchor, targetType) ?? targetType;
75-
}
76-
77-
// If we had no existing anchor, create one that starts from this target as
78-
// the starting point for the new supertypes.
79-
anchor ??= TypeHierarchyAnchor(location: location, path: []);
80-
81-
return _getSupertypes(targetType, anchor: anchor);
61+
return _getSupertypes(targetType);
8262
}
8363

8464
/// Finds a target for starting type hierarchy navigation at [offset].
@@ -101,7 +81,9 @@ class DartLazyTypeHierarchyComputer {
10181
}
10282
}
10383

104-
return type is InterfaceType ? TypeHierarchyItem.forType(type) : null;
84+
return type is InterfaceType
85+
? TypeHierarchyItem.forElement(type.element3)
86+
: null;
10587
}
10688

10789
/// Locate the [Element2] referenced by [location].
@@ -153,10 +135,7 @@ class DartLazyTypeHierarchyComputer {
153135
/// Includes all elements that contribute implementation to the type
154136
/// such as supertypes and mixins, but not interfaces, constraints or
155137
/// extended types.
156-
List<TypeHierarchyRelatedItem> _getSupertypes(
157-
InterfaceType type, {
158-
TypeHierarchyAnchor? anchor,
159-
}) {
138+
List<TypeHierarchyRelatedItem> _getSupertypes(InterfaceType type) {
160139
var supertype = type.superclass;
161140
var interfaces = type.interfaces;
162141
var mixins = type.mixins;
@@ -170,19 +149,6 @@ class DartLazyTypeHierarchyComputer {
170149
...mixins.map(TypeHierarchyRelatedItem.mixesIn),
171150
].nonNulls.toList();
172151

173-
if (anchor != null) {
174-
for (var (index, item) in supertypes.indexed) {
175-
// We only need to carry the anchor along if the supertype has type
176-
// arguments that we may be populating.
177-
if (item._type.typeArguments.isNotEmpty) {
178-
item._anchor = TypeHierarchyAnchor(
179-
location: anchor.location,
180-
path: [...anchor.path, index],
181-
);
182-
}
183-
}
184-
}
185-
186152
return supertypes;
187153
}
188154

@@ -193,29 +159,6 @@ class DartLazyTypeHierarchyComputer {
193159
declaration is MixinDeclaration ||
194160
declaration is ExtensionTypeDeclaration ||
195161
declaration is EnumDeclaration;
196-
197-
/// Navigate to [target] from [anchor], preserving type arguments supplied
198-
/// along the way.
199-
Future<InterfaceType?> _locateTargetFromAnchor(
200-
TypeHierarchyAnchor anchor,
201-
InterfaceType target,
202-
) async {
203-
// Start from the anchor.
204-
var anchorElement = await _findTargetElement(anchor.location);
205-
var anchorPath = anchor.path;
206-
207-
// Follow the provided path.
208-
var type = anchorElement?.thisType;
209-
for (int i = 0; i < anchorPath.length && type != null; i++) {
210-
var index = anchorPath[i];
211-
var supertypes = _getSupertypes(type);
212-
type = supertypes.length >= index + 1 ? supertypes[index]._type : null;
213-
}
214-
215-
// Verify the element we arrived at matches the targetElement to guard
216-
// against code changes that made the path from the anchor invalid.
217-
return type != null && type.element3 == target.element3 ? type : null;
218-
}
219162
}
220163

221164
class TypeHierarchyAnchor {
@@ -241,9 +184,6 @@ class TypeHierarchyItem {
241184
/// names/identifiers have not changed).
242185
final ElementLocation location;
243186

244-
/// The type being displayed.
245-
final InterfaceType _type;
246-
247187
/// The file that contains the declaration of this item.
248188
final String file;
249189

@@ -254,28 +194,26 @@ class TypeHierarchyItem {
254194
final SourceRange codeRange;
255195

256196
TypeHierarchyItem({
257-
required InterfaceType type,
258197
required this.displayName,
259198
required this.location,
260199
required this.file,
261200
required this.nameRange,
262201
required this.codeRange,
263-
}) : _type = type;
202+
});
264203

265-
TypeHierarchyItem._forType({
266-
required InterfaceType type,
204+
TypeHierarchyItem._forElement({
205+
required InterfaceElement2 element,
267206
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 = ElementLocation.forElement(type.element3);
207+
}) : displayName = _displayNameForElement(element),
208+
nameRange = _nameRangeForElement(element),
209+
codeRange = _codeRangeForElement(element),
210+
file = element.firstFragment.libraryFragment.source.fullName;
211+
212+
static TypeHierarchyItem? forElement(InterfaceElement2 element) {
213+
var location = ElementLocation.forElement(element);
276214
if (location == null) return null;
277215

278-
return TypeHierarchyItem._forType(type: type, location: location);
216+
return TypeHierarchyItem._forElement(element: element, location: location);
279217
}
280218

281219
/// Returns the [SourceRange] of the code for [element].
@@ -285,9 +223,9 @@ class TypeHierarchyItem {
285223
return SourceRange(firstFragment.codeOffset!, firstFragment.codeLength!);
286224
}
287225

288-
/// Returns a name to display in the hierarchy for [type].
289-
static String _displayNameForType(InterfaceType type) {
290-
return type.getDisplayString();
226+
/// Returns a name to display in the hierarchy for [element].
227+
static String _displayNameForElement(InterfaceElement2 element) {
228+
return element.baseElement.thisType.getDisplayString();
291229
}
292230

293231
/// Returns the [SourceRange] of the name for [element].
@@ -316,51 +254,48 @@ class TypeHierarchyRelatedItem extends TypeHierarchyItem {
316254
/// The relationship this item has with the target item.
317255
final TypeHierarchyItemRelationship relationship;
318256

319-
TypeHierarchyAnchor? _anchor;
320-
321-
TypeHierarchyRelatedItem({
322-
required super.type,
257+
TypeHierarchyRelatedItem.forElement({
258+
required super.element,
323259
required this.relationship,
324-
required super.displayName,
325260
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();
336-
337-
/// An optional anchor element used to preserve type args.
338-
TypeHierarchyAnchor? get anchor => _anchor;
261+
}) : super._forElement();
339262

340263
static TypeHierarchyRelatedItem? constrainedTo(InterfaceType type) =>
341-
_forType(type, relationship: TypeHierarchyItemRelationship.constrainedTo);
264+
_forElement(
265+
type.element3,
266+
relationship: TypeHierarchyItemRelationship.constrainedTo,
267+
);
342268

343-
static TypeHierarchyRelatedItem? extends_(InterfaceType type) =>
344-
_forType(type, relationship: TypeHierarchyItemRelationship.extends_);
269+
static TypeHierarchyRelatedItem? extends_(InterfaceType type) => _forElement(
270+
type.element3,
271+
relationship: TypeHierarchyItemRelationship.extends_,
272+
);
345273

346274
static TypeHierarchyRelatedItem? implements(InterfaceType type) =>
347-
_forType(type, relationship: TypeHierarchyItemRelationship.implements);
275+
_forElement(
276+
type.element3,
277+
relationship: TypeHierarchyItemRelationship.implements,
278+
);
348279

349-
static TypeHierarchyRelatedItem? mixesIn(InterfaceType type) =>
350-
_forType(type, relationship: TypeHierarchyItemRelationship.mixesIn);
280+
static TypeHierarchyRelatedItem? mixesIn(InterfaceType type) => _forElement(
281+
type.element3,
282+
relationship: TypeHierarchyItemRelationship.mixesIn,
283+
);
351284

352-
static TypeHierarchyRelatedItem? unknown(InterfaceType type) =>
353-
_forType(type, relationship: TypeHierarchyItemRelationship.unknown);
285+
static TypeHierarchyRelatedItem? unknown(InterfaceType type) => _forElement(
286+
type.element3,
287+
relationship: TypeHierarchyItemRelationship.unknown,
288+
);
354289

355-
static TypeHierarchyRelatedItem? _forType(
356-
InterfaceType type, {
290+
static TypeHierarchyRelatedItem? _forElement(
291+
InterfaceElement2 element, {
357292
required TypeHierarchyItemRelationship relationship,
358293
}) {
359-
var location = ElementLocation.forElement(type.element3);
294+
var location = ElementLocation.forElement(element);
360295
if (location == null) return null;
361296

362-
return TypeHierarchyRelatedItem.forType(
363-
type: type,
297+
return TypeHierarchyRelatedItem.forElement(
298+
element: element,
364299
relationship: relationship,
365300
location: location,
366301
);

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

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -190,26 +190,11 @@ class TypeHierarchySupertypesHandler
190190
}
191191

192192
var location = ElementLocation.decode(data.ref);
193-
var anchor = _toServerAnchor(data);
194-
var calls = await computer.findSupertypes(location, anchor: anchor);
193+
var calls = await computer.findSupertypes(location);
195194
var results = calls != null ? _convertItems(unit, calls) : null;
196195
return success(results);
197196
});
198197
}
199-
200-
/// Reads the anchor from [data] (if available) and converts it to a server
201-
/// [type_hierarchy.TypeHierarchyAnchor].
202-
type_hierarchy.TypeHierarchyAnchor? _toServerAnchor(
203-
TypeHierarchyItemInfo data,
204-
) {
205-
var anchor = data.anchor;
206-
return anchor != null
207-
? type_hierarchy.TypeHierarchyAnchor(
208-
location: ElementLocation.decode(anchor.ref),
209-
path: anchor.path,
210-
)
211-
: null;
212-
}
213198
}
214199

215200
/// Utility methods used by all Type Hierarchy handlers.
@@ -224,24 +209,13 @@ mixin _TypeHierarchyUtils on HandlerHelperMixin<AnalysisServer> {
224209
type_hierarchy.TypeHierarchyItem item,
225210
LineInfo lineInfo,
226211
) {
227-
var anchor =
228-
item is type_hierarchy.TypeHierarchyRelatedItem ? item.anchor : null;
229212
return TypeHierarchyItem(
230213
name: item.displayName,
231214
kind: SymbolKind.Class,
232215
uri: uriConverter.toClientUri(item.file),
233216
range: sourceRangeToRange(lineInfo, item.codeRange),
234217
selectionRange: sourceRangeToRange(lineInfo, item.nameRange),
235-
data: TypeHierarchyItemInfo(
236-
ref: item.location.encoding,
237-
anchor:
238-
anchor != null
239-
? TypeHierarchyAnchor(
240-
ref: anchor.location.encoding,
241-
path: anchor.path,
242-
)
243-
: null,
244-
),
218+
data: TypeHierarchyItemInfo(ref: item.location.encoding),
245219
);
246220
}
247221

pkg/analysis_server/test/lsp/type_hierarchy_test.dart

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -418,8 +418,8 @@ extension type E^2(A a) implements B, E1 {}
418418
);
419419
}
420420

421-
/// Ensure that type arguments flow across multiple levels of the tree.
422-
Future<void> test_generics_typeArgsFlow() async {
421+
/// Ensure that we always show type parameters and not type arguments.
422+
Future<void> test_generics_typeParameters() async {
423423
var content = '''
424424
class A<T1, T2> {}
425425
class B<T1, T2> extends A<T1, T2> {}
@@ -442,14 +442,7 @@ class ^E extends D {}
442442
}
443443

444444
// Check for substituted type args.
445-
expect(names, [
446-
'E',
447-
'D',
448-
'C<int>',
449-
'B<int, String>',
450-
'A<int, String>',
451-
'Object',
452-
]);
445+
expect(names, ['E', 'D', 'C<T1>', 'B<T1, T2>', 'A<T1, T2>', 'Object']);
453446
}
454447

455448
Future<void> test_implements() async {

0 commit comments

Comments
 (0)