Skip to content

Commit 35ec2ea

Browse files
kallentuCommit Queue
authored andcommitted
[analyzer] Dot shorthands: Issue 61219 - Recovery for selector chains in LHS of assignment.
This CL adds caching of a context type in the particular case that we have a dot shorthand in a property access in the LHS of an assignment. This scenario would previously crash upon seeing that we have no cached context type. It's still not valid code, but at least we're not crashing when we analyze it. Bug: #61219 Change-Id: I0159b90de7a53a8a1120e0ba2c7be5d7758cc17d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/442803 Reviewed-by: Brian Wilkerson <[email protected]> Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Kallen Tu <[email protected]>
1 parent 889fe27 commit 35ec2ea

File tree

3 files changed

+95
-0
lines changed

3 files changed

+95
-0
lines changed

pkg/analysis_server/test/services/completion/dart/location/dot_shorthand_property_access_test.dart

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,55 @@ suggestions
3535
''');
3636
}
3737

38+
Future<void> test_class_assignment() async {
39+
allowedIdentifiers = {'setter', 'self'};
40+
await computeSuggestions('''
41+
class C {
42+
set setter(int value) {}
43+
late C self = this;
44+
}
45+
46+
void f(C foo) {var foo.^ = C()}
47+
''');
48+
assertResponse(r'''
49+
suggestions
50+
''');
51+
}
52+
53+
Future<void> test_class_assignment_prefix() async {
54+
allowedIdentifiers = {'setter', 'self'};
55+
await computeSuggestions('''
56+
class C {
57+
set setter(int value) {}
58+
late C self = this;
59+
}
60+
61+
void f(C foo) {var foo.s^ = C()}
62+
''');
63+
assertResponse(r'''
64+
replacement
65+
left: 1
66+
suggestions
67+
''');
68+
}
69+
70+
Future<void> test_class_assignment_prefix_chain() async {
71+
allowedIdentifiers = {'setter', 'self'};
72+
await computeSuggestions('''
73+
class C {
74+
set setter(int value) {}
75+
late C self = this;
76+
}
77+
78+
void f(C foo) {var foo.s^.self = C()}
79+
''');
80+
assertResponse(r'''
81+
replacement
82+
left: 1
83+
suggestions
84+
''');
85+
}
86+
3887
Future<void> test_class_chain() async {
3988
allowedIdentifiers = {'getter', 'anotherGetter', 'notStatic'};
4089
await computeSuggestions('''

pkg/analyzer/lib/src/generated/resolver.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,6 +1515,13 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
15151515
);
15161516
} else if (node is PropertyAccessImpl) {
15171517
if (node.target case var target?) {
1518+
if (isDotShorthand(node)) {
1519+
// Recovery.
1520+
// It's a compile-time error to use a dot shorthand as the target of a
1521+
// write, but to prevent any crashing we provide an unknown context
1522+
// type since this shouldn't be valid code.
1523+
pushDotShorthandContext(target, operations.unknownType);
1524+
}
15181525
analyzeExpression(target, operations.unknownType);
15191526
popRewrite();
15201527
}

pkg/analyzer/test/src/dart/analysis/resolve_for_completion_test.dart

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,45 @@ class B extends A {
152152
result.assertResolvedNodes(['B(super.);']);
153153
}
154154

155+
test_dotShorthand_assignment() async {
156+
var result = await _resolveTestCode(r'''
157+
extension on int {
158+
set setter(int value) {}
159+
}
160+
161+
void f(int foo) {var foo.^ = 0}
162+
''');
163+
164+
result.assertResolvedNodes(['void f(int foo) {var foo; . = 0;}']);
165+
}
166+
167+
test_dotShorthand_assignment_chain_method() async {
168+
var result = await _resolveTestCode(r'''
169+
class C {
170+
set setter(int value) {}
171+
C method() => C();
172+
late C self = this;
173+
}
174+
175+
void f(C foo) {var foo.s^.method() = C()}
176+
''');
177+
178+
result.assertResolvedNodes(['void f(C foo) {var foo; .s.method() = C();}']);
179+
}
180+
181+
test_dotShorthand_assignment_chain_propertyAccess() async {
182+
var result = await _resolveTestCode(r'''
183+
class C {
184+
set setter(int value) {}
185+
late C self = this;
186+
}
187+
188+
void f(C foo) {var foo.s^.self = C()}
189+
''');
190+
191+
result.assertResolvedNodes(['void f(C foo) {var foo; .s.self = C();}']);
192+
}
193+
155194
test_extension_methodDeclaration_body() async {
156195
var result = await _resolveTestCode(r'''
157196
extension E on int {

0 commit comments

Comments
 (0)