Skip to content

Commit 8ef0e2a

Browse files
scheglovCommit Queue
authored and
Commit Queue
committed
Augment. Resolve PrefixExpression.
Change-Id: I947b0fee1b4f060bfe168a0f9138a6df4889d1d8 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/365544 Commit-Queue: Konstantin Shcheglov <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]>
1 parent 126ca0f commit 8ef0e2a

File tree

8 files changed

+243
-75
lines changed

8 files changed

+243
-75
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,8 @@ CompileTimeErrorCode.AUGMENTATION_WITHOUT_IMPORT:
223223
The fix is to add `import augment`.
224224
CompileTimeErrorCode.AUGMENTATION_WITHOUT_LIBRARY:
225225
status: noFix
226+
CompileTimeErrorCode.AUGMENTED_EXPRESSION_NOT_OPERATOR:
227+
status: noFix
226228
CompileTimeErrorCode.AWAIT_IN_LATE_LOCAL_VARIABLE_INITIALIZER:
227229
status: needsFix
228230
notes: |-

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

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -332,10 +332,20 @@ class BinaryExpressionResolver {
332332
var augmentation = _resolver.enclosingAugmentation;
333333
var augmentationTarget = augmentation?.augmentationTarget;
334334
if (augmentationTarget case MethodElement augmentationTarget) {
335-
leftOperand.element = augmentationTarget;
336-
node.staticElement = augmentationTarget;
337-
node.staticInvokeType = augmentationTarget.type;
335+
if (augmentationTarget.name == methodName) {
336+
leftOperand.element = augmentationTarget;
337+
node.staticElement = augmentationTarget;
338+
node.staticInvokeType = augmentationTarget.type;
339+
return;
340+
}
338341
}
342+
_errorReporter.atToken(
343+
leftOperand.augmentedKeyword,
344+
CompileTimeErrorCode.AUGMENTED_EXPRESSION_NOT_OPERATOR,
345+
arguments: [
346+
methodName,
347+
],
348+
);
339349
return;
340350
}
341351

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,31 @@ class PrefixExpressionResolver {
4949
return;
5050
}
5151

52+
if (node.operand case AugmentedExpressionImpl operand) {
53+
var methodName = _getPrefixOperator(node);
54+
var augmentation = _resolver.enclosingAugmentation;
55+
var augmentationTarget = augmentation?.augmentationTarget;
56+
if (augmentationTarget case MethodElement augmentationTarget) {
57+
if (augmentationTarget.name == methodName) {
58+
operand.element = augmentationTarget;
59+
operand.staticType = _resolver.thisType ?? InvalidTypeImpl.instance;
60+
node.staticElement = augmentationTarget;
61+
node.staticType = augmentationTarget.returnType;
62+
return;
63+
}
64+
}
65+
_errorReporter.atToken(
66+
operand.augmentedKeyword,
67+
CompileTimeErrorCode.AUGMENTED_EXPRESSION_NOT_OPERATOR,
68+
arguments: [
69+
methodName,
70+
],
71+
);
72+
operand.staticType = InvalidTypeImpl.instance;
73+
node.staticType = InvalidTypeImpl.instance;
74+
return;
75+
}
76+
5277
var operand = node.operand;
5378
if (operator.isIncrementOperator) {
5479
var operandResolution = _resolver.resolveForWrite(

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,15 @@ class CompileTimeErrorCode extends AnalyzerErrorCode {
270270
"Try updating the URI to reference the augmented library.",
271271
);
272272

273+
/// Parameters:
274+
/// 0: the lexeme of the operator.
275+
static const CompileTimeErrorCode AUGMENTED_EXPRESSION_NOT_OPERATOR =
276+
CompileTimeErrorCode(
277+
'AUGMENTED_EXPRESSION_NOT_OPERATOR',
278+
"The enclosing augmentation doesn't augment the operator '{0}'.",
279+
correctionMessage: "Try augmenting or invoking the correct operator.",
280+
);
281+
273282
/// No parameters.
274283
static const CompileTimeErrorCode AWAIT_IN_LATE_LOCAL_VARIABLE_INITIALIZER =
275284
CompileTimeErrorCode(

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ const List<ErrorCode> errorCodeValues = [
7070
CompileTimeErrorCode.AUGMENTATION_WITHOUT_DECLARATION,
7171
CompileTimeErrorCode.AUGMENTATION_WITHOUT_IMPORT,
7272
CompileTimeErrorCode.AUGMENTATION_WITHOUT_LIBRARY,
73+
CompileTimeErrorCode.AUGMENTED_EXPRESSION_NOT_OPERATOR,
7374
CompileTimeErrorCode.AWAIT_IN_LATE_LOCAL_VARIABLE_INITIALIZER,
7475
CompileTimeErrorCode.AWAIT_IN_WRONG_CONTEXT,
7576
CompileTimeErrorCode.AWAIT_OF_INCOMPATIBLE_TYPE,

pkg/analyzer/messages.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,6 +1163,13 @@ CompileTimeErrorCode:
11631163
problemMessage: The URI does not resolve to a library.
11641164
correctionMessage: Try updating the URI to reference the augmented library.
11651165
hasPublishedDocs: false
1166+
AUGMENTED_EXPRESSION_NOT_OPERATOR:
1167+
problemMessage: The enclosing augmentation doesn't augment the operator '{0}'.
1168+
correctionMessage: Try augmenting or invoking the correct operator.
1169+
hasPublishedDocs: false
1170+
comment: |-
1171+
Parameters:
1172+
0: the lexeme of the operator.
11661173
AWAIT_IN_LATE_LOCAL_VARIABLE_INITIALIZER:
11671174
problemMessage: "The 'await' expression can't be used in a 'late' local variable's initializer."
11681175
correctionMessage: "Try removing the 'late' modifier, or rewriting the initializer without using the 'await' expression."

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

Lines changed: 114 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -21,78 +21,6 @@ main() {
2121
@reflectiveTest
2222
class BinaryExpressionResolutionTest extends PubPackageResolutionTest
2323
with BinaryExpressionResolutionTestCases {
24-
test_augmentedExpression_class_method() async {
25-
await assertErrorsInCode('''
26-
class A {
27-
int operator+(Object? a) {
28-
return augmented + 0;
29-
}
30-
}
31-
''', [
32-
error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 50, 9),
33-
]);
34-
35-
var node = findNode.singleReturnStatement;
36-
assertResolvedNodeText(node, r'''
37-
ReturnStatement
38-
returnKeyword: return
39-
expression: BinaryExpression
40-
leftOperand: SimpleIdentifier
41-
token: augmented
42-
staticElement: <null>
43-
staticType: InvalidType
44-
operator: +
45-
rightOperand: IntegerLiteral
46-
literal: 0
47-
parameter: <null>
48-
staticType: int
49-
staticElement: <null>
50-
staticInvokeType: null
51-
staticType: InvalidType
52-
semicolon: ;
53-
''');
54-
}
55-
56-
test_augmentedExpression_class_method_augmentation() async {
57-
newFile('$testPackageLibPath/a.dart', r'''
58-
import augment 'test.dart';
59-
60-
class A {
61-
int operator+(Object? a) => 0;
62-
}
63-
''');
64-
65-
await assertNoErrorsInCode('''
66-
augment library 'a.dart';
67-
68-
augment class A {
69-
augment int operator+(Object? a) {
70-
return augmented + 0;
71-
}
72-
}
73-
''');
74-
75-
var node = findNode.singleReturnStatement;
76-
assertResolvedNodeText(node, r'''
77-
ReturnStatement
78-
returnKeyword: return
79-
expression: BinaryExpression
80-
leftOperand: AugmentedExpression
81-
augmentedKeyword: augmented
82-
element: self::@class::A::@method::+
83-
staticType: A
84-
operator: +
85-
rightOperand: IntegerLiteral
86-
literal: 0
87-
parameter: self::@class::A::@method::+::@parameter::a
88-
staticType: int
89-
staticElement: self::@class::A::@method::+
90-
staticInvokeType: int Function(Object?)
91-
staticType: int
92-
semicolon: ;
93-
''');
94-
}
95-
9624
test_eqEq_alwaysBool() async {
9725
await assertNoErrorsInCode(r'''
9826
extension type MyBool(bool it) implements bool {}
@@ -445,6 +373,120 @@ BinaryExpression
445373
''');
446374
}
447375

376+
test_plus_augmentedExpression_augments_nothing() async {
377+
await assertErrorsInCode('''
378+
class A {
379+
int operator+(Object? a) {
380+
return augmented + 0;
381+
}
382+
}
383+
''', [
384+
error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 50, 9),
385+
]);
386+
387+
var node = findNode.singleReturnStatement;
388+
assertResolvedNodeText(node, r'''
389+
ReturnStatement
390+
returnKeyword: return
391+
expression: BinaryExpression
392+
leftOperand: SimpleIdentifier
393+
token: augmented
394+
staticElement: <null>
395+
staticType: InvalidType
396+
operator: +
397+
rightOperand: IntegerLiteral
398+
literal: 0
399+
parameter: <null>
400+
staticType: int
401+
staticElement: <null>
402+
staticInvokeType: null
403+
staticType: InvalidType
404+
semicolon: ;
405+
''');
406+
}
407+
408+
test_plus_augmentedExpression_augments_plus() async {
409+
newFile('$testPackageLibPath/a.dart', r'''
410+
import augment 'test.dart';
411+
412+
class A {
413+
int operator+(Object? a) => 0;
414+
}
415+
''');
416+
417+
await assertNoErrorsInCode('''
418+
augment library 'a.dart';
419+
420+
augment class A {
421+
augment int operator+(Object? a) {
422+
return augmented + 0;
423+
}
424+
}
425+
''');
426+
427+
var node = findNode.singleReturnStatement;
428+
assertResolvedNodeText(node, r'''
429+
ReturnStatement
430+
returnKeyword: return
431+
expression: BinaryExpression
432+
leftOperand: AugmentedExpression
433+
augmentedKeyword: augmented
434+
element: self::@class::A::@method::+
435+
staticType: A
436+
operator: +
437+
rightOperand: IntegerLiteral
438+
literal: 0
439+
parameter: self::@class::A::@method::+::@parameter::a
440+
staticType: int
441+
staticElement: self::@class::A::@method::+
442+
staticInvokeType: int Function(Object?)
443+
staticType: int
444+
semicolon: ;
445+
''');
446+
}
447+
448+
test_plus_augmentedExpression_augments_unaryMinus() async {
449+
newFile('$testPackageLibPath/a.dart', r'''
450+
import augment 'test.dart';
451+
452+
class A {
453+
int operator-() => 0;
454+
}
455+
''');
456+
457+
await assertErrorsInCode('''
458+
augment library 'a.dart';
459+
460+
augment class A {
461+
augment int operator-() {
462+
return augmented + 0;
463+
}
464+
}
465+
''', [
466+
error(CompileTimeErrorCode.AUGMENTED_EXPRESSION_NOT_OPERATOR, 84, 9),
467+
]);
468+
469+
var node = findNode.singleReturnStatement;
470+
assertResolvedNodeText(node, r'''
471+
ReturnStatement
472+
returnKeyword: return
473+
expression: BinaryExpression
474+
leftOperand: AugmentedExpression
475+
augmentedKeyword: augmented
476+
element: <null>
477+
staticType: A
478+
operator: +
479+
rightOperand: IntegerLiteral
480+
literal: 0
481+
parameter: <null>
482+
staticType: int
483+
staticElement: <null>
484+
staticInvokeType: null
485+
staticType: InvalidType
486+
semicolon: ;
487+
''');
488+
}
489+
448490
test_plus_extensionType_int() async {
449491
await assertNoErrorsInCode('''
450492
extension type Int(int i) implements int {

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

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,41 @@ PrefixExpression
345345
''');
346346
}
347347

348+
test_minus_augmentedExpression_augments_minus() async {
349+
newFile('$testPackageLibPath/a.dart', r'''
350+
import augment 'test.dart';
351+
352+
class A {
353+
int operator-() => 0;
354+
}
355+
''');
356+
357+
await assertNoErrorsInCode('''
358+
augment library 'a.dart';
359+
360+
augment class A {
361+
augment int operator-() {
362+
return -augmented;
363+
}
364+
}
365+
''');
366+
367+
var node = findNode.singleReturnStatement;
368+
assertResolvedNodeText(node, r'''
369+
ReturnStatement
370+
returnKeyword: return
371+
expression: PrefixExpression
372+
operator: -
373+
operand: AugmentedExpression
374+
augmentedKeyword: augmented
375+
element: self::@class::A::@method::unary-
376+
staticType: A
377+
staticElement: self::@class::A::@method::unary-
378+
staticType: int
379+
semicolon: ;
380+
''');
381+
}
382+
348383
test_minus_dynamicIdentifier() async {
349384
await assertNoErrorsInCode(r'''
350385
void f(dynamic a) {
@@ -1093,6 +1128,43 @@ PrefixExpression
10931128
''');
10941129
}
10951130

1131+
test_tilde_augmentedExpression_augments_minus() async {
1132+
newFile('$testPackageLibPath/a.dart', r'''
1133+
import augment 'test.dart';
1134+
1135+
class A {
1136+
int operator-() => 0;
1137+
}
1138+
''');
1139+
1140+
await assertErrorsInCode('''
1141+
augment library 'a.dart';
1142+
1143+
augment class A {
1144+
augment int operator-() {
1145+
return ~augmented;
1146+
}
1147+
}
1148+
''', [
1149+
error(CompileTimeErrorCode.AUGMENTED_EXPRESSION_NOT_OPERATOR, 85, 9),
1150+
]);
1151+
1152+
var node = findNode.singleReturnStatement;
1153+
assertResolvedNodeText(node, r'''
1154+
ReturnStatement
1155+
returnKeyword: return
1156+
expression: PrefixExpression
1157+
operator: ~
1158+
operand: AugmentedExpression
1159+
augmentedKeyword: augmented
1160+
element: <null>
1161+
staticType: InvalidType
1162+
staticElement: <null>
1163+
staticType: InvalidType
1164+
semicolon: ;
1165+
''');
1166+
}
1167+
10961168
test_tilde_no_nullShorting() async {
10971169
await assertErrorsInCode(r'''
10981170
class A {

0 commit comments

Comments
 (0)