Skip to content

Commit b243e6a

Browse files
FMorschelCommit Queue
authored andcommitted
[DAS] Fixes semantic token for FunctionType.call
Bug: #61319 Change-Id: I4b42c410ff8e901da546d71658e37a5da6a410aa Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/451620 Auto-Submit: Felipe Morschel <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]> Reviewed-by: Samuel Rawlins <[email protected]> Commit-Queue: Brian Wilkerson <[email protected]>
1 parent 79fa199 commit b243e6a

File tree

2 files changed

+210
-4
lines changed

2 files changed

+210
-4
lines changed

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

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import 'package:analysis_server/src/lsp/semantic_tokens/encoder.dart'
1919
show SemanticTokenInfo;
2020
import 'package:analysis_server/src/lsp/semantic_tokens/mapping.dart'
2121
show highlightRegionTokenModifiers, highlightRegionTokenTypes;
22-
import 'package:analyzer/dart/ast/ast.dart';
2322
import 'package:analyzer/dart/ast/token.dart';
2423
import 'package:analyzer/dart/ast/visitor.dart';
2524
import 'package:analyzer/dart/element/element.dart';
@@ -30,6 +29,7 @@ import 'package:analyzer/src/dart/ast/extensions.dart';
3029
import 'package:analyzer/src/dart/element/extensions.dart';
3130
import 'package:analyzer/src/utilities/extensions/ast.dart';
3231
import 'package:analyzer_plugin/protocol/protocol_common.dart' hide Element;
32+
import 'package:collection/collection.dart';
3333

3434
/// A computer for [HighlightRegion]s and LSP [SemanticTokenInfo] in a Dart [CompilationUnit].
3535
class DartUnitHighlightsComputer {
@@ -674,16 +674,42 @@ class DartUnitHighlightsComputer {
674674
/// Returns whether [nameToken] is a reference to the `call` method on
675675
/// a function.
676676
bool _isCallMethod(AstNode parent, Token nameToken) {
677+
late bool enclosingInstanceFunction =
678+
switch (parent.enclosingInstanceElement) {
679+
ExtensionElement(:var extendedType) => extendedType.isFunction,
680+
_ => false,
681+
};
682+
Expression? expression() => switch (parent) {
683+
ExpressionFunctionBody(:var expression) ||
684+
ExpressionStatement(:var expression) => expression,
685+
ReturnStatement(:var expression) => expression,
686+
ArgumentList(:var arguments) => arguments.firstWhereOrNull((argument) {
687+
return argument is SimpleIdentifier && argument.token == nameToken;
688+
}),
689+
AssignmentExpression(:var rightHandSide) => rightHandSide,
690+
VariableDeclaration(:var initializer) => initializer,
691+
_ => null,
692+
};
677693
return // Invocation
678-
parent is MethodInvocation &&
694+
(parent is MethodInvocation &&
679695
parent.methodName.token == nameToken &&
680696
parent.methodName.name == MethodElement.CALL_METHOD_NAME &&
681-
parent.realTarget?.staticType is FunctionType ||
697+
((parent.realTarget?.staticType).isFunction ||
698+
enclosingInstanceFunction)) ||
682699
// Tearoff
683700
(parent is PrefixedIdentifier &&
684701
parent.identifier.token == nameToken &&
685702
parent.identifier.name == MethodElement.CALL_METHOD_NAME &&
686-
parent.prefix.staticType is FunctionType);
703+
parent.prefix.staticType.isFunction) ||
704+
// Property access
705+
(parent is PropertyAccess &&
706+
parent.propertyName.token == nameToken &&
707+
parent.propertyName.name == MethodElement.CALL_METHOD_NAME &&
708+
parent.realTarget.staticType.isFunction) ||
709+
// Special cases for extension methods
710+
(expression() is SimpleIdentifier &&
711+
nameToken.lexeme == MethodElement.CALL_METHOD_NAME &&
712+
enclosingInstanceFunction);
687713
}
688714

689715
void _reset() {
@@ -2084,3 +2110,8 @@ extension on StringInterpolation {
20842110
(false, false, false) => Quote.Double,
20852111
};
20862112
}
2113+
2114+
extension on DartType? {
2115+
bool get isFunction =>
2116+
this is FunctionType || (this?.isDartCoreFunction ?? false);
2117+
}

pkg/analysis_server/test/lsp/semantic_tokens_test.dart

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,6 +1213,148 @@ f(void Function(int)? x) {
12131213
await _initializeAndVerifyTokensInRange(content, expected);
12141214
}
12151215

1216+
Future<void> test_function_callMethod_invocation_extension() async {
1217+
var content = r'''
1218+
extension on void Function() {
1219+
m() => [!call()!];
1220+
}
1221+
''';
1222+
1223+
var expected = <_Token>[
1224+
_Token('call', SemanticTokenTypes.method, [
1225+
CustomSemanticTokenModifiers.instance,
1226+
]),
1227+
];
1228+
1229+
await _initializeAndVerifyTokensInRange(content, expected);
1230+
}
1231+
1232+
Future<void> test_function_callMethod_propertyAccess() async {
1233+
var content = r'''
1234+
extension on void Function()? {
1235+
m() => [!this?.call!];
1236+
}
1237+
''';
1238+
1239+
var expected = <_Token>[
1240+
_Token('this', SemanticTokenTypes.keyword),
1241+
_Token('call', SemanticTokenTypes.method, [
1242+
CustomSemanticTokenModifiers.instance,
1243+
]),
1244+
];
1245+
1246+
await _initializeAndVerifyTokensInRange(content, expected);
1247+
}
1248+
1249+
Future<void> test_function_callMethod_simpleIdentifier() async {
1250+
var content = r'''
1251+
extension on void Function() {
1252+
m() {
1253+
[!call!];
1254+
}
1255+
}
1256+
''';
1257+
1258+
var expected = <_Token>[
1259+
_Token('call', SemanticTokenTypes.method, [
1260+
CustomSemanticTokenModifiers.instance,
1261+
]),
1262+
];
1263+
1264+
await _initializeAndVerifyTokensInRange(content, expected);
1265+
}
1266+
1267+
Future<void> test_function_callMethod_simpleIdentifier_argument() async {
1268+
var content = r'''
1269+
extension on void Function() {
1270+
m(void Function() f) {
1271+
m([!call!]);
1272+
}
1273+
}
1274+
''';
1275+
1276+
var expected = <_Token>[
1277+
_Token('call', SemanticTokenTypes.method, [
1278+
CustomSemanticTokenModifiers.instance,
1279+
]),
1280+
];
1281+
1282+
await _initializeAndVerifyTokensInRange(content, expected);
1283+
}
1284+
1285+
Future<void> test_function_callMethod_simpleIdentifier_assignment() async {
1286+
var content = r'''
1287+
extension on void Function() {
1288+
m() {
1289+
var a;
1290+
a = [!call!];
1291+
}
1292+
}
1293+
''';
1294+
1295+
var expected = <_Token>[
1296+
_Token('call', SemanticTokenTypes.method, [
1297+
CustomSemanticTokenModifiers.instance,
1298+
]),
1299+
];
1300+
1301+
await _initializeAndVerifyTokensInRange(content, expected);
1302+
}
1303+
1304+
Future<void>
1305+
test_function_callMethod_simpleIdentifier_expressionFunctionBody() async {
1306+
var content = r'''
1307+
extension on void Function() {
1308+
m() => [!call!];
1309+
}
1310+
''';
1311+
1312+
var expected = <_Token>[
1313+
_Token('call', SemanticTokenTypes.method, [
1314+
CustomSemanticTokenModifiers.instance,
1315+
]),
1316+
];
1317+
1318+
await _initializeAndVerifyTokensInRange(content, expected);
1319+
}
1320+
1321+
Future<void> test_function_callMethod_simpleIdentifier_return() async {
1322+
var content = r'''
1323+
extension on void Function() {
1324+
m() {
1325+
return [!call!];
1326+
}
1327+
}
1328+
''';
1329+
1330+
var expected = <_Token>[
1331+
_Token('call', SemanticTokenTypes.method, [
1332+
CustomSemanticTokenModifiers.instance,
1333+
]),
1334+
];
1335+
1336+
await _initializeAndVerifyTokensInRange(content, expected);
1337+
}
1338+
1339+
Future<void>
1340+
test_function_callMethod_simpleIdentifier_variableDeclaration() async {
1341+
var content = r'''
1342+
extension on void Function() {
1343+
m() {
1344+
var _ = [!call!];
1345+
}
1346+
}
1347+
''';
1348+
1349+
var expected = <_Token>[
1350+
_Token('call', SemanticTokenTypes.method, [
1351+
CustomSemanticTokenModifiers.instance,
1352+
]),
1353+
];
1354+
1355+
await _initializeAndVerifyTokensInRange(content, expected);
1356+
}
1357+
12161358
Future<void> test_function_callMethod_tearOff() async {
12171359
var content = r'''
12181360
f(void Function(int) x) {
@@ -1230,6 +1372,39 @@ f(void Function(int) x) {
12301372
await _initializeAndVerifyTokensInRange(content, expected);
12311373
}
12321374

1375+
Future<void> test_functionType_callMethod_invocation_extension() async {
1376+
var content = r'''
1377+
extension on Function {
1378+
m() => [!call()!];
1379+
}
1380+
''';
1381+
1382+
var expected = <_Token>[
1383+
_Token('call', SemanticTokenTypes.method, [
1384+
CustomSemanticTokenModifiers.instance,
1385+
]),
1386+
];
1387+
1388+
await _initializeAndVerifyTokensInRange(content, expected);
1389+
}
1390+
1391+
Future<void> test_functionType_callMethod_tearOff() async {
1392+
var content = r'''
1393+
f(Function x) {
1394+
[!x.call!];
1395+
}
1396+
''';
1397+
1398+
var expected = [
1399+
_Token('x', SemanticTokenTypes.parameter),
1400+
_Token('call', SemanticTokenTypes.method, [
1401+
CustomSemanticTokenModifiers.instance,
1402+
]),
1403+
];
1404+
1405+
await _initializeAndVerifyTokensInRange(content, expected);
1406+
}
1407+
12331408
/// Verify that sending a semantic token request immediately after an overlay
12341409
/// update (with no delay) does not result in corrupt semantic tokens because
12351410
/// the previous file content was used.

0 commit comments

Comments
 (0)