Skip to content

Commit c5116b4

Browse files
kallentuCommit Queue
authored and
Commit Queue
committed
[analyzer] Dot shorthands: Error - unable to resolve a dot shorthand property access.
Added `DOT_SHORTHAND_MISSING_CONTEXT` error code for when we don't find a valid context type to resolve the dot shorthand head with. `DOT_SHORTHAND_UNDEFINED_GETTER` is used for being unable to find a static getter or field with a certain context type and name. Unit tests added and a few language error + co19 tests passing (eg `simple_identifier_extends_error_test`). Bug: #59835 Change-Id: Ic515b57dd0f4243b049e02bd58b694a500d57975 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/425181 Reviewed-by: Brian Wilkerson <[email protected]> Reviewed-by: Paul Berry <[email protected]> Commit-Queue: Kallen Tu <[email protected]>
1 parent 67a24ea commit c5116b4

File tree

9 files changed

+169
-42
lines changed

9 files changed

+169
-42
lines changed

pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,10 @@ CompileTimeErrorCode.DEFINITELY_UNASSIGNED_LATE_LOCAL_VARIABLE:
514514
CompileTimeErrorCode.DISALLOWED_TYPE_INSTANTIATION_EXPRESSION:
515515
status: needsFix
516516
since: 2.15
517+
CompileTimeErrorCode.DOT_SHORTHAND_MISSING_CONTEXT:
518+
status: needsEvaluation
519+
CompileTimeErrorCode.DOT_SHORTHAND_UNDEFINED_GETTER:
520+
status: needsEvaluation
517521
CompileTimeErrorCode.DUPLICATE_CONSTRUCTOR_DEFAULT:
518522
status: noFix
519523
notes: |-

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

+50-26
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,13 @@ class PropertyElementResolver with ScopeHelpers {
4242
DotShorthandPropertyAccessImpl node,
4343
) {
4444
if (_resolver.isDotShorthandContextEmpty) {
45-
// TODO(kallentu): Produce an error here for not being able to find a
46-
// context type.
47-
return PropertyElementResolverResult();
45+
assert(
46+
false,
47+
'DotShorthandPropertyAccessImpl is not enclosed in an expression for '
48+
'which DotShorthandMixin.isDotShorthand is true',
49+
);
4850
}
51+
4952
TypeImpl context =
5053
_resolver.getDotShorthandContext().unwrapTypeSchemaView();
5154

@@ -61,26 +64,36 @@ class PropertyElementResolver with ScopeHelpers {
6164
identifier.name,
6265
_definingLibrary,
6366
);
64-
if (element != null) {
65-
return PropertyElementResolverResult(
66-
readElementRequested2: element,
67-
getType: element.returnType,
67+
// We didn't resolve to any static getter or static field using the
68+
// context type.
69+
if (element == null) {
70+
errorReporter.atNode(
71+
node,
72+
CompileTimeErrorCode.DOT_SHORTHAND_UNDEFINED_GETTER,
73+
arguments: [node.propertyName.name, context.getDisplayString()],
6874
);
75+
return PropertyElementResolverResult();
6976
}
70-
} else {
71-
var contextElement = context.element3;
72-
return _resolveTargetInterfaceElement(
73-
typeReference: contextElement,
74-
isCascaded: false,
75-
propertyName: identifier,
76-
hasRead: true,
77-
hasWrite: false,
77+
return PropertyElementResolverResult(
78+
readElementRequested2: element,
79+
getType: element.returnType,
7880
);
7981
}
82+
var contextElement = context.element3;
83+
return _resolveTargetInterfaceElement(
84+
typeReference: contextElement,
85+
isCascaded: false,
86+
propertyName: identifier,
87+
hasRead: true,
88+
hasWrite: false,
89+
resolvingDotShorthand: true,
90+
);
8091
}
8192

82-
// TODO(kallentu): Produce an error here for not being able to find a
83-
// property.
93+
errorReporter.atNode(
94+
node,
95+
CompileTimeErrorCode.DOT_SHORTHAND_MISSING_CONTEXT,
96+
);
8497
return PropertyElementResolverResult();
8598
}
8699

@@ -714,6 +727,7 @@ class PropertyElementResolver with ScopeHelpers {
714727
required SimpleIdentifier propertyName,
715728
required bool hasRead,
716729
required bool hasWrite,
730+
bool resolvingDotShorthand = false,
717731
}) {
718732
if (isCascaded) {
719733
typeReference = _resolver.typeProvider.typeType.element3;
@@ -742,15 +756,25 @@ class PropertyElementResolver with ScopeHelpers {
742756
readElement = null;
743757
}
744758
} else {
745-
var code =
746-
typeReference is EnumElement
747-
? CompileTimeErrorCode.UNDEFINED_ENUM_CONSTANT
748-
: CompileTimeErrorCode.UNDEFINED_GETTER;
749-
errorReporter.atNode(
750-
propertyName,
751-
code,
752-
arguments: [propertyName.name, typeReference.name3!],
753-
);
759+
if (resolvingDotShorthand) {
760+
// We didn't resolve to any static getter or static field using the
761+
// context type.
762+
errorReporter.atNode(
763+
propertyName,
764+
CompileTimeErrorCode.DOT_SHORTHAND_UNDEFINED_GETTER,
765+
arguments: [propertyName.name, typeReference.name3!],
766+
);
767+
} else {
768+
var code =
769+
typeReference is EnumElement
770+
? CompileTimeErrorCode.UNDEFINED_ENUM_CONSTANT
771+
: CompileTimeErrorCode.UNDEFINED_GETTER;
772+
errorReporter.atNode(
773+
propertyName,
774+
code,
775+
arguments: [propertyName.name, typeReference.name3!],
776+
);
777+
}
754778
}
755779
}
756780

pkg/analyzer/lib/src/error/codes.g.dart

+18
Original file line numberDiff line numberDiff line change
@@ -1392,6 +1392,24 @@ class CompileTimeErrorCode extends ErrorCode {
13921392
hasPublishedDocs: true,
13931393
);
13941394

1395+
static const CompileTimeErrorCode DOT_SHORTHAND_MISSING_CONTEXT =
1396+
CompileTimeErrorCode(
1397+
'DOT_SHORTHAND_MISSING_CONTEXT',
1398+
"A dot shorthand can't be used where there is no context type.",
1399+
);
1400+
1401+
/// Parameters:
1402+
/// 0: the name of the static getter
1403+
/// 1: the name of the enclosing type where the getter is being looked for
1404+
static const CompileTimeErrorCode
1405+
DOT_SHORTHAND_UNDEFINED_GETTER = CompileTimeErrorCode(
1406+
'DOT_SHORTHAND_UNDEFINED_GETTER',
1407+
"The static getter '{0}' isn't defined for the context type '{1}'.",
1408+
correctionMessage:
1409+
"Try correcting the name to the name of an existing static getter, or "
1410+
"defining a getter or field named '{0}'.",
1411+
);
1412+
13951413
/// No parameters.
13961414
static const CompileTimeErrorCode DUPLICATE_CONSTRUCTOR_DEFAULT =
13971415
CompileTimeErrorCode(

pkg/analyzer/lib/src/error/error_code_values.g.dart

+2
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ const List<ErrorCode> errorCodeValues = [
174174
CompileTimeErrorCode.DEFERRED_IMPORT_OF_EXTENSION,
175175
CompileTimeErrorCode.DEFINITELY_UNASSIGNED_LATE_LOCAL_VARIABLE,
176176
CompileTimeErrorCode.DISALLOWED_TYPE_INSTANTIATION_EXPRESSION,
177+
CompileTimeErrorCode.DOT_SHORTHAND_MISSING_CONTEXT,
178+
CompileTimeErrorCode.DOT_SHORTHAND_UNDEFINED_GETTER,
177179
CompileTimeErrorCode.DUPLICATE_CONSTRUCTOR_DEFAULT,
178180
CompileTimeErrorCode.DUPLICATE_CONSTRUCTOR_NAME,
179181
CompileTimeErrorCode.DUPLICATE_DEFINITION,

pkg/analyzer/messages.yaml

+9
Original file line numberDiff line numberDiff line change
@@ -3860,6 +3860,15 @@ CompileTimeErrorCode:
38603860
comment: |-
38613861
Parameters:
38623862
0: the name of the duplicate entity
3863+
DOT_SHORTHAND_MISSING_CONTEXT:
3864+
problemMessage: "A dot shorthand can't be used where there is no context type."
3865+
DOT_SHORTHAND_UNDEFINED_GETTER:
3866+
problemMessage: "The static getter '{0}' isn't defined for the context type '{1}'."
3867+
correctionMessage: "Try correcting the name to the name of an existing static getter, or defining a getter or field named '{0}'."
3868+
comment: |-
3869+
Parameters:
3870+
0: the name of the static getter
3871+
1: the name of the enclosing type where the getter is being looked for
38633872
DUPLICATE_CONSTRUCTOR_DEFAULT:
38643873
sharedName: DUPLICATE_CONSTRUCTOR
38653874
problemMessage: The unnamed constructor is already defined.

pkg/analyzer/test/src/dart/resolution/dot_shorthand_property_access_test.dart

+57
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'package:analyzer/src/error/codes.dart';
56
import 'package:test_reflective_loader/test_reflective_loader.dart';
67

78
import 'context_collection_resolution.dart';
@@ -317,6 +318,62 @@ DotShorthandPropertyAccess
317318
''');
318319
}
319320

321+
test_error_context_invalid() async {
322+
await assertErrorsInCode(
323+
'''
324+
class C { }
325+
326+
void main() {
327+
C Function() c = .member;
328+
print(c);
329+
}
330+
''',
331+
[error(CompileTimeErrorCode.DOT_SHORTHAND_MISSING_CONTEXT, 46, 7)],
332+
);
333+
}
334+
335+
test_error_context_none() async {
336+
await assertErrorsInCode(
337+
'''
338+
void main() {
339+
var c = .member;
340+
print(c);
341+
}
342+
''',
343+
[error(CompileTimeErrorCode.DOT_SHORTHAND_MISSING_CONTEXT, 24, 7)],
344+
);
345+
}
346+
347+
test_error_unresolved() async {
348+
await assertErrorsInCode(
349+
'''
350+
class C { }
351+
352+
void main() {
353+
C c = .getter;
354+
print(c);
355+
}
356+
''',
357+
[error(CompileTimeErrorCode.DOT_SHORTHAND_UNDEFINED_GETTER, 36, 6)],
358+
);
359+
}
360+
361+
test_error_unresolved_new() async {
362+
await assertErrorsInCode(
363+
'''
364+
class C {
365+
C.named();
366+
}
367+
368+
void main() {
369+
C c = .new;
370+
print(c);
371+
}
372+
''',
373+
[error(CompileTimeErrorCode.DOT_SHORTHAND_UNDEFINED_GETTER, 48, 4)],
374+
);
375+
}
376+
320377
test_extensionType() async {
321378
await assertNoErrorsInCode('''
322379
extension type C(int integer) {

tests/language/dot_shorthands/simple/simple_identifier_error_test.dart

+16-10
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,33 @@ import '../dot_shorthand_helper.dart';
1111

1212
void main() {
1313
var color = .blue;
14-
// ^^^^
15-
// [analyzer] unspecified
14+
// ^^^^^
15+
// [analyzer] COMPILE_TIME_ERROR.DOT_SHORTHAND_MISSING_CONTEXT
16+
// ^
1617
// [cfe] No type was provided to find the dot shorthand 'blue'.
1718

1819
const constColor = .blue;
19-
// ^^^^
20-
// [analyzer] unspecified
20+
// ^^^^^
21+
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
22+
// [analyzer] COMPILE_TIME_ERROR.DOT_SHORTHAND_MISSING_CONTEXT
23+
// ^
2124
// [cfe] No type was provided to find the dot shorthand 'blue'.
2225

2326
var integer = .one;
24-
// ^^^
25-
// [analyzer] unspecified
27+
// ^^^^
28+
// [analyzer] COMPILE_TIME_ERROR.DOT_SHORTHAND_MISSING_CONTEXT
29+
// ^
2630
// [cfe] No type was provided to find the dot shorthand 'one'.
2731

2832
const constInteger = .one;
29-
// ^^^
30-
// [analyzer] unspecified
33+
// ^^^^
34+
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
35+
// [analyzer] COMPILE_TIME_ERROR.DOT_SHORTHAND_MISSING_CONTEXT
36+
// ^
3137
// [cfe] No type was provided to find the dot shorthand 'one'.
3238

3339
Integer i = .one();
34-
// ^
35-
// [analyzer] unspecified
40+
// ^^^^
41+
// [analyzer] COMPILE_TIME_ERROR.INVOCATION_OF_NON_FUNCTION_EXPRESSION
3642
// [cfe] The method 'call' isn't defined for the class 'Integer'.
3743
}

tests/language/dot_shorthands/simple/simple_identifier_extends_error_test.dart

+9-6
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,24 @@ import '../dot_shorthand_helper.dart';
1414

1515
void extendsInteger<X extends Integer>() {
1616
X x = .one;
17-
// ^^^
18-
// [analyzer] unspecified
17+
// ^^^^
18+
// [analyzer] COMPILE_TIME_ERROR.DOT_SHORTHAND_MISSING_CONTEXT
19+
// ^
1920
// [cfe] The static getter or field 'one' isn't defined for the type 'X'.
2021
}
2122

2223
void extendsIntegerNullable<X extends Integer?>() {
2324
X x = .one;
24-
// ^^^
25-
// [analyzer] unspecified
25+
// ^^^^
26+
// [analyzer] COMPILE_TIME_ERROR.DOT_SHORTHAND_MISSING_CONTEXT
27+
// ^
2628
// [cfe] The static getter or field 'one' isn't defined for the type 'X'.
2729
}
2830

2931
void extendsFutureOrInteger<X extends FutureOr<Integer>>() {
3032
X x = .one;
31-
// ^^^
32-
// [analyzer] unspecified
33+
// ^^^^
34+
// [analyzer] COMPILE_TIME_ERROR.DOT_SHORTHAND_MISSING_CONTEXT
35+
// ^
3336
// [cfe] The static getter or field 'one' isn't defined for the type 'X'.
3437
}

tests/language/explicit_type_instantiation_parsing_test.dart

+4
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,8 @@ void main() {
249249
// [cfe] A comparison expression can't be an operand of another comparison expression.
250250
// ^
251251
// [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED
252+
// ^^^^^^^^^
253+
// [analyzer] COMPILE_TIME_ERROR.DOT_SHORTHAND_MISSING_CONTEXT
252254
// [cfe] This requires the experimental 'dot-shorthands' language feature to be enabled.
253255
// ^
254256
// [cfe] The static getter or field 'instance' isn't defined for the type 'dynamic'.
@@ -259,6 +261,8 @@ void main() {
259261
// [cfe] A comparison expression can't be an operand of another comparison expression.
260262
// ^
261263
// [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED
264+
// ^^^^
265+
// [analyzer] COMPILE_TIME_ERROR.DOT_SHORTHAND_MISSING_CONTEXT
262266
// [cfe] This requires the experimental 'dot-shorthands' language feature to be enabled.
263267
// ^
264268
// [cfe] The static getter or field 'any' isn't defined for the type 'dynamic'.

0 commit comments

Comments
 (0)