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 {