Support postfix ++ and -- operators

Change-Id: Ib16f30a8b5d6e94b1a6ec0cddf5c88f58188ea83
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/107021
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 2360633..96097494 100644
--- a/pkg/nnbd_migration/lib/src/graph_builder.dart
+++ b/pkg/nnbd_migration/lib/src/graph_builder.dart
@@ -554,8 +554,27 @@
 
   @override
   DecoratedType visitPostfixExpression(PostfixExpression node) {
-    // TODO(brianwilkerson)
-    _unimplemented(node, 'PostfixExpression');
+    var operatorType = node.operator.type;
+    if (operatorType == TokenType.PLUS_PLUS ||
+        operatorType == TokenType.MINUS_MINUS) {
+      _handleAssignment(_notNullType, node.operand);
+      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;
+    }
+    _unimplemented(
+        node, 'Postfix expression with operator ${node.operator.lexeme}');
   }
 
   @override
diff --git a/pkg/nnbd_migration/test/graph_builder_test.dart b/pkg/nnbd_migration/test/graph_builder_test.dart
index 5b408e3..9d6d8b7 100644
--- a/pkg/nnbd_migration/test/graph_builder_test.dart
+++ b/pkg/nnbd_migration/test/graph_builder_test.dart
@@ -1284,6 +1284,36 @@
         assertEdge(always, decoratedTypeAnnotation('int').node, hard: false));
   }
 
+  test_postfixExpression_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_postfixExpression_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_prefixedIdentifier_field_type() async {
     await analyze('''
 class C {