Migration: support index expressions.

Change-Id: Ie43b5045df75b325a74243a8ae8801387c73c64a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/104883
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
diff --git a/pkg/analysis_server/lib/src/nullability/graph_builder.dart b/pkg/analysis_server/lib/src/nullability/graph_builder.dart
index ee4c725..7414beb 100644
--- a/pkg/analysis_server/lib/src/nullability/graph_builder.dart
+++ b/pkg/analysis_server/lib/src/nullability/graph_builder.dart
@@ -292,6 +292,22 @@
   }
 
   @override
+  DecoratedType visitIndexExpression(IndexExpression node) {
+    DecoratedType targetType;
+    if (node.target != null) {
+      targetType = _handleAssignment(_notNullType, node.target);
+    }
+    var callee = node.staticElement;
+    if (callee == null) {
+      throw new UnimplementedError('TODO(paulberry)');
+    }
+    var calleeType = getOrComputeElementType(callee, targetType: targetType);
+    // TODO(paulberry): substitute if necessary
+    _handleAssignment(calleeType.positionalParameters[0], node.index);
+    return calleeType.returnType;
+  }
+
+  @override
   DecoratedType visitIntegerLiteral(IntegerLiteral node) {
     return DecoratedType(node.staticType, NullabilityNode.never);
   }
diff --git a/pkg/analysis_server/test/src/nullability/migration_visitor_test.dart b/pkg/analysis_server/test/src/nullability/migration_visitor_test.dart
index e5e2877..79c3227 100644
--- a/pkg/analysis_server/test/src/nullability/migration_visitor_test.dart
+++ b/pkg/analysis_server/test/src/nullability/migration_visitor_test.dart
@@ -563,6 +563,40 @@
         contextNode: nullable_return);
   }
 
+  test_indexExpression_index() async {
+    await analyze('''
+class C {
+  int operator[](int i) => 1;
+}
+int f(C c, int j) => c[j];
+''');
+    assertEdge(decoratedTypeAnnotation('int j').node,
+        decoratedTypeAnnotation('int i').node,
+        hard: true);
+  }
+
+  test_indexExpression_return_type() async {
+    await analyze('''
+class C {
+  int operator[](int i) => 1;
+}
+int f(C c) => c[0];
+''');
+    assertEdge(decoratedTypeAnnotation('int operator').node,
+        decoratedTypeAnnotation('int f').node,
+        hard: false);
+  }
+
+  test_indexExpression_target_check() async {
+    await analyze('''
+class C {
+  int operator[](int i) => 1;
+}
+int f(C c) => c[0];
+''');
+    assertNullCheck(checkExpression('c['), decoratedTypeAnnotation('C c').node);
+  }
+
   test_intLiteral() async {
     await analyze('''
 int f() {
diff --git a/pkg/analysis_server/test/src/nullability/provisional_api_test.dart b/pkg/analysis_server/test/src/nullability/provisional_api_test.dart
index eb0d189..fca6f2c 100644
--- a/pkg/analysis_server/test/src/nullability/provisional_api_test.dart
+++ b/pkg/analysis_server/test/src/nullability/provisional_api_test.dart
@@ -264,6 +264,38 @@
     await _checkSingleFileChanges(content, expected);
   }
 
+  test_data_flow_indexed_get_index_value() async {
+    var content = '''
+class C {
+  int operator[](int i) => 1;
+}
+int f(C c) => c[null];
+''';
+    var expected = '''
+class C {
+  int operator[](int? i) => 1;
+}
+int f(C c) => c[null];
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  test_data_flow_indexed_get_value() async {
+    var content = '''
+class C {
+  int operator[](int i) => null;
+}
+int f(C c) => c[0];
+''';
+    var expected = '''
+class C {
+  int? operator[](int i) => null;
+}
+int? f(C c) => c[0];
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
   test_data_flow_inward() async {
     var content = '''
 int f(int i) => 0;