fix indexed super constructor

This fixes a bug where the AstBuilder fails
given a constructor of the form:

class C {
  C() : super()[];
}

In the process, 2 buildInitializer methods were extracted from
the AstBuilder.endInitializers method.

Fix https://github.com/dart-lang/sdk/issues/37285

Change-Id: Icacf28b2ed0eff9b7168c97ee0c03d78e5fcd68b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/106500
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Dan Rubel <danrubel@google.com>
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index abfe057..955d11e 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -327,6 +327,116 @@
     }
   }
 
+  ConstructorInitializer buildInitializer(Object initializerObject) {
+    if (initializerObject is FunctionExpressionInvocation) {
+      Expression function = initializerObject.function;
+      if (function is SuperExpression) {
+        return ast.superConstructorInvocation(
+            function.superKeyword, null, null, initializerObject.argumentList);
+      } else {
+        return ast.redirectingConstructorInvocation(
+            (function as ThisExpression).thisKeyword,
+            null,
+            null,
+            initializerObject.argumentList);
+      }
+    }
+
+    if (initializerObject is MethodInvocation) {
+      Expression target = initializerObject.target;
+      if (target is SuperExpression) {
+        return ast.superConstructorInvocation(
+            target.superKeyword,
+            initializerObject.operator,
+            initializerObject.methodName,
+            initializerObject.argumentList);
+      }
+      if (target is ThisExpression) {
+        return ast.redirectingConstructorInvocation(
+            target.thisKeyword,
+            initializerObject.operator,
+            initializerObject.methodName,
+            initializerObject.argumentList);
+      }
+      return buildInitializerTargetExpressionRecovery(
+          target, initializerObject);
+    }
+
+    if (initializerObject is PropertyAccess) {
+      return buildInitializerTargetExpressionRecovery(
+          initializerObject.target, initializerObject);
+    }
+
+    if (initializerObject is AssignmentExpression) {
+      Token thisKeyword;
+      Token period;
+      SimpleIdentifier fieldName;
+      Expression left = initializerObject.leftHandSide;
+      if (left is PropertyAccess) {
+        Expression target = left.target;
+        if (target is ThisExpression) {
+          thisKeyword = target.thisKeyword;
+          period = left.operator;
+        } else {
+          assert(target is SuperExpression);
+          // Recovery:
+          // Parser has reported FieldInitializedOutsideDeclaringClass.
+        }
+        fieldName = left.propertyName;
+      } else if (left is SimpleIdentifier) {
+        fieldName = left;
+      } else {
+        // Recovery:
+        // Parser has reported invalid assignment.
+        SuperExpression superExpression = left;
+        fieldName = ast.simpleIdentifier(superExpression.superKeyword);
+      }
+      return ast.constructorFieldInitializer(thisKeyword, period, fieldName,
+          initializerObject.operator, initializerObject.rightHandSide);
+    }
+
+    if (initializerObject is AssertInitializer) {
+      return initializerObject;
+    }
+
+    if (initializerObject is IndexExpression) {
+      return buildInitializerTargetExpressionRecovery(
+          initializerObject.target, initializerObject);
+    }
+
+    throw new UnsupportedError('unsupported initializer:'
+        ' ${initializerObject.runtimeType} :: $initializerObject');
+  }
+
+  AstNode buildInitializerTargetExpressionRecovery(
+      Expression target, Object initializerObject) {
+    if (target is FunctionExpressionInvocation) {
+      Expression targetFunct = target.function;
+      if (targetFunct is SuperExpression) {
+        // TODO(danrubel): Consider generating this error in the parser
+        // This error is also reported in the body builder
+        handleRecoverableError(messageInvalidSuperInInitializer,
+            targetFunct.superKeyword, targetFunct.superKeyword);
+        return ast.superConstructorInvocation(
+            targetFunct.superKeyword, null, null, target.argumentList);
+      }
+      if (targetFunct is ThisExpression) {
+        // TODO(danrubel): Consider generating this error in the parser
+        // This error is also reported in the body builder
+        handleRecoverableError(messageInvalidThisInInitializer,
+            targetFunct.thisKeyword, targetFunct.thisKeyword);
+        return ast.redirectingConstructorInvocation(
+            targetFunct.thisKeyword, null, null, target.argumentList);
+      }
+      throw new UnsupportedError('unsupported initializer:'
+          ' ${initializerObject.runtimeType} :: $initializerObject'
+          ' %% targetFunct : ${targetFunct.runtimeType} :: $targetFunct');
+    }
+    throw new UnsupportedError('unsupported initializer:'
+        ' ${initializerObject.runtimeType} :: $initializerObject'
+        ' %% target : ${target.runtimeType} :: $target');
+  }
+
   void checkFieldFormalParameters(FormalParameterList parameters) {
     if (parameters?.parameters != null) {
       parameters.parameters.forEach((FormalParameter param) {
@@ -1221,122 +1331,12 @@
 
     var initializers = <ConstructorInitializer>[];
     for (Object initializerObject in initializerObjects) {
-      if (initializerObject is FunctionExpressionInvocation) {
-        Expression function = initializerObject.function;
-        if (function is SuperExpression) {
-          initializers.add(ast.superConstructorInvocation(function.superKeyword,
-              null, null, initializerObject.argumentList));
-        } else {
-          initializers.add(ast.redirectingConstructorInvocation(
-              (function as ThisExpression).thisKeyword,
-              null,
-              null,
-              initializerObject.argumentList));
-        }
-      } else if (initializerObject is MethodInvocation) {
-        Expression target = initializerObject.target;
-        if (target is SuperExpression) {
-          initializers.add(ast.superConstructorInvocation(
-              target.superKeyword,
-              initializerObject.operator,
-              initializerObject.methodName,
-              initializerObject.argumentList));
-        } else if (target is ThisExpression) {
-          initializers.add(ast.redirectingConstructorInvocation(
-              target.thisKeyword,
-              initializerObject.operator,
-              initializerObject.methodName,
-              initializerObject.argumentList));
-        } else {
-          // Recovery: Invalid initializer
-          if (target is FunctionExpressionInvocation) {
-            var targetFunct = target.function;
-            if (targetFunct is SuperExpression) {
-              initializers.add(ast.superConstructorInvocation(
-                  targetFunct.superKeyword, null, null, target.argumentList));
-              // TODO(danrubel): Consider generating this error in the parser
-              // This error is also reported in the body builder
-              handleRecoverableError(messageInvalidSuperInInitializer,
-                  targetFunct.superKeyword, targetFunct.superKeyword);
-            } else if (targetFunct is ThisExpression) {
-              initializers.add(ast.redirectingConstructorInvocation(
-                  targetFunct.thisKeyword, null, null, target.argumentList));
-              // TODO(danrubel): Consider generating this error in the parser
-              // This error is also reported in the body builder
-              handleRecoverableError(messageInvalidThisInInitializer,
-                  targetFunct.thisKeyword, targetFunct.thisKeyword);
-            } else {
-              throw new UnsupportedError(
-                  'unsupported initializer $initializerObject');
-            }
-          } else {
-            throw new UnsupportedError(
-                'unsupported initializer $initializerObject');
-          }
-        }
-      } else if (initializerObject is AssignmentExpression) {
-        Token thisKeyword;
-        Token period;
-        SimpleIdentifier fieldName;
-        Expression left = initializerObject.leftHandSide;
-        if (left is PropertyAccess) {
-          Expression target = left.target;
-          if (target is ThisExpression) {
-            thisKeyword = target.thisKeyword;
-            period = left.operator;
-          } else {
-            assert(target is SuperExpression);
-            // Recovery:
-            // Parser has reported FieldInitializedOutsideDeclaringClass.
-          }
-          fieldName = left.propertyName;
-        } else if (left is SimpleIdentifier) {
-          fieldName = left;
-        } else {
-          // Recovery:
-          // Parser has reported invalid assignment.
-          SuperExpression superExpression = left;
-          fieldName = ast.simpleIdentifier(superExpression.superKeyword);
-        }
-        initializers.add(ast.constructorFieldInitializer(
-            thisKeyword,
-            period,
-            fieldName,
-            initializerObject.operator,
-            initializerObject.rightHandSide));
-      } else if (initializerObject is AssertInitializer) {
-        initializers.add(initializerObject);
-      } else if (initializerObject is PropertyAccess) {
-        // Recovery: Invalid initializer
-        Expression target = initializerObject.target;
-        if (target is FunctionExpressionInvocation) {
-          var targetFunct = target.function;
-          if (targetFunct is SuperExpression) {
-            initializers.add(ast.superConstructorInvocation(
-                targetFunct.superKeyword, null, null, target.argumentList));
-            // TODO(danrubel): Consider generating this error in the parser
-            // This error is also reported in the body builder
-            handleRecoverableError(messageInvalidSuperInInitializer,
-                targetFunct.superKeyword, targetFunct.superKeyword);
-          } else if (targetFunct is ThisExpression) {
-            initializers.add(ast.redirectingConstructorInvocation(
-                targetFunct.thisKeyword, null, null, target.argumentList));
-            // TODO(danrubel): Consider generating this error in the parser
-            // This error is also reported in the body builder
-            handleRecoverableError(messageInvalidThisInInitializer,
-                targetFunct.thisKeyword, targetFunct.thisKeyword);
-          } else {
-            throw new UnsupportedError(
-                'unsupported initializer $initializerObject');
-          }
-        } else {
-          throw new UnsupportedError(
-              'unsupported initializer $initializerObject');
-        }
-      } else {
+      ConstructorInitializer initializer = buildInitializer(initializerObject);
+      if (initializer == null) {
         throw new UnsupportedError('unsupported initializer:'
             ' ${initializerObject.runtimeType} :: $initializerObject');
       }
+      initializers.add(initializer);
     }
 
     push(initializers);
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 4de8709..e038ca8 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -1566,6 +1566,54 @@
     expect(constructor.body, isEmptyFunctionBody);
   }
 
+  void test_parseConstructor_superIndexed() {
+    createParser('C() : super()[];');
+    var constructor = parser.parseClassMember('C') as ConstructorDeclaration;
+    listener.assertErrors([
+      expectedError(ParserErrorCode.INVALID_SUPER_IN_INITIALIZER, 6, 5),
+      expectedError(ParserErrorCode.MISSING_IDENTIFIER, 14, 1),
+    ]);
+    expect(constructor, isNotNull);
+    expect(constructor.externalKeyword, isNull);
+    expect(constructor.constKeyword, isNull);
+    expect(constructor.factoryKeyword, isNull);
+    expect(constructor.returnType.name, 'C');
+    _assertIsDeclarationName(constructor.returnType, false);
+    expect(constructor.name, isNull);
+    expect(constructor.parameters, isNotNull);
+    expect(constructor.parameters.parameters, isEmpty);
+    expect(constructor.separator.lexeme, ':');
+    expect(constructor.initializers, hasLength(1));
+    SuperConstructorInvocation initializer = constructor.initializers[0];
+    expect(initializer.argumentList.arguments, isEmpty);
+    expect(constructor.redirectedConstructor, isNull);
+    expect(constructor.body, isEmptyFunctionBody);
+  }
+
+  void test_parseConstructor_thisIndexed() {
+    createParser('C() : this()[];');
+    var constructor = parser.parseClassMember('C') as ConstructorDeclaration;
+    listener.assertErrors([
+      expectedError(ParserErrorCode.INVALID_THIS_IN_INITIALIZER, 6, 4),
+      expectedError(ParserErrorCode.MISSING_IDENTIFIER, 13, 1),
+    ]);
+    expect(constructor, isNotNull);
+    expect(constructor.externalKeyword, isNull);
+    expect(constructor.constKeyword, isNull);
+    expect(constructor.factoryKeyword, isNull);
+    expect(constructor.returnType.name, 'C');
+    _assertIsDeclarationName(constructor.returnType, false);
+    expect(constructor.name, isNull);
+    expect(constructor.parameters, isNotNull);
+    expect(constructor.parameters.parameters, isEmpty);
+    expect(constructor.separator.lexeme, ':');
+    expect(constructor.initializers, hasLength(1));
+    RedirectingConstructorInvocation initializer = constructor.initializers[0];
+    expect(initializer.argumentList.arguments, isEmpty);
+    expect(constructor.redirectedConstructor, isNull);
+    expect(constructor.body, isEmptyFunctionBody);
+  }
+
   void test_parseConstructor_unnamed() {
     createParser('C();');
     var constructor = parser.parseClassMember('C') as ConstructorDeclaration;