Skip to content

Commit d698ace

Browse files
DanTupCommit Queue
authored and
Commit Queue
committed
[analysis_server] Migrate LSP Go-To handlers to new element model
Change-Id: Ie517dcbba87c34d12a42707c3beea141d3fd509a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/393880 Reviewed-by: Konstantin Shcheglov <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Brian Wilkerson <[email protected]>
1 parent 082c710 commit d698ace

File tree

6 files changed

+195
-71
lines changed

6 files changed

+195
-71
lines changed

pkg/analysis_server/analyzer_use_new_elements.txt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@ lib/src/lsp/handlers/code_actions/dart.dart
2323
lib/src/lsp/handlers/commands/abstract_refactor.dart
2424
lib/src/lsp/handlers/custom/abstract_go_to.dart
2525
lib/src/lsp/handlers/custom/handler_imports.dart
26-
lib/src/lsp/handlers/custom/handler_augmentation.dart
27-
lib/src/lsp/handlers/custom/handler_augmented.dart
28-
lib/src/lsp/handlers/custom/handler_super.dart
2926
lib/src/lsp/handlers/handler_completion.dart
3027
lib/src/lsp/handlers/handler_completion_resolve.dart
3128
lib/src/lsp/handlers/handler_definition.dart

pkg/analysis_server/lib/src/lsp/handlers/custom/abstract_go_to.dart

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,10 @@ import 'package:meta/meta.dart';
1818
/// a location to navigate to a particular kind of related element, such as
1919
/// Super, Augmentation Target or Augmentation.
2020
abstract class AbstractGoToHandler
21-
extends
22-
SharedMessageHandler<
23-
TextDocumentPositionParams,
24-
Either2<Location, List<Location>>?
25-
> {
21+
// TODO(dantup): Remove this class after https://dart-review.googlesource.com/c/sdk/+/393861
22+
// lands.
23+
extends
24+
SharedMessageHandler<TextDocumentPositionParams, Either2<Location, List<Location>>?> {
2625
AbstractGoToHandler(super.server);
2726

2827
@override

pkg/analysis_server/lib/src/lsp/handlers/custom/handler_augmentation.dart

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,54 @@
44

55
import 'package:analysis_server/lsp_protocol/protocol.dart' hide Element;
66
import 'package:analysis_server/src/lsp/constants.dart';
7-
import 'package:analysis_server/src/lsp/handlers/custom/abstract_go_to.dart';
8-
import 'package:analyzer/dart/analysis/results.dart';
9-
import 'package:analyzer/dart/element/element.dart';
10-
import 'package:analyzer/src/utilities/extensions/element.dart';
7+
import 'package:analysis_server/src/lsp/error_or.dart';
8+
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
9+
import 'package:analysis_server/src/lsp/mapping.dart';
10+
import 'package:analyzer/src/dart/ast/ast.dart';
11+
import 'package:analyzer/src/utilities/extensions/ast.dart';
1112

12-
class AugmentationHandler extends AbstractGoToHandler {
13+
class AugmentationHandler
14+
extends SharedMessageHandler<TextDocumentPositionParams, Location?> {
1315
AugmentationHandler(super.server);
1416

1517
@override
1618
Method get handlesMessage => CustomMethods.augmentation;
1719

20+
@override
21+
LspJsonHandler<TextDocumentPositionParams> get jsonHandler =>
22+
TextDocumentPositionParams.jsonHandler;
23+
1824
@override
1925
bool get requiresTrustedCaller => false;
2026

2127
@override
22-
Either2<Location?, List<Location>> findRelatedLocations(
23-
Element element,
24-
ResolvedLibraryResult libraryResult,
25-
ResolvedUnitResult unit,
26-
String? prefix) {
27-
// Although the base class supports returning multiple elements, this
28-
// handler is documented to only return a single element.
29-
// Changing this to return a list could be a breaking change for
30-
// clients.
31-
return Either2.t1(elementToLocation(element.augmentation));
28+
Future<ErrorOr<Location?>> handle(
29+
TextDocumentPositionParams params,
30+
MessageInfo message,
31+
CancellationToken token,
32+
) async {
33+
if (!isDartDocument(params.textDocument)) {
34+
return success(null);
35+
}
36+
37+
var pos = params.position;
38+
var path = pathOfDoc(params.textDocument);
39+
var unit = await path.mapResult(requireResolvedUnit);
40+
var offset = unit.mapResultSync((unit) => toOffset(unit.lineInfo, pos));
41+
42+
return (unit, offset).mapResultsSync((unit, offset) {
43+
// Find the nearest node that could have fragments.
44+
var node =
45+
unit.unit
46+
.nodeCovering(offset: offset)
47+
?.thisOrAncestorOfType<FragmentDeclaration>();
48+
49+
var location = fragmentToLocation(
50+
uriConverter,
51+
// Augmentation = next fragment.
52+
node?.declaredFragment?.nextFragment,
53+
);
54+
return success(location);
55+
});
3256
}
3357
}

pkg/analysis_server/lib/src/lsp/handlers/custom/handler_augmented.dart

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,54 @@
44

55
import 'package:analysis_server/lsp_protocol/protocol.dart' hide Element;
66
import 'package:analysis_server/src/lsp/constants.dart';
7-
import 'package:analysis_server/src/lsp/handlers/custom/abstract_go_to.dart';
8-
import 'package:analyzer/dart/analysis/results.dart';
9-
import 'package:analyzer/dart/element/element.dart';
7+
import 'package:analysis_server/src/lsp/error_or.dart';
8+
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
9+
import 'package:analysis_server/src/lsp/mapping.dart';
10+
import 'package:analyzer/src/dart/ast/ast.dart';
11+
import 'package:analyzer/src/utilities/extensions/ast.dart';
1012

11-
class AugmentedHandler extends AbstractGoToHandler {
13+
class AugmentedHandler
14+
extends SharedMessageHandler<TextDocumentPositionParams, Location?> {
1215
AugmentedHandler(super.server);
1316

1417
@override
1518
Method get handlesMessage => CustomMethods.augmented;
1619

20+
@override
21+
LspJsonHandler<TextDocumentPositionParams> get jsonHandler =>
22+
TextDocumentPositionParams.jsonHandler;
23+
1724
@override
1825
bool get requiresTrustedCaller => false;
1926

2027
@override
21-
Either2<Location?, List<Location>> findRelatedLocations(
22-
Element element,
23-
ResolvedLibraryResult libraryResult,
24-
ResolvedUnitResult unit,
25-
String? prefix) {
26-
// Although the base class supports returning multiple elements, this
27-
// handler is documented to only return a single element.
28-
// Changing this to return a list could be a breaking change for
29-
// clients.
30-
return Either2.t1(elementToLocation(switch (element) {
31-
ExecutableElement element => element.augmentationTarget,
32-
InstanceElement element => element.augmentationTarget,
33-
PropertyInducingElement element => element.augmentationTarget,
34-
_ => null,
35-
}));
28+
Future<ErrorOr<Location?>> handle(
29+
TextDocumentPositionParams params,
30+
MessageInfo message,
31+
CancellationToken token,
32+
) async {
33+
if (!isDartDocument(params.textDocument)) {
34+
return success(null);
35+
}
36+
37+
var pos = params.position;
38+
var path = pathOfDoc(params.textDocument);
39+
var unit = await path.mapResult(requireResolvedUnit);
40+
var offset = unit.mapResultSync((unit) => toOffset(unit.lineInfo, pos));
41+
42+
return (unit, offset).mapResultsSync((unit, offset) {
43+
// Find the nearest node that could have fragments.
44+
var node =
45+
unit.unit
46+
.nodeCovering(offset: offset)
47+
?.thisOrAncestorOfType<FragmentDeclaration>();
48+
49+
var location = fragmentToLocation(
50+
uriConverter,
51+
// Augmented = previous fragment.
52+
node?.declaredFragment?.previousFragment,
53+
);
54+
return success(location);
55+
});
3656
}
3757
}

pkg/analysis_server/lib/src/lsp/handlers/custom/handler_super.dart

Lines changed: 77 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,71 +4,119 @@
44

55
import 'package:analysis_server/lsp_protocol/protocol.dart' hide Element;
66
import 'package:analysis_server/src/lsp/constants.dart';
7-
import 'package:analysis_server/src/lsp/handlers/custom/abstract_go_to.dart';
8-
import 'package:analyzer/dart/analysis/results.dart';
9-
import 'package:analyzer/dart/element/element.dart';
7+
import 'package:analysis_server/src/lsp/error_or.dart';
8+
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
9+
import 'package:analysis_server/src/lsp/mapping.dart';
10+
import 'package:analyzer/dart/ast/ast.dart';
11+
import 'package:analyzer/dart/element/element2.dart';
1012
import 'package:analyzer/src/dart/analysis/session.dart';
13+
import 'package:analyzer/src/dart/ast/element_locator.dart';
1114
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
12-
import 'package:analyzer/src/utilities/extensions/element.dart';
15+
import 'package:analyzer/src/utilities/extensions/ast.dart';
1316

14-
class SuperHandler extends AbstractGoToHandler {
17+
class SuperHandler
18+
extends SharedMessageHandler<TextDocumentPositionParams, Location?> {
1519
SuperHandler(super.server);
1620

1721
@override
1822
Method get handlesMessage => CustomMethods.super_;
1923

24+
@override
25+
LspJsonHandler<TextDocumentPositionParams> get jsonHandler =>
26+
TextDocumentPositionParams.jsonHandler;
27+
2028
@override
2129
bool get requiresTrustedCaller => false;
2230

2331
@override
24-
Either2<Location?, List<Location>> findRelatedLocations(
25-
Element element,
26-
ResolvedLibraryResult libraryResult,
27-
ResolvedUnitResult unit,
28-
String? prefix) {
29-
// Although the base class supports returning multiple elements, this
30-
// handler is documented to only return a single element.
31-
// Changing this to return a list could be a breaking change for
32-
// clients.
33-
return Either2.t1(
34-
elementToLocation(_SuperComputer().computeSuper(element)));
32+
Future<ErrorOr<Location?>> handle(
33+
TextDocumentPositionParams params,
34+
MessageInfo message,
35+
CancellationToken token,
36+
) async {
37+
if (!isDartDocument(params.textDocument)) {
38+
return success(null);
39+
}
40+
41+
var pos = params.position;
42+
var path = pathOfDoc(params.textDocument);
43+
var unit = await path.mapResult(requireResolvedUnit);
44+
var offset = unit.mapResultSync((unit) => toOffset(unit.lineInfo, pos));
45+
46+
return (unit, offset).mapResultsSync((unit, offset) {
47+
// Find the nearest node that could have a super.
48+
var node = unit.unit
49+
.nodeCovering(offset: offset)
50+
?.thisOrAncestorMatching(_canHaveSuper);
51+
if (node == null) {
52+
return success(null);
53+
}
54+
55+
var element = ElementLocator.locate2(node);
56+
if (element == null) {
57+
return success(null);
58+
}
59+
60+
var targetFragment = _SuperComputer().computeSuper(element);
61+
var location = fragmentToLocation(uriConverter, targetFragment);
62+
return success(location);
63+
});
3564
}
65+
66+
/// Returns whether [node] is something that can be considered to have a
67+
/// "super" (a class or a class member).
68+
bool _canHaveSuper(AstNode node) =>
69+
node is ClassDeclaration || node is ClassMember;
3670
}
3771

3872
class _SuperComputer {
39-
Element? computeSuper(Element element) {
73+
Fragment? computeSuper(Element2 element) {
4074
return switch (element) {
41-
ConstructorElement element => _findSuperConstructor(element),
42-
InterfaceElement element => _findSuperClass(element),
75+
ConstructorElement2 element => _findSuperConstructor(element),
76+
InterfaceElement2 element => _findSuperClass(element),
4377
_ => _findSuperMember(element),
4478
};
4579
}
4680

47-
Element? _findSuperClass(InterfaceElement element) {
48-
return element.supertype?.element;
81+
Fragment? _findSuperClass(InterfaceElement2 element) {
82+
// For super classes, we use the first fragment (the original declaration).
83+
// This differs from methods/getters because we jump to the end of the
84+
// augmentation chain for those.
85+
return element.supertype?.element3.firstFragment;
4986
}
5087

51-
Element? _findSuperConstructor(ConstructorElement element) {
52-
return element.superConstructor?.withAugmentations.last;
88+
Fragment? _findSuperConstructor(ConstructorElement2 element) {
89+
return _lastFragment(element.superConstructor2);
5390
}
5491

55-
Element? _findSuperMember(Element element) {
92+
Fragment? _findSuperMember(Element2 element) {
5693
var session = element.session;
5794
if (session is! AnalysisSessionImpl) {
5895
return null;
5996
}
6097

6198
var inheritanceManager = session.inheritanceManager;
62-
var elementName = element.name;
63-
var interfaceElement = element.thisOrAncestorOfType<InterfaceElement>();
99+
var elementName = element.name3;
100+
var interfaceElement = element.thisOrAncestorOfType2<InterfaceElement2>();
64101

65102
if (elementName == null || interfaceElement == null) {
66103
return null;
67104
}
68105

69-
var name = Name(interfaceElement.library.source.uri, elementName);
70-
var member = inheritanceManager.getInherited2(interfaceElement, name);
106+
var name = Name(
107+
interfaceElement.library2.firstFragment.source.uri,
108+
elementName,
109+
);
110+
var member = inheritanceManager.getInherited4(interfaceElement, name);
71111

72-
return member;
112+
return _lastFragment(member);
113+
}
114+
115+
Fragment? _lastFragment(FragmentedElement? element) {
116+
Fragment? fragment = element?.firstFragment;
117+
while (fragment?.nextFragment != null) {
118+
fragment = fragment?.nextFragment;
119+
}
120+
return fragment;
73121
}
74122
}

pkg/analysis_server/lib/src/lsp/mapping.dart

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import 'package:analysis_server/src/services/completion/dart/feature_computer.da
2323
import 'package:analysis_server/src/services/snippets/snippet.dart';
2424
import 'package:analysis_server/src/utilities/extensions/string.dart';
2525
import 'package:analyzer/dart/analysis/results.dart' as server;
26+
import 'package:analyzer/dart/element/element2.dart';
2627
import 'package:analyzer/error/error.dart' as server;
2728
import 'package:analyzer/source/line_info.dart' as server;
2829
import 'package:analyzer/source/line_info.dart';
@@ -497,6 +498,41 @@ lsp.SymbolKind elementKindToSymbolKind(
497498
);
498499
}
499500

501+
lsp.Location? fragmentToLocation(
502+
ClientUriConverter uriConverter,
503+
Fragment? fragment,
504+
) {
505+
if (fragment == null) {
506+
return null;
507+
}
508+
509+
var libraryFragment = fragment.libraryFragment;
510+
var sourcePath = libraryFragment.source.fullName;
511+
512+
var nameOffset = fragment.nameOffset2;
513+
var nameLength = fragment.name2?.length;
514+
515+
// For unnamed constructors, use the type name as the target location.
516+
if (nameOffset == null && fragment is ConstructorFragment) {
517+
nameOffset = fragment.typeNameOffset;
518+
nameLength = fragment.typeName?.length;
519+
}
520+
521+
if (nameOffset == null || nameLength == null) {
522+
// This is some kind of synthetic fragment we can't navigate to.
523+
return null;
524+
}
525+
526+
return lsp.Location(
527+
uri: uriConverter.toClientUri(sourcePath),
528+
range: toRange(
529+
libraryFragment.lineInfo,
530+
nameOffset,
531+
nameLength,
532+
),
533+
);
534+
}
535+
500536
/// Returns additional details to be shown against a completion.
501537
CompletionDetail getCompletionDetail(
502538
server.CompletionSuggestion suggestion, {

0 commit comments

Comments
 (0)