Skip to content

Commit beca727

Browse files
kallentuCommit Queue
authored andcommitted
[analysis_server] Dot shorthands: Syntactic and semantic highlighting.
Added additional logic for handling highlighting for dot shorthands. New semantic tokens and highlights tests passing. Bug: #59836 Change-Id: I2e242732aade9471675731473532d6d3c6558281 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/433102 Commit-Queue: Kallen Tu <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]>
1 parent 808cc05 commit beca727

File tree

3 files changed

+303
-1
lines changed

3 files changed

+303
-1
lines changed

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

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,9 @@ class DartUnitHighlightsComputer {
441441
}
442442
var isStatic = element.isStatic;
443443
var isInvocation =
444-
parent is MethodInvocation && parent.methodName.token == nameToken;
444+
(parent is MethodInvocation && parent.methodName.token == nameToken) ||
445+
(parent is DotShorthandInvocation &&
446+
parent.memberName.token == nameToken);
445447
// OK
446448
HighlightRegionType type;
447449
if (isStatic) {
@@ -979,6 +981,23 @@ class _DartUnitHighlightsComputerVisitor extends RecursiveAstVisitor<void> {
979981
super.visitDoStatement(node);
980982
}
981983

984+
@override
985+
void visitDotShorthandPropertyAccess(DotShorthandPropertyAccess node) {
986+
var element = node.propertyName.element;
987+
if (element is ConstructorElement) {
988+
computer._addRegion_node(
989+
node.propertyName,
990+
HighlightRegionType.CONSTRUCTOR_TEAR_OFF,
991+
);
992+
} else {
993+
computer._addIdentifierRegion(
994+
parent: node,
995+
nameToken: node.propertyName.token,
996+
element: element,
997+
);
998+
}
999+
}
1000+
9821001
@override
9831002
void visitDoubleLiteral(DoubleLiteral node) {
9841003
computer._addRegion_node(node, HighlightRegionType.LITERAL_DOUBLE);

pkg/analysis_server/test/analysis/notification_highlights2_test.dart

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,38 @@ void f() {
816816
assertHasRegion(HighlightRegionType.CONSTRUCTOR, 'name(42)');
817817
}
818818

819+
Future<void> test_CONSTRUCTOR_implicitNew_dotShorthand() async {
820+
addTestFile('''
821+
class A {
822+
A();
823+
A.named(int x);
824+
}
825+
void f() {
826+
A a = .new();
827+
A aa = .named(42);
828+
}
829+
''');
830+
await prepareHighlights();
831+
assertHasRegion(HighlightRegionType.CONSTRUCTOR, 'new()');
832+
assertHasRegion(HighlightRegionType.CONSTRUCTOR, 'named(42)');
833+
}
834+
835+
Future<void> test_CONSTRUCTOR_TEAR_OFF_dotShorthand() async {
836+
addTestFile('''
837+
class A {
838+
A();
839+
A.named();
840+
}
841+
void f() {
842+
A a = .new; // compile-time error
843+
A aa = .named; // compile-time error
844+
}
845+
''');
846+
await prepareHighlights();
847+
assertHasRegion(HighlightRegionType.CONSTRUCTOR_TEAR_OFF, 'new;');
848+
assertHasRegion(HighlightRegionType.CONSTRUCTOR_TEAR_OFF, 'named;');
849+
}
850+
819851
Future<void> test_CONSTRUCTOR_TEAR_OFF_named() async {
820852
addTestFile('''
821853
class A<T> {
@@ -1004,6 +1036,17 @@ void f() {
10041036
''');
10051037
}
10061038

1039+
Future<void> test_enum_constant_dotShorthand() async {
1040+
addTestFile('''
1041+
enum E { a }
1042+
void f() {
1043+
E e = .a;
1044+
}
1045+
''');
1046+
await prepareHighlights();
1047+
assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'a;');
1048+
}
1049+
10071050
Future<void> test_enum_constructor() async {
10081051
var testCode = TestCode.parse(r'''
10091052
const a = 0;
@@ -1364,6 +1407,31 @@ void f(A a) {
13641407
assertHasRegion(HighlightRegionType.STATIC_GETTER_REFERENCE, 'ccc;');
13651408
}
13661409

1410+
Future<void> test_GETTER_dotShorthand() async {
1411+
addTestFile('''
1412+
class A {
1413+
static A get aGetter => A();
1414+
}
1415+
extension type B(int x) {
1416+
static B get bGetter => B(1);
1417+
}
1418+
class C {}
1419+
class D extends C with Mixin {}
1420+
mixin Mixin on C {
1421+
static Mixin get dGetter => D();
1422+
}
1423+
void f() {
1424+
A a = .aGetter;
1425+
B b = .bGetter;
1426+
Mixin m = .dGetter;
1427+
}
1428+
''');
1429+
await prepareHighlights();
1430+
assertHasRegion(HighlightRegionType.STATIC_GETTER_REFERENCE, 'aGetter;');
1431+
assertHasRegion(HighlightRegionType.STATIC_GETTER_REFERENCE, 'bGetter;');
1432+
assertHasRegion(HighlightRegionType.STATIC_GETTER_REFERENCE, 'dGetter;');
1433+
}
1434+
13671435
Future<void> test_IDENTIFIER_DEFAULT() async {
13681436
addTestFile('''
13691437
void f() {
@@ -1943,6 +2011,37 @@ void f(p) {
19432011
assertHasRegion(HighlightRegionType.INSTANCE_METHOD_REFERENCE, 'add(null)');
19442012
}
19452013

2014+
Future<void> test_METHOD_dotShorthand() async {
2015+
addTestFile('''
2016+
class A {
2017+
static A aMethod() => A();
2018+
}
2019+
extension type B(int x) {
2020+
static B bMethod() => B(1);
2021+
}
2022+
class C {}
2023+
class D extends C with Mixin {}
2024+
mixin Mixin on C {
2025+
static Mixin dMethod() => D();
2026+
}
2027+
void f() {
2028+
A a = .aMethod();
2029+
A aa = .aMethod; // compile-time error
2030+
B b = .bMethod();
2031+
B bb = .bMethod; // compile-time error
2032+
Mixin m = .dMethod();
2033+
Mixin mm = .dMethod; // compile-time error
2034+
}
2035+
''');
2036+
await prepareHighlights();
2037+
assertHasRegion(HighlightRegionType.STATIC_METHOD_REFERENCE, 'aMethod();');
2038+
assertHasRegion(HighlightRegionType.STATIC_METHOD_TEAR_OFF, 'aMethod;');
2039+
assertHasRegion(HighlightRegionType.STATIC_METHOD_REFERENCE, 'bMethod();');
2040+
assertHasRegion(HighlightRegionType.STATIC_METHOD_TEAR_OFF, 'bMethod;');
2041+
assertHasRegion(HighlightRegionType.STATIC_METHOD_REFERENCE, 'dMethod();');
2042+
assertHasRegion(HighlightRegionType.STATIC_METHOD_TEAR_OFF, 'dMethod;');
2043+
}
2044+
19462045
Future<void> test_mixin() async {
19472046
var testCode = TestCode.parse(r'''
19482047
mixin M on int {}

pkg/analysis_server/test/lsp/semantic_tokens_test.dart

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -927,6 +927,190 @@ import '../file.dart'
927927
await _initializeAndVerifyTokens(content, expected);
928928
}
929929

930+
Future<void> test_dotShorthand_constructor() async {
931+
failTestOnErrorDiagnostic = false;
932+
933+
var content = r'''
934+
class A {
935+
A();
936+
A.named(int x);
937+
}
938+
void f() {
939+
[!
940+
A a = .new();
941+
A aa = .named(42);
942+
A aTearOff = .new;
943+
A aTearOff = .named;
944+
!]
945+
}
946+
''';
947+
948+
var expected = [
949+
_Token('A', SemanticTokenTypes.class_),
950+
_Token('a', SemanticTokenTypes.variable, [
951+
SemanticTokenModifiers.declaration,
952+
]),
953+
_Token('new', SemanticTokenTypes.method, [
954+
CustomSemanticTokenModifiers.constructor,
955+
]),
956+
_Token('A', SemanticTokenTypes.class_),
957+
_Token('aa', SemanticTokenTypes.variable, [
958+
SemanticTokenModifiers.declaration,
959+
]),
960+
_Token('named', SemanticTokenTypes.method, [
961+
CustomSemanticTokenModifiers.constructor,
962+
]),
963+
_Token('42', SemanticTokenTypes.number),
964+
_Token('A', SemanticTokenTypes.class_),
965+
_Token('aTearOff', SemanticTokenTypes.variable, [
966+
SemanticTokenModifiers.declaration,
967+
]),
968+
_Token('new', SemanticTokenTypes.method, [
969+
CustomSemanticTokenModifiers.constructor,
970+
]),
971+
_Token('A', SemanticTokenTypes.class_),
972+
_Token('aTearOff', SemanticTokenTypes.variable, [
973+
SemanticTokenModifiers.declaration,
974+
]),
975+
_Token('named', SemanticTokenTypes.method, [
976+
CustomSemanticTokenModifiers.constructor,
977+
]),
978+
];
979+
980+
await _initializeAndVerifyTokensInRange(content, expected);
981+
}
982+
983+
Future<void> test_dotShorthand_getter() async {
984+
var content = r'''
985+
enum E { a }
986+
class A {
987+
static A get aGetter => A();
988+
}
989+
extension type B(int x) {
990+
static B get bGetter => B(1);
991+
}
992+
class C {}
993+
class D extends C with Mixin {}
994+
mixin Mixin on C {
995+
static Mixin get dGetter => D();
996+
}
997+
void f() {
998+
[!
999+
E e = .a;
1000+
A a = .aGetter;
1001+
B b = .bGetter;
1002+
Mixin m = .dGetter;
1003+
!]
1004+
}
1005+
''';
1006+
1007+
var expected = [
1008+
_Token('E', SemanticTokenTypes.enum_),
1009+
_Token('e', SemanticTokenTypes.variable, [
1010+
SemanticTokenModifiers.declaration,
1011+
]),
1012+
_Token('a', SemanticTokenTypes.enumMember),
1013+
_Token('A', SemanticTokenTypes.class_),
1014+
_Token('a', SemanticTokenTypes.variable, [
1015+
SemanticTokenModifiers.declaration,
1016+
]),
1017+
_Token('aGetter', SemanticTokenTypes.property, [
1018+
SemanticTokenModifiers.static,
1019+
]),
1020+
_Token('B', SemanticTokenTypes.class_),
1021+
_Token('b', SemanticTokenTypes.variable, [
1022+
SemanticTokenModifiers.declaration,
1023+
]),
1024+
_Token('bGetter', SemanticTokenTypes.property, [
1025+
SemanticTokenModifiers.static,
1026+
]),
1027+
_Token('Mixin', SemanticTokenTypes.class_),
1028+
_Token('m', SemanticTokenTypes.variable, [
1029+
SemanticTokenModifiers.declaration,
1030+
]),
1031+
_Token('dGetter', SemanticTokenTypes.property, [
1032+
SemanticTokenModifiers.static,
1033+
]),
1034+
];
1035+
1036+
await _initializeAndVerifyTokensInRange(content, expected);
1037+
}
1038+
1039+
Future<void> test_dotShorthand_method() async {
1040+
failTestOnErrorDiagnostic = false;
1041+
1042+
var content = r'''
1043+
class A {
1044+
static A aMethod() => A();
1045+
}
1046+
extension type B(int x) {
1047+
static B bMethod() => B(1);
1048+
}
1049+
class C {}
1050+
class D extends C with Mixin {}
1051+
mixin Mixin on C {
1052+
static Mixin dMethod() => D();
1053+
}
1054+
void f() {
1055+
[!
1056+
A a = .aMethod();
1057+
A aa = .aMethod;
1058+
B b = .bMethod();
1059+
B bb = .bMethod;
1060+
Mixin m = .dMethod();
1061+
Mixin mm = .dMethod;
1062+
!]
1063+
}
1064+
''';
1065+
1066+
var expected = [
1067+
_Token('A', SemanticTokenTypes.class_),
1068+
_Token('a', SemanticTokenTypes.variable, [
1069+
SemanticTokenModifiers.declaration,
1070+
]),
1071+
_Token('aMethod', SemanticTokenTypes.method, [
1072+
SemanticTokenModifiers.static,
1073+
]),
1074+
_Token('A', SemanticTokenTypes.class_),
1075+
_Token('aa', SemanticTokenTypes.variable, [
1076+
SemanticTokenModifiers.declaration,
1077+
]),
1078+
_Token('aMethod', SemanticTokenTypes.method, [
1079+
SemanticTokenModifiers.static,
1080+
]),
1081+
_Token('B', SemanticTokenTypes.class_),
1082+
_Token('b', SemanticTokenTypes.variable, [
1083+
SemanticTokenModifiers.declaration,
1084+
]),
1085+
_Token('bMethod', SemanticTokenTypes.method, [
1086+
SemanticTokenModifiers.static,
1087+
]),
1088+
_Token('B', SemanticTokenTypes.class_),
1089+
_Token('bb', SemanticTokenTypes.variable, [
1090+
SemanticTokenModifiers.declaration,
1091+
]),
1092+
_Token('bMethod', SemanticTokenTypes.method, [
1093+
SemanticTokenModifiers.static,
1094+
]),
1095+
_Token('Mixin', SemanticTokenTypes.class_),
1096+
_Token('m', SemanticTokenTypes.variable, [
1097+
SemanticTokenModifiers.declaration,
1098+
]),
1099+
_Token('dMethod', SemanticTokenTypes.method, [
1100+
SemanticTokenModifiers.static,
1101+
]),
1102+
_Token('Mixin', SemanticTokenTypes.class_),
1103+
_Token('mm', SemanticTokenTypes.variable, [
1104+
SemanticTokenModifiers.declaration,
1105+
]),
1106+
_Token('dMethod', SemanticTokenTypes.method, [
1107+
SemanticTokenModifiers.static,
1108+
]),
1109+
];
1110+
1111+
await _initializeAndVerifyTokensInRange(content, expected);
1112+
}
1113+
9301114
Future<void> test_emptyAnalysisRoots_handlesFileRequestsImmediately() async {
9311115
var content = '''
9321116
// test

0 commit comments

Comments
 (0)