Support prefix ++ and -- operators

Change-Id: I2437469ad67721736a6b4800f0134e0f358a7dbf
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/106970
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/nnbd_migration/lib/src/graph_builder.dart b/pkg/nnbd_migration/lib/src/graph_builder.dart
index 412a3ba..2360633 100644
--- a/pkg/nnbd_migration/lib/src/graph_builder.dart
+++ b/pkg/nnbd_migration/lib/src/graph_builder.dart
@@ -572,8 +572,25 @@
   DecoratedType visitPrefixExpression(PrefixExpression node) {
     /* DecoratedType operandType = */
     _handleAssignment(_notNullType, node.operand);
-    if (node.operator.type == TokenType.BANG) {
+    var operatorType = node.operator.type;
+    if (operatorType == TokenType.BANG) {
       return _nonNullableBoolType;
+    } else if (operatorType == TokenType.PLUS_PLUS ||
+        operatorType == TokenType.MINUS_MINUS) {
+      var callee = node.staticElement;
+      if (callee is ClassMemberElement &&
+          callee.enclosingElement.typeParameters.isNotEmpty) {
+        // TODO(paulberry)
+        _unimplemented(node,
+            'Operator ${operatorType.lexeme} defined on a class with type parameters');
+      }
+      if (callee == null) {
+        // TODO(paulberry)
+        _unimplemented(node, 'Unresolved operator ${operatorType.lexeme}');
+      }
+      var calleeType = getOrComputeElementType(callee);
+      // TODO(paulberry): substitute if necessary
+      return calleeType.returnType;
     }
     // TODO(brianwilkerson) The remaining cases are invocations.
     _unimplemented(
diff --git a/pkg/nnbd_migration/test/graph_builder_test.dart b/pkg/nnbd_migration/test/graph_builder_test.dart
index 7835703..5b408e3 100644
--- a/pkg/nnbd_migration/test/graph_builder_test.dart
+++ b/pkg/nnbd_migration/test/graph_builder_test.dart
@@ -1335,7 +1335,7 @@
     assertEdge(decoratedTypeAnnotation('C c').node, never, hard: true);
   }
 
-  test_prefixExpression_bang2() async {
+  test_prefixExpression_bang() async {
     await analyze('''
 bool f(bool b) {
   return !b;
@@ -1350,6 +1350,36 @@
     assertEdge(never, return_f, hard: false);
   }
 
+  test_prefixExpression_minusMinus() async {
+    await analyze('''
+int f(int i) {
+  return --i;
+}
+''');
+
+    var declaration = decoratedTypeAnnotation('int i').node;
+    var use = checkExpression('i;');
+    assertNullCheck(use, assertEdge(declaration, never, hard: true));
+
+    var returnType = decoratedTypeAnnotation('int f').node;
+    assertEdge(never, returnType, hard: false);
+  }
+
+  test_prefixExpression_plusPlus() async {
+    await analyze('''
+int f(int i) {
+  return ++i;
+}
+''');
+
+    var declaration = decoratedTypeAnnotation('int i').node;
+    var use = checkExpression('i;');
+    assertNullCheck(use, assertEdge(declaration, never, hard: true));
+
+    var returnType = decoratedTypeAnnotation('int f').node;
+    assertEdge(never, returnType, hard: false);
+  }
+
   test_propertyAccess_return_type() async {
     await analyze('''
 class C {