Skip to content

Commit 789c266

Browse files
bwilkersonCommit Queue
authored and
Commit Queue
committed
Migrate the call hierarchy computer
Change-Id: I373604453f01af52d0a54386b51fdc5b68e4f854 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/400700 Reviewed-by: Samuel Rawlins <[email protected]> Commit-Queue: Brian Wilkerson <[email protected]>
1 parent 5cacaca commit 789c266

File tree

2 files changed

+61
-45
lines changed

2 files changed

+61
-45
lines changed

pkg/analysis_server/analyzer_use_new_elements.txt

-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
lib/plugin/protocol/protocol_dart.dart
22
lib/src/analysis_server.dart
33
lib/src/cider/rename.dart
4-
lib/src/computer/computer_call_hierarchy.dart
54
lib/src/domains/analysis/occurrences_dart.dart
65
lib/src/handler/legacy/edit_get_available_refactorings.dart
76
lib/src/handler/legacy/search_find_element_references.dart

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

+61-44
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,25 @@ import 'package:analysis_server/src/services/search/search_engine.dart';
77
import 'package:analyzer/dart/analysis/results.dart';
88
import 'package:analyzer/dart/ast/ast.dart';
99
import 'package:analyzer/dart/ast/visitor.dart';
10-
import 'package:analyzer/dart/element/element.dart';
10+
import 'package:analyzer/dart/element/element2.dart';
1111
import 'package:analyzer/source/source_range.dart';
1212
import 'package:analyzer/src/dart/ast/element_locator.dart';
1313
import 'package:analyzer/src/dart/ast/utilities.dart';
1414
import 'package:analyzer/src/dart/element/element.dart';
15-
import 'package:analyzer/src/utilities/extensions/element.dart';
1615

1716
/// Returns the container for [element] that should be used in Call Hierarchy.
1817
///
1918
/// Returns `null` if none of [elements] are valid containers.
2019
///
2120
/// This is used to construct (and group calls by) a [CallHierarchyItem] that
2221
/// contains calls and also locate their containers for additional labelling.
23-
Element? _getContainer(Element element) {
22+
Element2? _getContainer(Element2 element) {
23+
// TODO(brianwilkerson): This used to use the compilation unit as a container
24+
// which allowed users to see the path to the containing file, but that's
25+
// been lost. Consider trying to restore that behavior.
2426
const containerKinds = {
2527
ElementKind.CLASS,
26-
ElementKind.COMPILATION_UNIT,
28+
ElementKind.LIBRARY,
2729
ElementKind.CONSTRUCTOR,
2830
ElementKind.ENUM,
2931
ElementKind.EXTENSION,
@@ -34,29 +36,27 @@ Element? _getContainer(Element element) {
3436
ElementKind.MIXIN,
3537
ElementKind.SETTER,
3638
};
37-
return element.thisOrAncestorMatching(
39+
return element.thisOrAncestorMatching2(
3840
(ancestor) => containerKinds.contains(ancestor.kind),
3941
);
4042
}
4143

4244
/// Gets a user-friendly display name for [element].
43-
String _getDisplayName(Element element) {
44-
return element is CompilationUnitElement
45-
? element.source.shortName
46-
: element is PropertyAccessorElement
47-
? element.isGetter
48-
? 'get ${element.displayName}'
49-
: 'set ${element.displayName}'
50-
: element.displayName;
45+
String _getDisplayName(Element2 element) {
46+
return switch (element) {
47+
LibraryElement2() => element.firstFragment.source.shortName,
48+
GetterElement() => 'get ${element.displayName}',
49+
SetterElement() => 'set ${element.displayName}',
50+
_ => element.displayName,
51+
};
5152
}
5253

5354
/// A [CallHierarchyItem] and a set of ranges that call to or from it.
5455
class CallHierarchyCalls {
5556
final CallHierarchyItem item;
56-
final List<SourceRange> ranges;
57+
final List<SourceRange> ranges = [];
5758

58-
CallHierarchyCalls(this.item, [List<SourceRange>? ranges])
59-
: ranges = ranges ?? [];
59+
CallHierarchyCalls(this.item);
6060
}
6161

6262
/// An item that can appear in a Call Hierarchy.
@@ -102,39 +102,53 @@ class CallHierarchyItem {
102102
required this.codeRange,
103103
});
104104

105-
CallHierarchyItem.forElement(Element element)
105+
CallHierarchyItem.forElement(Element2 element)
106106
: displayName = _getDisplayName(element),
107107
nameRange = _nameRangeForElement(element),
108108
codeRange = _codeRangeForElement(element),
109-
file = element.source!.fullName,
109+
file = element.firstFragment.libraryFragment!.source.fullName,
110110
kind = CallHierarchyKind.forElement(element) {
111-
var enclosingElement = element.enclosingElement3;
111+
var enclosingElement =
112+
element.enclosingElement2 ??
113+
element.firstFragment.enclosingFragment?.element;
112114
var container =
113115
enclosingElement != null ? _getContainer(enclosingElement) : null;
114116
containerName = container != null ? _getDisplayName(container) : null;
115117
}
116118

117119
/// Returns the [SourceRange] of the code for [element].
118-
static SourceRange _codeRangeForElement(Element element) {
120+
static SourceRange _codeRangeForElement(Element2 element) {
119121
// For synthetic items (like implicit constructors), use the nonSynthetic
120122
// element for the location.
121-
var elementImpl = element.nonSynthetic as ElementImpl;
123+
element = _nonSynthetic(element);
124+
var fragment = element.firstFragment as ElementImpl;
122125

123126
// Non-synthetic elements should always have code locations.
124-
return SourceRange(elementImpl.codeOffset!, elementImpl.codeLength!);
127+
// TODO(brianwilkerson): Figure out why that's no longer true and possibly
128+
// remove the conditionals below.
129+
return SourceRange(fragment.codeOffset ?? 0, fragment.codeLength ?? 0);
125130
}
126131

127132
/// Returns the [SourceRange] of the name for [element].
128-
static SourceRange _nameRangeForElement(Element element) {
133+
static SourceRange _nameRangeForElement(Element2 element) {
129134
// For synthetic items (like implicit constructors), use the nonSynthetic
130135
// element for the location.
131-
element = element.nonSynthetic;
136+
element = _nonSynthetic(element);
137+
var fragment = element.firstFragment as ElementImpl;
132138

133139
// Compilation units will return -1 for nameOffset which is not valid, so
134-
//use 0:0.
135-
return element.nameOffset == -1
140+
// use 0:0.
141+
return fragment.nameOffset == -1
136142
? SourceRange(0, 0)
137-
: SourceRange(element.nameOffset, element.nameLength);
143+
: SourceRange(fragment.nameOffset, fragment.nameLength);
144+
}
145+
146+
static Element2 _nonSynthetic(Element2 element) {
147+
element = element.nonSynthetic2;
148+
if (element.isSynthetic) {
149+
element = element.enclosingElement2 ?? element;
150+
}
151+
return element;
138152
}
139153
}
140154

@@ -153,7 +167,7 @@ enum CallHierarchyKind {
153167

154168
static const _elementMapping = {
155169
ElementKind.CLASS: class_,
156-
ElementKind.COMPILATION_UNIT: file,
170+
ElementKind.LIBRARY: file,
157171
ElementKind.CONSTRUCTOR: constructor,
158172
ElementKind.EXTENSION: extension,
159173
ElementKind.FUNCTION: function,
@@ -163,7 +177,7 @@ enum CallHierarchyKind {
163177
ElementKind.SETTER: property,
164178
};
165179

166-
static CallHierarchyKind forElement(Element element) =>
180+
static CallHierarchyKind forElement(Element2 element) =>
167181
_elementMapping[element.kind] ?? unknown;
168182
}
169183

@@ -210,28 +224,28 @@ class DartCallHierarchyComputer {
210224
// implicit constructors do not have.
211225
// Here, we map them back to the synthetic constructor element.
212226
var isImplicitConstructor =
213-
element is InterfaceElement &&
227+
element is InterfaceElement2 &&
214228
target.kind == CallHierarchyKind.constructor;
215229
if (isImplicitConstructor) {
216-
element = element.unnamedConstructor;
230+
element = element.unnamedConstructor2;
217231
}
218232

219233
// We only find incoming calls to executable elements.
220-
if (element is! ExecutableElement) {
234+
if (element is! ExecutableElement2) {
221235
return [];
222236
}
223237

224238
var computer = ElementReferencesComputer(searchEngine);
225-
var references = await computer.compute(element.asElement2, false);
239+
var references = await computer.compute(element, false);
226240

227241
// Group results by their container, since we only want to return a single
228242
// entry for a body, with a set of ranges within.
229-
var resultsByContainer = <Element, CallHierarchyCalls>{};
243+
var resultsByContainer = <Element2, CallHierarchyCalls>{};
230244
// We may need to fetch parsed results for the other files, reuse them
231245
// across calls.
232246
var parsedUnits = <String, SomeParsedUnitResult?>{};
233247
for (var reference in references) {
234-
var container = _getContainer(reference.element);
248+
var container = _getContainer(reference.element2);
235249
if (container == null) {
236250
continue;
237251
}
@@ -279,7 +293,7 @@ class DartCallHierarchyComputer {
279293

280294
// Group results by their target, since we only want to return a single
281295
// entry for each target, with a set of ranges that call it.
282-
var resultsByTarget = <Element, CallHierarchyCalls>{};
296+
var resultsByTarget = <Element2, CallHierarchyCalls>{};
283297
for (var referenceNode in referenceNodes) {
284298
var target = _getElementOfNode(referenceNode);
285299
if (target == null) {
@@ -309,7 +323,7 @@ class DartCallHierarchyComputer {
309323
var element = _getElementOfNode(node);
310324

311325
// We only return targets that are executable elements.
312-
return element is ExecutableElement
326+
return element is ExecutableElement2
313327
? CallHierarchyItem.forElement(element)
314328
: null;
315329
}
@@ -348,7 +362,7 @@ class DartCallHierarchyComputer {
348362
/// Return the [Element] of the given [node], or `null` if [node] is `null`,
349363
/// does not have an element, or the element is not a valid target for call
350364
/// hierarchy.
351-
Element? _getElementOfNode(AstNode? node) {
365+
Element2? _getElementOfNode(AstNode? node) {
352366
if (node == null) {
353367
return null;
354368
}
@@ -357,18 +371,18 @@ class DartCallHierarchyComputer {
357371
// ElementLocator returns the class for default constructor calls and null
358372
// for constructor names.
359373
if (node is NamedType && parent is ConstructorName) {
360-
return parent.staticElement;
374+
return parent.element;
361375
} else if (node is ConstructorName) {
362-
return node.staticElement;
376+
return node.element;
363377
} else if (node is PropertyAccess) {
364378
node = node.propertyName;
365379
}
366380

367-
var element = ElementLocator.locate(node);
381+
var element = ElementLocator.locate2(node);
368382

369383
// Don't consider synthetic getter/setter for a field to be executable
370384
// since they don't contain any executable code.
371-
if (element is PropertyAccessorElement && element.isSynthetic) {
385+
if (element is PropertyAccessorElement2 && element.isSynthetic) {
372386
return null;
373387
}
374388

@@ -380,7 +394,7 @@ class DartCallHierarchyComputer {
380394
/// This is used to ensure calls are only returned for the expected target
381395
/// if source code has changed since the earlier request that provided
382396
/// [target] to the client.
383-
bool _isMatchingElement(Element element, CallHierarchyItem target) {
397+
bool _isMatchingElement(Element2 element, CallHierarchyItem target) {
384398
return _getDisplayName(element) == target.displayName;
385399
}
386400

@@ -494,7 +508,10 @@ class _OutboundCallVisitor extends RecursiveAstVisitor<void> {
494508

495509
@override
496510
void visitSimpleIdentifier(SimpleIdentifier node) {
497-
if (node.staticElement is FunctionElement && !node.inDeclarationContext()) {
511+
var element = node.element;
512+
if ((element is LocalFunctionElement ||
513+
element is TopLevelFunctionElement) &&
514+
!node.inDeclarationContext()) {
498515
collect(node);
499516
}
500517
super.visitSimpleIdentifier(node);

0 commit comments

Comments
 (0)