Augment. Resolve PrefixExpression.
Change-Id: I947b0fee1b4f060bfe168a0f9138a6df4889d1d8
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/365544
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
index c14cbad..0989c69 100644
--- a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
+++ b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
@@ -223,6 +223,8 @@
The fix is to add `import augment`.
CompileTimeErrorCode.AUGMENTATION_WITHOUT_LIBRARY:
status: noFix
+CompileTimeErrorCode.AUGMENTED_EXPRESSION_NOT_OPERATOR:
+ status: noFix
CompileTimeErrorCode.AWAIT_IN_LATE_LOCAL_VARIABLE_INITIALIZER:
status: needsFix
notes: |-
diff --git a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
index 5adaacf..decf6f4 100644
--- a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
@@ -332,10 +332,20 @@
var augmentation = _resolver.enclosingAugmentation;
var augmentationTarget = augmentation?.augmentationTarget;
if (augmentationTarget case MethodElement augmentationTarget) {
- leftOperand.element = augmentationTarget;
- node.staticElement = augmentationTarget;
- node.staticInvokeType = augmentationTarget.type;
+ if (augmentationTarget.name == methodName) {
+ leftOperand.element = augmentationTarget;
+ node.staticElement = augmentationTarget;
+ node.staticInvokeType = augmentationTarget.type;
+ return;
+ }
}
+ _errorReporter.atToken(
+ leftOperand.augmentedKeyword,
+ CompileTimeErrorCode.AUGMENTED_EXPRESSION_NOT_OPERATOR,
+ arguments: [
+ methodName,
+ ],
+ );
return;
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
index 39a6404..33e559d 100644
--- a/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
@@ -49,6 +49,31 @@
return;
}
+ if (node.operand case AugmentedExpressionImpl operand) {
+ var methodName = _getPrefixOperator(node);
+ var augmentation = _resolver.enclosingAugmentation;
+ var augmentationTarget = augmentation?.augmentationTarget;
+ if (augmentationTarget case MethodElement augmentationTarget) {
+ if (augmentationTarget.name == methodName) {
+ operand.element = augmentationTarget;
+ operand.staticType = _resolver.thisType ?? InvalidTypeImpl.instance;
+ node.staticElement = augmentationTarget;
+ node.staticType = augmentationTarget.returnType;
+ return;
+ }
+ }
+ _errorReporter.atToken(
+ operand.augmentedKeyword,
+ CompileTimeErrorCode.AUGMENTED_EXPRESSION_NOT_OPERATOR,
+ arguments: [
+ methodName,
+ ],
+ );
+ operand.staticType = InvalidTypeImpl.instance;
+ node.staticType = InvalidTypeImpl.instance;
+ return;
+ }
+
var operand = node.operand;
if (operator.isIncrementOperator) {
var operandResolution = _resolver.resolveForWrite(
diff --git a/pkg/analyzer/lib/src/error/codes.g.dart b/pkg/analyzer/lib/src/error/codes.g.dart
index 8e7ace6..63a80c8 100644
--- a/pkg/analyzer/lib/src/error/codes.g.dart
+++ b/pkg/analyzer/lib/src/error/codes.g.dart
@@ -270,6 +270,15 @@
"Try updating the URI to reference the augmented library.",
);
+ /// Parameters:
+ /// 0: the lexeme of the operator.
+ static const CompileTimeErrorCode AUGMENTED_EXPRESSION_NOT_OPERATOR =
+ CompileTimeErrorCode(
+ 'AUGMENTED_EXPRESSION_NOT_OPERATOR',
+ "The enclosing augmentation doesn't augment the operator '{0}'.",
+ correctionMessage: "Try augmenting or invoking the correct operator.",
+ );
+
/// No parameters.
static const CompileTimeErrorCode AWAIT_IN_LATE_LOCAL_VARIABLE_INITIALIZER =
CompileTimeErrorCode(
diff --git a/pkg/analyzer/lib/src/error/error_code_values.g.dart b/pkg/analyzer/lib/src/error/error_code_values.g.dart
index a478aec..400a387 100644
--- a/pkg/analyzer/lib/src/error/error_code_values.g.dart
+++ b/pkg/analyzer/lib/src/error/error_code_values.g.dart
@@ -70,6 +70,7 @@
CompileTimeErrorCode.AUGMENTATION_WITHOUT_DECLARATION,
CompileTimeErrorCode.AUGMENTATION_WITHOUT_IMPORT,
CompileTimeErrorCode.AUGMENTATION_WITHOUT_LIBRARY,
+ CompileTimeErrorCode.AUGMENTED_EXPRESSION_NOT_OPERATOR,
CompileTimeErrorCode.AWAIT_IN_LATE_LOCAL_VARIABLE_INITIALIZER,
CompileTimeErrorCode.AWAIT_IN_WRONG_CONTEXT,
CompileTimeErrorCode.AWAIT_OF_INCOMPATIBLE_TYPE,
diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml
index 5c814c9..9e76b95 100644
--- a/pkg/analyzer/messages.yaml
+++ b/pkg/analyzer/messages.yaml
@@ -1163,6 +1163,13 @@
problemMessage: The URI does not resolve to a library.
correctionMessage: Try updating the URI to reference the augmented library.
hasPublishedDocs: false
+ AUGMENTED_EXPRESSION_NOT_OPERATOR:
+ problemMessage: The enclosing augmentation doesn't augment the operator '{0}'.
+ correctionMessage: Try augmenting or invoking the correct operator.
+ hasPublishedDocs: false
+ comment: |-
+ Parameters:
+ 0: the lexeme of the operator.
AWAIT_IN_LATE_LOCAL_VARIABLE_INITIALIZER:
problemMessage: "The 'await' expression can't be used in a 'late' local variable's initializer."
correctionMessage: "Try removing the 'late' modifier, or rewriting the initializer without using the 'await' expression."
diff --git a/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart
index e2f9424..57fe97d 100644
--- a/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart
@@ -21,78 +21,6 @@
@reflectiveTest
class BinaryExpressionResolutionTest extends PubPackageResolutionTest
with BinaryExpressionResolutionTestCases {
- test_augmentedExpression_class_method() async {
- await assertErrorsInCode('''
-class A {
- int operator+(Object? a) {
- return augmented + 0;
- }
-}
-''', [
- error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 50, 9),
- ]);
-
- var node = findNode.singleReturnStatement;
- assertResolvedNodeText(node, r'''
-ReturnStatement
- returnKeyword: return
- expression: BinaryExpression
- leftOperand: SimpleIdentifier
- token: augmented
- staticElement: <null>
- staticType: InvalidType
- operator: +
- rightOperand: IntegerLiteral
- literal: 0
- parameter: <null>
- staticType: int
- staticElement: <null>
- staticInvokeType: null
- staticType: InvalidType
- semicolon: ;
-''');
- }
-
- test_augmentedExpression_class_method_augmentation() async {
- newFile('$testPackageLibPath/a.dart', r'''
-import augment 'test.dart';
-
-class A {
- int operator+(Object? a) => 0;
-}
-''');
-
- await assertNoErrorsInCode('''
-augment library 'a.dart';
-
-augment class A {
- augment int operator+(Object? a) {
- return augmented + 0;
- }
-}
-''');
-
- var node = findNode.singleReturnStatement;
- assertResolvedNodeText(node, r'''
-ReturnStatement
- returnKeyword: return
- expression: BinaryExpression
- leftOperand: AugmentedExpression
- augmentedKeyword: augmented
- element: self::@class::A::@method::+
- staticType: A
- operator: +
- rightOperand: IntegerLiteral
- literal: 0
- parameter: self::@class::A::@method::+::@parameter::a
- staticType: int
- staticElement: self::@class::A::@method::+
- staticInvokeType: int Function(Object?)
- staticType: int
- semicolon: ;
-''');
- }
-
test_eqEq_alwaysBool() async {
await assertNoErrorsInCode(r'''
extension type MyBool(bool it) implements bool {}
@@ -445,6 +373,120 @@
''');
}
+ test_plus_augmentedExpression_augments_nothing() async {
+ await assertErrorsInCode('''
+class A {
+ int operator+(Object? a) {
+ return augmented + 0;
+ }
+}
+''', [
+ error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 50, 9),
+ ]);
+
+ var node = findNode.singleReturnStatement;
+ assertResolvedNodeText(node, r'''
+ReturnStatement
+ returnKeyword: return
+ expression: BinaryExpression
+ leftOperand: SimpleIdentifier
+ token: augmented
+ staticElement: <null>
+ staticType: InvalidType
+ operator: +
+ rightOperand: IntegerLiteral
+ literal: 0
+ parameter: <null>
+ staticType: int
+ staticElement: <null>
+ staticInvokeType: null
+ staticType: InvalidType
+ semicolon: ;
+''');
+ }
+
+ test_plus_augmentedExpression_augments_plus() async {
+ newFile('$testPackageLibPath/a.dart', r'''
+import augment 'test.dart';
+
+class A {
+ int operator+(Object? a) => 0;
+}
+''');
+
+ await assertNoErrorsInCode('''
+augment library 'a.dart';
+
+augment class A {
+ augment int operator+(Object? a) {
+ return augmented + 0;
+ }
+}
+''');
+
+ var node = findNode.singleReturnStatement;
+ assertResolvedNodeText(node, r'''
+ReturnStatement
+ returnKeyword: return
+ expression: BinaryExpression
+ leftOperand: AugmentedExpression
+ augmentedKeyword: augmented
+ element: self::@class::A::@method::+
+ staticType: A
+ operator: +
+ rightOperand: IntegerLiteral
+ literal: 0
+ parameter: self::@class::A::@method::+::@parameter::a
+ staticType: int
+ staticElement: self::@class::A::@method::+
+ staticInvokeType: int Function(Object?)
+ staticType: int
+ semicolon: ;
+''');
+ }
+
+ test_plus_augmentedExpression_augments_unaryMinus() async {
+ newFile('$testPackageLibPath/a.dart', r'''
+import augment 'test.dart';
+
+class A {
+ int operator-() => 0;
+}
+''');
+
+ await assertErrorsInCode('''
+augment library 'a.dart';
+
+augment class A {
+ augment int operator-() {
+ return augmented + 0;
+ }
+}
+''', [
+ error(CompileTimeErrorCode.AUGMENTED_EXPRESSION_NOT_OPERATOR, 84, 9),
+ ]);
+
+ var node = findNode.singleReturnStatement;
+ assertResolvedNodeText(node, r'''
+ReturnStatement
+ returnKeyword: return
+ expression: BinaryExpression
+ leftOperand: AugmentedExpression
+ augmentedKeyword: augmented
+ element: <null>
+ staticType: A
+ operator: +
+ rightOperand: IntegerLiteral
+ literal: 0
+ parameter: <null>
+ staticType: int
+ staticElement: <null>
+ staticInvokeType: null
+ staticType: InvalidType
+ semicolon: ;
+''');
+ }
+
test_plus_extensionType_int() async {
await assertNoErrorsInCode('''
extension type Int(int i) implements int {
diff --git a/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart
index 58f1a1d..e13ce31 100644
--- a/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart
@@ -345,6 +345,41 @@
''');
}
+ test_minus_augmentedExpression_augments_minus() async {
+ newFile('$testPackageLibPath/a.dart', r'''
+import augment 'test.dart';
+
+class A {
+ int operator-() => 0;
+}
+''');
+
+ await assertNoErrorsInCode('''
+augment library 'a.dart';
+
+augment class A {
+ augment int operator-() {
+ return -augmented;
+ }
+}
+''');
+
+ var node = findNode.singleReturnStatement;
+ assertResolvedNodeText(node, r'''
+ReturnStatement
+ returnKeyword: return
+ expression: PrefixExpression
+ operator: -
+ operand: AugmentedExpression
+ augmentedKeyword: augmented
+ element: self::@class::A::@method::unary-
+ staticType: A
+ staticElement: self::@class::A::@method::unary-
+ staticType: int
+ semicolon: ;
+''');
+ }
+
test_minus_dynamicIdentifier() async {
await assertNoErrorsInCode(r'''
void f(dynamic a) {
@@ -1093,6 +1128,43 @@
''');
}
+ test_tilde_augmentedExpression_augments_minus() async {
+ newFile('$testPackageLibPath/a.dart', r'''
+import augment 'test.dart';
+
+class A {
+ int operator-() => 0;
+}
+''');
+
+ await assertErrorsInCode('''
+augment library 'a.dart';
+
+augment class A {
+ augment int operator-() {
+ return ~augmented;
+ }
+}
+''', [
+ error(CompileTimeErrorCode.AUGMENTED_EXPRESSION_NOT_OPERATOR, 85, 9),
+ ]);
+
+ var node = findNode.singleReturnStatement;
+ assertResolvedNodeText(node, r'''
+ReturnStatement
+ returnKeyword: return
+ expression: PrefixExpression
+ operator: ~
+ operand: AugmentedExpression
+ augmentedKeyword: augmented
+ element: <null>
+ staticType: InvalidType
+ staticElement: <null>
+ staticType: InvalidType
+ semicolon: ;
+''');
+ }
+
test_tilde_no_nullShorting() async {
await assertErrorsInCode(r'''
class A {