// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:async';

import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';

import '../dart/analysis/base.dart';
import '../task/strong/strong_test_helper.dart';
import 'element_text.dart';

main() {
  defineReflectiveSuite(() {
    defineReflectiveTests(TopLevelInferenceTest);
    defineReflectiveTests(TopLevelInferenceErrorsTest);
//    defineReflectiveTests(ApplyCheckElementTextReplacements);
  });
}

@reflectiveTest
class ApplyCheckElementTextReplacements {
  test_applyReplacements() {
    applyCheckElementTextReplacements();
  }
}

@reflectiveTest
class TopLevelInferenceErrorsTest extends AbstractStrongTest {
  @override
  bool get enableNewAnalysisDriver => true;

  test_initializer_additive() async {
    await _assertErrorOnlyLeft(['+', '-']);
  }

  test_initializer_assign() async {
    var content = r'''
var a = 1;
var t1 = /*error:TOP_LEVEL_UNSUPPORTED*/a += 1;
var t2 = (/*error:TOP_LEVEL_UNSUPPORTED*/a = 2);
''';
    await checkFile(content);
  }

  test_initializer_binary_onlyLeft() async {
    var content = r'''
var a = 1;
var t = (/*error:TOP_LEVEL_UNSUPPORTED*/a = 1) + (a = 2);
''';
    await checkFile(content);
  }

  test_initializer_bitwise() async {
    await _assertErrorOnlyLeft(['&', '|', '^']);
  }

  test_initializer_boolean() async {
    var content = r'''
var a = 1;
var t1 = ((a = 1) == 0) || ((a = 2) == 0);
var t2 = ((a = 1) == 0) && ((a = 2) == 0);
var t3 = !((a = 1) == 0);
''';
    await checkFile(content);
  }

  test_initializer_cascade() async {
    var content = r'''
var a = 0;
var t = (/*error:TOP_LEVEL_UNSUPPORTED*/a = 1)..isEven;
''';
    await checkFile(content);
  }

  test_initializer_classField_instance_instanceCreation() async {
    var content = r'''
class A<T> {}
class B {
  var t1 = new A<int>();
  var t2 = /*info:INFERRED_TYPE_ALLOCATION*/new
           /*error:TOP_LEVEL_TYPE_ARGUMENTS*/A();
}
''';
    await checkFile(content);
  }

  test_initializer_classField_static_instanceCreation() async {
    var content = r'''
class A<T> {}
class B {
  static var t1 = 1;
  static var t2 = /*info:INFERRED_TYPE_ALLOCATION*/new
                  /*error:TOP_LEVEL_TYPE_ARGUMENTS*/A();
}
''';
    await checkFile(content);
  }

  test_initializer_conditional() async {
    var content = r'''
var a = 1;
var b = true;
var t = b ?
          (/*error:TOP_LEVEL_UNSUPPORTED*/a = 1) :
          (/*error:TOP_LEVEL_UNSUPPORTED*/a = 2);
''';
    await checkFile(content);
  }

  test_initializer_dependencyCycle() async {
    var content = r'''
var a = /*error:TOP_LEVEL_CYCLE*/b;
var b = /*error:TOP_LEVEL_CYCLE*/a;
''';
    await checkFile(content);
  }

  test_initializer_equality() async {
    var content = r'''
var a = 1;
var t1 = ((a = 1) == 0) == ((a = 2) == 0);
var t2 = ((a = 1) == 0) != ((a = 2) == 0);
''';
    await checkFile(content);
  }

  test_initializer_functionLiteral_blockBody() async {
    var content = r'''
var t = /*error:TOP_LEVEL_FUNCTION_LITERAL_BLOCK*/
        /*info:INFERRED_TYPE_CLOSURE*/
        (int p) {};
''';
    await checkFile(content);
  }

  test_initializer_functionLiteral_expressionBody() async {
    var content = r'''
var a = 0;
var t = (int p) => (/*error:TOP_LEVEL_UNSUPPORTED*/a = 1);
''';
    await checkFile(content);
  }

  test_initializer_functionLiteral_parameters_withoutType() async {
    var content = r'''
var t = (int a,
         /*error:TOP_LEVEL_FUNCTION_LITERAL_PARAMETER*/b,
         int c,
         /*error:TOP_LEVEL_FUNCTION_LITERAL_PARAMETER*/d) => 0;
''';
    await checkFile(content);
  }

  test_initializer_hasTypeAnnotation() async {
    var content = r'''
var a = 1;
int t = (a = 1);
''';
    await checkFile(content);
  }

  test_initializer_identifier() async {
    var content = r'''
int top_function() => 0;
var top_variable = 0;
int get top_getter => 0;
class A {
  static var static_field = 0;
  static int get static_getter => 0;
  static int static_method() => 0;
  int instance_method() => 0;
}
var t1 = top_function;
var t2 = top_variable;
var t3 = top_getter;
var t4 = A.static_field;
var t5 = A.static_getter;
var t6 = A.static_method;
var t7 = new A().instance_method;
''';
    await checkFile(content);
  }

  test_initializer_identifier_error() async {
    var content = r'''
var a = 0;
var b = (/*error:TOP_LEVEL_UNSUPPORTED*/a = 1);
var c = /*error:TOP_LEVEL_IDENTIFIER_NO_TYPE*/b;
''';
    await checkFile(content);
  }

  test_initializer_ifNull() async {
    var content = r'''
var a = 1;
var t = /*error:TOP_LEVEL_UNSUPPORTED*/a ?? 2;
''';
    await checkFile(content);
  }

  test_initializer_instanceCreation_withoutTypeParameters() async {
    var content = r'''
class A {}
var t = new A();
''';
    await checkFile(content);
  }

  test_initializer_instanceCreation_withTypeParameters() async {
    var content = r'''
class A<T> {}
var t1 = new A<int>();
var t2 = /*info:INFERRED_TYPE_ALLOCATION*/new
         /*error:TOP_LEVEL_TYPE_ARGUMENTS*/A();
''';
    await checkFile(content);
  }

  test_initializer_instanceGetter() async {
    var content = r'''
class A {
  int f = 1;
}
var a = new A()./*error:TOP_LEVEL_INSTANCE_GETTER*/f;
''';
    await checkFile(content);
  }

  test_initializer_methodInvocation_function() async {
    var content = r'''
int f1() => null;
T f2<T>() => null;
var t1 = f1();
var t2 = /*error:TOP_LEVEL_TYPE_ARGUMENTS*/f2();
var t3 = f2<int>();
''';
    await checkFile(content);
  }

  test_initializer_methodInvocation_method() async {
    var content = r'''
class A {
  int m1() => null;
  T m2<T>() => null;
}
var a = new A();
var t1 = a.m1();
var t2 = a./*error:TOP_LEVEL_TYPE_ARGUMENTS*/m2();
var t3 = a.m2<int>();
''';
    await checkFile(content);
  }

  test_initializer_multiplicative() async {
    await _assertErrorOnlyLeft(['*', '/', '%', '~/']);
  }

  test_initializer_postfixIncDec() async {
    var content = r'''
var a = 1;
var t1 = a++;
var t2 = a--;
''';
    await checkFile(content);
  }

  test_initializer_prefixIncDec() async {
    var content = r'''
var a = 1;
var t1 = ++a;
var t2 = --a;
''';
    await checkFile(content);
  }

  test_initializer_relational() async {
    await _assertErrorOnlyLeft(['>', '>=', '<', '<=']);
  }

  test_initializer_shift() async {
    await _assertErrorOnlyLeft(['<<', '>>']);
  }

  test_initializer_typedList() async {
    var content = r'''
var a = 1;
var t = <int>[a = 1];
''';
    await checkFile(content);
  }

  test_initializer_typedMap() async {
    var content = r'''
var a = 1;
var t = <int, int>{(a = 1) : (a = 2)};
''';
    await checkFile(content);
  }

  test_initializer_untypedList() async {
    var content = r'''
var a = 1;
var t = /*info:INFERRED_TYPE_LITERAL*/[
            /*error:TOP_LEVEL_UNSUPPORTED*/a = 1,
            2, 3];
''';
    await checkFile(content);
  }

  test_initializer_untypedMap() async {
    var content = r'''
var a = 1;
var t = /*info:INFERRED_TYPE_LITERAL*/{
            (/*error:TOP_LEVEL_UNSUPPORTED*/a = 1) :
            (/*error:TOP_LEVEL_UNSUPPORTED*/a = 2)};
''';
    await checkFile(content);
  }

  test_override_conflictFieldType() async {
    var content = r'''
abstract class A {
  int aaa;
}
abstract class B {
  String aaa;
}
class C implements A, B {
  /*error:INVALID_METHOD_OVERRIDE*/var aaa;
}
''';
    await checkFile(content);
  }

  @failingTest
  test_override_conflictParameterType_method() async {
    var content = r'''
abstract class A {
  void mmm(int a);
}
abstract class B {
  void mmm(String a);
}
class C implements A, B {
  void mmm(/*error:TOP_LEVEL_INFERENCE_ERROR*/a) {}
}
''';
    await checkFile(content);
  }

  Future<Null> _assertErrorOnlyLeft(List<String> operators) async {
    var err = '/*error:TOP_LEVEL_UNSUPPORTED*/';
    String code = 'var a = 1;\n';
    for (var i = 0; i < operators.length; i++) {
      String operator = operators[i];
      code += 'var t$i = (${err}a = 1) $operator (a = 2);\n';
    }
    await checkFile(code);
  }
}

@reflectiveTest
class TopLevelInferenceTest extends BaseAnalysisDriverTest {
  void addFile(String path, String code) {
    provider.newFile(_p(path), code);
  }

  test_initializer_additive() async {
    var library = await _encodeDecodeLibrary(r'''
var vPlusIntInt = 1 + 2;
var vPlusIntDouble = 1 + 2.0;
var vPlusDoubleInt = 1.0 + 2;
var vPlusDoubleDouble = 1.0 + 2.0;
var vMinusIntInt = 1 - 2;
var vMinusIntDouble = 1 - 2.0;
var vMinusDoubleInt = 1.0 - 2;
var vMinusDoubleDouble = 1.0 - 2.0;
''');
    checkElementText(
        library,
        r'''
int vPlusIntInt;
double vPlusIntDouble;
double vPlusDoubleInt;
double vPlusDoubleDouble;
int vMinusIntInt;
double vMinusIntDouble;
double vMinusDoubleInt;
double vMinusDoubleDouble;
''');
  }

  test_initializer_as() async {
    var library = await _encodeDecodeLibrary(r'''
var V = 1 as num;
''');
    checkElementText(
        library,
        r'''
num V;
''');
  }

  test_initializer_await() async {
    var library = await _encodeDecodeLibrary(r'''
import 'dart:async';
int fValue() => 42;
Future<int> fFuture() async => 42;
var uValue = () async => await fValue();
var uFuture = () async => await fFuture();
''');
    checkElementText(
        library,
        r'''
import 'dart:async';
() → Future<int> uValue;
() → Future<int> uFuture;
int fValue() {}
Future<int> fFuture() async {}
''');
  }

  test_initializer_bitwise() async {
    var library = await _encodeDecodeLibrary(r'''
var vBitXor = 1 ^ 2;
var vBitAnd = 1 & 2;
var vBitOr = 1 | 2;
var vBitShiftLeft = 1 << 2;
var vBitShiftRight = 1 >> 2;
''');
    checkElementText(
        library,
        r'''
int vBitXor;
int vBitAnd;
int vBitOr;
int vBitShiftLeft;
int vBitShiftRight;
''');
  }

  test_initializer_cascade() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  int a;
  void m() {}
}
var vSetField = new A()..a = 1;
var vInvokeMethod = new A()..m();
var vBoth = new A()..a = 1..m();
''');
    checkElementText(
        library,
        r'''
class A {
  int a;
  void m() {}
}
A vSetField;
A vInvokeMethod;
A vBoth;
''');
  }

  test_initializer_conditional() async {
    var library = await _encodeDecodeLibrary(r'''
var V = true ? 1 : 2.3;
''');
    checkElementText(
        library,
        r'''
num V;
''');
  }

  test_initializer_equality() async {
    var library = await _encodeDecodeLibrary(r'''
var vEq = 1 == 2;
var vNotEq = 1 != 2;
''');
    checkElementText(
        library,
        r'''
bool vEq;
bool vNotEq;
''');
  }

  test_initializer_error_assign() async {
    var library = await _encodeDecodeLibrary(r'''
var a = 1;
var t1 = (a = 2);
var t2 = (a += 2);
''');
    checkElementText(
        library,
        r'''
int a;
dynamic t1/*error: assignment*/;
dynamic t2/*error: assignment*/;
''');
  }

  test_initializer_error_assign_prefixed() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  int f;
}
var a = new A();
var t1 = (a.f = 1);
var t2 = (a.f += 2);
''');
    checkElementText(
        library,
        r'''
class A {
  int f;
}
A a;
dynamic t1/*error: assignment*/;
dynamic t2/*error: assignment*/;
''');
  }

  test_initializer_error_assign_prefixed_viaInterface() async {
    var library = await _encodeDecodeLibrary(r'''
class I {
  int f;
}
abstract class C implements I {}
C c;
var t1 = (c.f = 1);
var t2 = (c.f += 2);
''');
    checkElementText(
        library,
        r'''
class I {
  int f;
}
abstract class C implements I {
}
C c;
dynamic t1/*error: assignment*/;
dynamic t2/*error: assignment*/;
''');
  }

  test_initializer_error_assign_viaInterface() async {
    var library = await _encodeDecodeLibrary(r'''
class I {
  int f;
}
abstract class C implements I {}
C getC() => null;
var t1 = (getC().f = 1);
var t2 = (getC().f += 2);
''');
    checkElementText(
        library,
        r'''
class I {
  int f;
}
abstract class C implements I {
}
dynamic t1/*error: assignment*/;
dynamic t2/*error: assignment*/;
C getC() {}
''');
  }

  /**
   * A simple or qualified identifier referring to a top level function, static
   * variable, field, getter; or a static class variable, static getter or
   * method; or an instance method; has the inferred type of the identifier.
   *
   * Note: specifically, references to instance fields and instance getters are
   * disallowed here.
   */
  test_initializer_error_classField_useInstanceGetter() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  int f = 1;
}
class B {
  A a;
}
class C {
  B b;
}
class X {
  A a = new A();
  B b = new B();
  C c = new C();
  var t01 = a.f;
  var t02 = b.a.f;
  var t03 = c.b.a.f;
  var t11 = new A().f;
  var t12 = new B().a.f;
  var t13 = new C().b.a.f;
  var t21 = newA().f;
  var t22 = newB().a.f;
  var t23 = newC().b.a.f;
}
A newA() => new A();
B newB() => new B();
C newC() => new C();
''');
    checkElementText(
        library,
        r'''
class A {
  int f;
}
class B {
  A a;
}
class C {
  B b;
}
class X {
  A a;
  B b;
  C c;
  dynamic t01/*error: instanceGetter*/;
  dynamic t02/*error: instanceGetter*/;
  dynamic t03/*error: instanceGetter*/;
  dynamic t11/*error: instanceGetter*/;
  dynamic t12/*error: instanceGetter*/;
  dynamic t13/*error: instanceGetter*/;
  dynamic t21/*error: instanceGetter*/;
  dynamic t22/*error: instanceGetter*/;
  dynamic t23/*error: instanceGetter*/;
}
A newA() {}
B newB() {}
C newC() {}
''');
  }

  test_initializer_error_extractProperty() async {
    var library = await _encodeDecodeLibrary(r'''
class C {
  bool b;
}
C f() => null;
var x = f().b;
''');
    checkElementText(
        library,
        r'''
class C {
  bool b;
}
dynamic x/*error: instanceGetter*/;
C f() {}
''');
  }

  test_initializer_error_extractProperty_inOtherLibraryCycle() async {
    addFile(
        '/a.dart',
        r'''
import 'b.dart';
var x = new C().f;
''');
    addFile(
        '/b.dart',
        r'''
class C {
  var f = 0;
}
''');
    var library = await _encodeDecodeLibrary(r'''
import 'a.dart';
var t1 = x;
''');
    checkElementText(
        library,
        r'''
import 'a.dart';
dynamic t1;
''');
  }

  test_initializer_error_extractProperty_inStaticField() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  int f;
}
class B {
  static var t = new A().f;
}
''');
    checkElementText(
        library,
        r'''
class A {
  int f;
}
class B {
  static dynamic t/*error: instanceGetter*/;
}
''');
  }

  test_initializer_error_extractProperty_prefixedIdentifier() async {
    var library = await _encodeDecodeLibrary(r'''
class C {
  bool b;
}
C c;
var x = c.b;
''');
    checkElementText(
        library,
        r'''
class C {
  bool b;
}
C c;
dynamic x/*error: instanceGetter*/;
''');
  }

  test_initializer_error_extractProperty_prefixedIdentifier_viaInterface() async {
    var library = await _encodeDecodeLibrary(r'''
class I {
  bool b;
}
abstract class C implements I {}
C c;
var x = c.b;
''');
    checkElementText(
        library,
        r'''
class I {
  bool b;
}
abstract class C implements I {
}
C c;
dynamic x/*error: instanceGetter*/;
''');
  }

  test_initializer_error_extractProperty_viaInterface() async {
    var library = await _encodeDecodeLibrary(r'''
class I {
  bool b;
}
abstract class C implements I {}
C f() => null;
var x = f().b;
''');
    checkElementText(
        library,
        r'''
class I {
  bool b;
}
abstract class C implements I {
}
dynamic x/*error: instanceGetter*/;
C f() {}
''');
  }

  test_initializer_error_instanceGetterOfObject() async {
    var library = await _encodeDecodeLibrary(r'''
dynamic f() => null;
var s = f().toString();
var h = f().hashCode;
''');
    checkElementText(
        library,
        r'''
String s;
dynamic h/*error: instanceGetter*/;
dynamic f() {}
''');
  }

  test_initializer_error_instanceGetterOfObject_prefixed() async {
    var library = await _encodeDecodeLibrary(r'''
dynamic d;
var s = d.toString();
var h = d.hashCode;
''');
    checkElementText(
        library,
        r'''
dynamic d;
String s;
dynamic h/*error: instanceGetter*/;
''');
  }

  test_initializer_error_referenceToFieldOfStaticField() async {
    var library = await _encodeDecodeLibrary(r'''
class C {
  static D d;
}
class D {
  int i;
}
final x = C.d.i;
''');
    checkElementText(
        library,
        r'''
class C {
  static D d;
}
class D {
  int i;
}
final dynamic x/*error: instanceGetter*/;
''');
  }

  test_initializer_error_referenceToFieldOfStaticGetter() async {
    var library = await _encodeDecodeLibrary(r'''
class C {
  static D get d => null;
}
class D {
  int i;
}
var x = C.d.i;
''');
    checkElementText(
        library,
        r'''
class C {
  static D get d {}
}
class D {
  int i;
}
dynamic x/*error: instanceGetter*/;
''');
  }

  test_initializer_functionExpression() async {
    var library = await _encodeDecodeLibrary(r'''
import 'dart:async';
var vFuture = new Future<int>(42);
var v_noParameters_inferredReturnType = () => 42;
var v_hasParameter_withType_inferredReturnType = (String a) => 42;
var v_hasParameter_withType_returnParameter = (String a) => a;
var v_async_returnValue = () async => 42;
var v_async_returnFuture = () async => vFuture;
''');
    checkElementText(
        library,
        r'''
import 'dart:async';
Future<int> vFuture;
() → int v_noParameters_inferredReturnType;
(String) → int v_hasParameter_withType_inferredReturnType;
(String) → String v_hasParameter_withType_returnParameter;
() → Future<int> v_async_returnValue;
() → Future<int> v_async_returnFuture;
''');
  }

  @failingTest
  test_initializer_functionExpressionInvocation_noTypeParameters() async {
    var library = await _encodeDecodeLibrary(r'''
var v = (() => 42)();
''');
    // TODO(scheglov) add more function expression tests
    checkElementText(
        library,
        r'''
int v;
''');
  }

  test_initializer_functionInvocation_hasTypeParameters() async {
    var library = await _encodeDecodeLibrary(r'''
T f<T>() => null;
var vHasTypeArgument = f<int>();
var vNoTypeArgument = f();
''');
    checkElementText(
        library,
        r'''
int vHasTypeArgument;
dynamic vNoTypeArgument;
T f<T>() {}
''');
  }

  test_initializer_functionInvocation_noTypeParameters() async {
    var library = await _encodeDecodeLibrary(r'''
String f(int p) => null;
var vOkArgumentType = f(1);
var vWrongArgumentType = f(2.0);
''');
    checkElementText(
        library,
        r'''
String vOkArgumentType;
String vWrongArgumentType;
String f(int p) {}
''');
  }

  test_initializer_identifier() async {
    var library = await _encodeDecodeLibrary(r'''
String topLevelFunction(int p) => null;
var topLevelVariable = 0;
int get topLevelGetter => 0;
class A {
  static var staticClassVariable = 0;
  static int get staticGetter => 0;
  static String staticClassMethod(int p) => null;
  String instanceClassMethod(int p) => null;
}
var r_topLevelFunction = topLevelFunction;
var r_topLevelVariable = topLevelVariable;
var r_topLevelGetter = topLevelGetter;
var r_staticClassVariable = A.staticClassVariable;
var r_staticGetter = A.staticGetter;
var r_staticClassMethod = A.staticClassMethod;
var instanceOfA = new A();
var r_instanceClassMethod = instanceOfA.instanceClassMethod;
''');
    checkElementText(
        library,
        r'''
class A {
  static int staticClassVariable;
  static int get staticGetter {}
  static String staticClassMethod(int p) {}
  String instanceClassMethod(int p) {}
}
int topLevelVariable;
(int) → String r_topLevelFunction;
int r_topLevelVariable;
int r_topLevelGetter;
int r_staticClassVariable;
int r_staticGetter;
(int) → String r_staticClassMethod;
A instanceOfA;
(int) → String r_instanceClassMethod;
int get topLevelGetter {}
String topLevelFunction(int p) {}
''');
  }

  test_initializer_identifier_error_cycle_classField() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  static var a = B.b;
}
class B {
  static var b = A.a;
}
var c = A.a;
''');
    checkElementText(
        library,
        r'''
class A {
  static dynamic a/*error: dependencyCycle*/;
}
class B {
  static dynamic b/*error: dependencyCycle*/;
}
dynamic c;
''');
  }

  test_initializer_identifier_error_cycle_mix() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  static var a = b;
}
var b = A.a;
var c = b;
''');
    checkElementText(
        library,
        r'''
class A {
  static dynamic a/*error: dependencyCycle*/;
}
dynamic b/*error: dependencyCycle*/;
dynamic c;
''');
  }

  test_initializer_identifier_error_cycle_topLevel() async {
    var library = await _encodeDecodeLibrary(r'''
var a = b;
var b = c;
var c = a;
var d = a;
''');
    checkElementText(
        library,
        r'''
dynamic a/*error: dependencyCycle*/;
dynamic b/*error: dependencyCycle*/;
dynamic c/*error: dependencyCycle*/;
dynamic d;
''');
  }

  test_initializer_identifier_formalParameter() async {
    // TODO(scheglov) I don't understand this yet
  }

  @failingTest
  test_initializer_instanceCreation_hasTypeParameter() async {
    var library = await _encodeDecodeLibrary(r'''
class A<T> {}
var a = new A<int>();
var b = new A();
''');
    // TODO(scheglov) test for inference failure error
    checkElementText(
        library,
        r'''
class A<T> {
}
A<int> a;
dynamic b;
''');
  }

  test_initializer_instanceCreation_noTypeParameters() async {
    var library = await _encodeDecodeLibrary(r'''
class A {}
var a = new A();
''');
    checkElementText(
        library,
        r'''
class A {
}
A a;
''');
  }

  test_initializer_is() async {
    var library = await _encodeDecodeLibrary(r'''
var a = 1.2;
var b = a is int;
''');
    checkElementText(
        library,
        r'''
double a;
bool b;
''');
  }

  @failingTest
  test_initializer_literal() async {
    var library = await _encodeDecodeLibrary(r'''
var vNull = null;
var vBoolFalse = false;
var vBoolTrue = true;
var vInt = 1;
var vIntLong = 0x9876543210987654321;
var vDouble = 2.3;
var vString = 'abc';
var vStringConcat = 'aaa' 'bbb';
var vStringInterpolation = 'aaa ${true} ${42} bbb';
var vSymbol = #aaa.bbb.ccc;
''');
    checkElementText(
        library,
        r'''
Null vNull;
bool vBoolFalse;
bool vBoolTrue;
int vInt;
int vIntLong;
double vDouble;
String vString;
String vStringConcat;
String vStringInterpolation;
Symbol vSymbol;
''');
  }

  test_initializer_literal_list_typed() async {
    var library = await _encodeDecodeLibrary(r'''
var vObject = <Object>[1, 2, 3];
var vNum = <num>[1, 2, 3];
var vNumEmpty = <num>[];
var vInt = <int>[1, 2, 3];
''');
    checkElementText(
        library,
        r'''
List<Object> vObject;
List<num> vNum;
List<num> vNumEmpty;
List<int> vInt;
''');
  }

  test_initializer_literal_list_untyped() async {
    var library = await _encodeDecodeLibrary(r'''
var vInt = [1, 2, 3];
var vNum = [1, 2.0];
var vObject = [1, 2.0, '333'];
''');
    checkElementText(
        library,
        r'''
List<int> vInt;
List<num> vNum;
List<Object> vObject;
''');
  }

  @failingTest
  test_initializer_literal_list_untyped_empty() async {
    var library = await _encodeDecodeLibrary(r'''
var vNonConst = [];
var vConst = const [];
''');
    checkElementText(
        library,
        r'''
List<dynamic> vNonConst;
List<Null> vConst;
''');
  }

  test_initializer_literal_map_typed() async {
    var library = await _encodeDecodeLibrary(r'''
var vObjectObject = <Object, Object>{1: 'a'};
var vComparableObject = <Comparable<int>, Object>{1: 'a'};
var vNumString = <num, String>{1: 'a'};
var vNumStringEmpty = <num, String>{};
var vIntString = <int, String>{};
''');
    checkElementText(
        library,
        r'''
Map<Object, Object> vObjectObject;
Map<Comparable<int>, Object> vComparableObject;
Map<num, String> vNumString;
Map<num, String> vNumStringEmpty;
Map<int, String> vIntString;
''');
  }

  test_initializer_literal_map_untyped() async {
    var library = await _encodeDecodeLibrary(r'''
var vIntString = {1: 'a', 2: 'b'};
var vNumString = {1: 'a', 2.0: 'b'};
var vIntObject = {1: 'a', 2: 3.0};
''');
    checkElementText(
        library,
        r'''
Map<int, String> vIntString;
Map<num, String> vNumString;
Map<int, Object> vIntObject;
''');
  }

  @failingTest
  test_initializer_literal_map_untyped_empty() async {
    var library = await _encodeDecodeLibrary(r'''
var vNonConst = {};
var vConst = const {};
''');
    checkElementText(
        library,
        r'''
Map<dynamic, dynamic> vNonConst;
Map<Null, Null> vConst;
''');
  }

  test_initializer_logicalBool() async {
    var library = await _encodeDecodeLibrary(r'''
var a = true;
var b = true;
var vEq = 1 == 2;
var vAnd = a && b;
var vOr = a || b;
''');
    checkElementText(
        library,
        r'''
bool a;
bool b;
bool vEq;
bool vAnd;
bool vOr;
''');
  }

  @failingTest
  test_initializer_methodInvocation_hasTypeParameters() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  List<T> m<T>() => null;
}
var vWithTypeArgument = new A().m<int>();
var vWithoutTypeArgument = new A().m();
''');
    // TODO(scheglov) test for inference failure error
    checkElementText(
        library,
        r'''
class A {
  List<T> m<T>(int p) {}
}
List<int> vWithTypeArgument;
dynamic vWithoutTypeArgument;
''');
  }

  test_initializer_methodInvocation_noTypeParameters() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  String m(int p) => null;
}
var instanceOfA = new A();
var v1 = instanceOfA.m();
var v2 = new A().m();
''');
    checkElementText(
        library,
        r'''
class A {
  String m(int p) {}
}
A instanceOfA;
String v1;
String v2;
''');
  }

  test_initializer_multiplicative() async {
    var library = await _encodeDecodeLibrary(r'''
var vModuloIntInt = 1 % 2;
var vModuloIntDouble = 1 % 2.0;
var vMultiplyIntInt = 1 * 2;
var vMultiplyIntDouble = 1 * 2.0;
var vMultiplyDoubleInt = 1.0 * 2;
var vMultiplyDoubleDouble = 1.0 * 2.0;
var vDivideIntInt = 1 / 2;
var vDivideIntDouble = 1 / 2.0;
var vDivideDoubleInt = 1.0 / 2;
var vDivideDoubleDouble = 1.0 / 2.0;
var vFloorDivide = 1 ~/ 2;
''');
    checkElementText(
        library,
        r'''
int vModuloIntInt;
double vModuloIntDouble;
int vMultiplyIntInt;
double vMultiplyIntDouble;
double vMultiplyDoubleInt;
double vMultiplyDoubleDouble;
num vDivideIntInt;
num vDivideIntDouble;
double vDivideDoubleInt;
double vDivideDoubleDouble;
int vFloorDivide;
''');
  }

  @failingTest
  test_initializer_onlyLeft() async {
    var library = await _encodeDecodeLibrary(r'''
var a = 1;
var vEq = a == ((a = 2) == 0);
var vNotEq = a != ((a = 2) == 0);
''');
    checkElementText(
        library,
        r'''
int a;
bool vEq;
bool vNotEq;
''');
  }

  test_initializer_parenthesized() async {
    var library = await _encodeDecodeLibrary(r'''
var V = (42);
''');
    checkElementText(
        library,
        r'''
int V;
''');
  }

  @failingTest
  test_initializer_postfix() async {
    var library = await _encodeDecodeLibrary(r'''
var vInt = 1;
var vDouble = 2;
var vIncInt = vInt++;
var vDecInt = vInt--;
var vIncDouble = vDouble++;
var vDecDouble = vDouble--;
''');
    checkElementText(
        library,
        r'''
int vInt;
int vDouble;
int vIncInt;
int vDecInt;
double vIncDouble;
double vDecDouble;
''');
  }

  @failingTest
  test_initializer_prefix_incDec() async {
    var library = await _encodeDecodeLibrary(r'''
var vInt = 1;
var vDouble = 2.0;
var vIncInt = ++vInt;
var vDecInt = --vInt;
var vIncDouble = ++vDouble;
var vDecInt = --vDouble;
''');
    checkElementText(
        library,
        r'''
int vInt;
double vDouble;
int vIncInt;
int vDecInt;
double vIncDouble;
double vDecInt;
''');
  }

  @failingTest
  test_initializer_prefix_incDec_custom() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  B operator+(int v) => null;
}
class B {}
var a = new A();
var vInc = ++a;
var vDec = --a;
''');
    checkElementText(
        library,
        r'''
A a;
B vInc;
B vDec;
''');
  }

  test_initializer_prefix_not() async {
    var library = await _encodeDecodeLibrary(r'''
var vNot = !true;
''');
    checkElementText(
        library,
        r'''
bool vNot;
''');
  }

  test_initializer_prefix_other() async {
    var library = await _encodeDecodeLibrary(r'''
var vNegateInt = -1;
var vNegateDouble = -1.0;
var vComplement = ~1;
''');
    checkElementText(
        library,
        r'''
int vNegateInt;
double vNegateDouble;
int vComplement;
''');
  }

  test_initializer_relational() async {
    var library = await _encodeDecodeLibrary(r'''
var vLess = 1 < 2;
var vLessOrEqual = 1 <= 2;
var vGreater = 1 > 2;
var vGreaterOrEqual = 1 >= 2;
''');
    checkElementText(
        library,
        r'''
bool vLess;
bool vLessOrEqual;
bool vGreater;
bool vGreaterOrEqual;
''');
  }

  @failingTest
  test_initializer_throw() async {
    var library = await _encodeDecodeLibrary(r'''
var V = throw 42;
''');
    checkElementText(
        library,
        r'''
Null V;
''');
  }

  test_instanceField_fieldFormal() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  var f = 0;
  A([this.f = 'hello']);
}
''');
    checkElementText(
        library,
        r'''
class A {
  int f;
  A([int this.f]);
}
''');
  }

  test_instanceField_fromField() async {
    var library = await _encodeDecodeLibrary(r'''
abstract class A {
  int x;
  int y;
  int z;
}
class B implements A {
  var x;
  get y => null;
  set z(_) {}
}
''');
    checkElementText(
        library,
        r'''
abstract class A {
  int x;
  int y;
  int z;
}
class B implements A {
  int x;
  synthetic final int y;
  synthetic int z;
  int get y {}
  void set z(int _) {}
}
''',
        withSyntheticFields: true);
  }

  test_instanceField_fromField_explicitDynamic() async {
    var library = await _encodeDecodeLibrary(r'''
abstract class A {
  dynamic x;
}
class B implements A {
  var x = 1;
}
''');
    checkElementText(
        library,
        r'''
abstract class A {
  dynamic x;
}
class B implements A {
  dynamic x;
}
''');
  }

  test_instanceField_fromField_generic() async {
    var library = await _encodeDecodeLibrary(r'''
abstract class A<E> {
  E x;
  E y;
  E z;
}
class B<T> implements A<T> {
  var x;
  get y => null;
  set z(_) {}
}
''');
    checkElementText(
        library,
        r'''
abstract class A<E> {
  E x;
  E y;
  E z;
}
class B<T> implements A<T> {
  T x;
  synthetic final T y;
  synthetic T z;
  T get y {}
  void set z(T _) {}
}
''',
        withSyntheticFields: true);
  }

  test_instanceField_fromField_implicitDynamic() async {
    var library = await _encodeDecodeLibrary(r'''
abstract class A {
  var x;
}
class B implements A {
  var x = 1;
}
''');
    checkElementText(
        library,
        r'''
abstract class A {
  dynamic x;
}
class B implements A {
  dynamic x;
}
''');
  }

  test_instanceField_fromField_narrowType() async {
    var library = await _encodeDecodeLibrary(r'''
abstract class A {
  num x;
}
class B implements A {
  var x = 1;
}
''');
    checkElementText(
        library,
        r'''
abstract class A {
  num x;
}
class B implements A {
  num x;
}
''');
  }

  test_instanceField_fromGetter() async {
    var library = await _encodeDecodeLibrary(r'''
abstract class A {
  int get x;
  int get y;
  int get z;
}
class B implements A {
  var x;
  get y => null;
  set z(_) {}
}
''');
    checkElementText(
        library,
        r'''
abstract class A {
  int get x;
  int get y;
  int get z;
}
class B implements A {
  int x;
  int get y {}
  void set z(int _) {}
}
''');
  }

  test_instanceField_fromGetter_generic() async {
    var library = await _encodeDecodeLibrary(r'''
abstract class A<E> {
  E get x;
  E get y;
  E get z;
}
class B<T> implements A<T> {
  var x;
  get y => null;
  set z(_) {}
}
''');
    checkElementText(
        library,
        r'''
abstract class A<E> {
  E get x;
  E get y;
  E get z;
}
class B<T> implements A<T> {
  T x;
  T get y {}
  void set z(T _) {}
}
''');
  }

  test_instanceField_fromGetter_multiple_different() async {
    var library = await _encodeDecodeLibrary(r'''
abstract class A {
  int get x;
}
abstract class B {
  String get x;
}
class C implements A, B {
  get x => null;
}
''');
    // TODO(scheglov) test for inference failure error
    checkElementText(
        library,
        r'''
abstract class A {
  int get x;
}
abstract class B {
  String get x;
}
class C implements A, B {
  dynamic get x {}
}
''');
  }

  test_instanceField_fromGetter_multiple_different_dynamic() async {
    var library = await _encodeDecodeLibrary(r'''
abstract class A {
  int get x;
}
abstract class B {
  dynamic get x;
}
class C implements A, B {
  get x => null;
}
''');
    // TODO(scheglov) test for inference failure error
    checkElementText(
        library,
        r'''
abstract class A {
  int get x;
}
abstract class B {
  dynamic get x;
}
class C implements A, B {
  dynamic get x {}
}
''');
  }

  test_instanceField_fromGetter_multiple_different_generic() async {
    var library = await _encodeDecodeLibrary(r'''
abstract class A<T> {
  T get x;
}
abstract class B<T> {
  T get x;
}
class C implements A<int>, B<String> {
  get x => null;
}
''');
    // TODO(scheglov) test for inference failure error
    checkElementText(
        library,
        r'''
abstract class A<T> {
  T get x;
}
abstract class B<T> {
  T get x;
}
class C implements A<int>, B<String> {
  dynamic get x {}
}
''');
  }

  test_instanceField_fromGetter_multiple_same() async {
    var library = await _encodeDecodeLibrary(r'''
abstract class A {
  int get x;
}
abstract class B {
  int get x;
}
class C implements A, B {
  get x => null;
}
''');
    checkElementText(
        library,
        r'''
abstract class A {
  int get x;
}
abstract class B {
  int get x;
}
class C implements A, B {
  int get x {}
}
''');
  }

  test_instanceField_fromGetterSetter_different_field() async {
    var library = await _encodeDecodeLibrary(r'''
abstract class A {
  int get x;
  int get y;
}
abstract class B {
  void set x(String _);
  void set y(String _);
}
class C implements A, B {
  var x;
  final y;
}
''');
    checkElementText(
        library,
        r'''
abstract class A {
  int get x;
  int get y;
}
abstract class B {
  void set x(String _);
  void set y(String _);
}
class C implements A, B {
  dynamic x/*error: overrideConflictFieldType*/;
  final int y;
}
''');
  }

  test_instanceField_fromGetterSetter_different_getter() async {
    var library = await _encodeDecodeLibrary(r'''
abstract class A {
  int get x;
}
abstract class B {
  void set x(String _);
}
class C implements A, B {
  get x => null;
}
''');
    checkElementText(
        library,
        r'''
abstract class A {
  synthetic final int x;
  int get x;
}
abstract class B {
  synthetic String x;
  void set x(String _);
}
class C implements A, B {
  synthetic final int x;
  int get x {}
}
''',
        withSyntheticFields: true);
  }

  test_instanceField_fromGetterSetter_different_setter() async {
    var library = await _encodeDecodeLibrary(r'''
abstract class A {
  int get x;
}
abstract class B {
  void set x(String _);
}
class C implements A, B {
  set x(_);
}
''');
    // TODO(scheglov) test for inference failure error
    checkElementText(
        library,
        r'''
abstract class A {
  synthetic final int x;
  int get x;
}
abstract class B {
  synthetic String x;
  void set x(String _);
}
class C implements A, B {
  synthetic dynamic x;
  void set x(dynamic _);
}
''',
        withSyntheticFields: true);
  }

  test_instanceField_fromGetterSetter_same_field() async {
    var library = await _encodeDecodeLibrary(r'''
abstract class A {
  int get x;
}
abstract class B {
  void set x(int _);
}
class C implements A, B {
  var x;
}
''');
    checkElementText(
        library,
        r'''
abstract class A {
  int get x;
}
abstract class B {
  void set x(int _);
}
class C implements A, B {
  int x;
}
''');
  }

  test_instanceField_fromGetterSetter_same_getter() async {
    var library = await _encodeDecodeLibrary(r'''
abstract class A {
  int get x;
}
abstract class B {
  void set x(int _);
}
class C implements A, B {
  get x => null;
}
''');
    checkElementText(
        library,
        r'''
abstract class A {
  synthetic final int x;
  int get x;
}
abstract class B {
  synthetic int x;
  void set x(int _);
}
class C implements A, B {
  synthetic final int x;
  int get x {}
}
''',
        withSyntheticFields: true);
  }

  test_instanceField_fromGetterSetter_same_setter() async {
    var library = await _encodeDecodeLibrary(r'''
abstract class A {
  int get x;
}
abstract class B {
  void set x(int _);
}
class C implements A, B {
  set x(_);
}
''');
    checkElementText(
        library,
        r'''
abstract class A {
  synthetic final int x;
  int get x;
}
abstract class B {
  synthetic int x;
  void set x(int _);
}
class C implements A, B {
  synthetic int x;
  void set x(int _);
}
''',
        withSyntheticFields: true);
  }

  test_instanceField_fromSetter() async {
    var library = await _encodeDecodeLibrary(r'''
abstract class A {
  void set x(int _);
  void set y(int _);
  void set z(int _);
}
class B implements A {
  var x;
  get y => null;
  set z(_) {}
}
''');
    checkElementText(
        library,
        r'''
abstract class A {
  void set x(int _);
  void set y(int _);
  void set z(int _);
}
class B implements A {
  int x;
  int get y {}
  void set z(int _) {}
}
''');
  }

  test_instanceField_fromSetter_multiple_different() async {
    var library = await _encodeDecodeLibrary(r'''
abstract class A {
  void set x(int _);
}
abstract class B {
  void set x(String _);
}
class C implements A, B {
  get x => null;
}
''');
    checkElementText(
        library,
        r'''
abstract class A {
  void set x(int _);
}
abstract class B {
  void set x(String _);
}
class C implements A, B {
  dynamic get x {}
}
''');
  }

  test_instanceField_fromSetter_multiple_same() async {
    var library = await _encodeDecodeLibrary(r'''
abstract class A {
  void set x(int _);
}
abstract class B {
  void set x(int _);
}
class C implements A, B {
  get x => null;
}
''');
    checkElementText(
        library,
        r'''
abstract class A {
  void set x(int _);
}
abstract class B {
  void set x(int _);
}
class C implements A, B {
  int get x {}
}
''');
  }

  test_instanceField_functionTypeAlias_doesNotUseItsTypeParameter() async {
    var library = await _encodeDecodeLibrary(r'''
typedef F<T>();

class A<T> {
  F<T> get x => null;
  List<F<T>> get y => null;
}

class B extends A<int> {
  get x => null;
  get y => null;
}
''');
    checkElementText(
        library,
        r'''
typedef dynamic F<T>();
class A<T> {
  F<T> get x {}
  List<F<T>> get y {}
}
class B extends A<int> {
  F<int> get x {}
  List<F<int>> get y {}
}
''');
  }

  test_instanceField_inheritsCovariant_fromSetter_field() async {
    var library = await _encodeDecodeLibrary(r'''
abstract class A {
  num get x;
  void set x(covariant num _);
}
class B implements A {
  int x;
}
''');
    checkElementText(
        library,
        r'''
abstract class A {
  num get x;
  void set x(covariant num _);
}
class B implements A {
  int x;
  synthetic int get x {}
  synthetic void set x(covariant int _x) {}
}
''',
        withSyntheticAccessors: true);
  }

  test_instanceField_inheritsCovariant_fromSetter_setter() async {
    var library = await _encodeDecodeLibrary(r'''
abstract class A {
  num get x;
  void set x(covariant num _);
}
class B implements A {
  set x(int _) {}
}
''');
    checkElementText(
        library,
        r'''
abstract class A {
  num get x;
  void set x(covariant num _);
}
class B implements A {
  void set x(covariant int _) {}
}
''');
  }

  test_instanceField_initializer() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  var t1 = 1;
  var t2 = 2.0;
  var t3 = null;
}
''');
    checkElementText(
        library,
        r'''
class A {
  int t1;
  double t2;
  dynamic t3;
}
''');
  }

  test_method_error_conflict_parameterType_generic() async {
    var library = await _encodeDecodeLibrary(r'''
class A<T> {
  void m(T a) {}
}
class B<E> {
  void m(E a) {}
}
class C extends A<int> implements B<double> {
  m(a) {}
}
''');
    checkElementText(
        library,
        r'''
class A<T> {
  void m(T a) {}
}
class B<E> {
  void m(E a) {}
}
class C extends A<int> implements B<double> {
  void m(dynamic a/*error: overrideConflictParameterType*/) {}
}
''');
  }

  test_method_error_conflict_parameterType_notGeneric() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  void m(int a) {}
}
class B {
  void m(String a) {}
}
class C extends A implements B {
  m(a) {}
}
''');
    checkElementText(
        library,
        r'''
class A {
  void m(int a) {}
}
class B {
  void m(String a) {}
}
class C extends A implements B {
  void m(dynamic a/*error: overrideConflictParameterType*/) {}
}
''');
  }

  test_method_error_conflict_returnType_generic() async {
    var library = await _encodeDecodeLibrary(r'''
class A<K, V> {
  V m(K a) {}
}
class B<T> {
  T m(int a) {}
}
class C extends A<int, String> implements B<double> {
  m(a) {}
}
''');
    // TODO(scheglov) test for inference failure error
    checkElementText(
        library,
        r'''
class A<K, V> {
  V m(K a) {}
}
class B<T> {
  T m(int a) {}
}
class C extends A<int, String> implements B<double> {
  dynamic m(int a) {}
}
''');
  }

  test_method_error_conflict_returnType_notGeneric() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  int m() {}
}
class B {
  String m() {}
}
class C extends A implements B {
  m() {}
}
''');
    // TODO(scheglov) test for inference failure error
    checkElementText(
        library,
        r'''
class A {
  int m() {}
}
class B {
  String m() {}
}
class C extends A implements B {
  dynamic m() {}
}
''');
  }

  test_method_error_hasMethod_noParameter_required() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  void m(int a) {}
}
class B extends A {
  m(a, b) {}
}
''');
    // It's an error to add a new required parameter, but it is not a
    // top-level type inference error.
    checkElementText(
        library,
        r'''
class A {
  void m(int a) {}
}
class B extends A {
  void m(int a, dynamic b) {}
}
''');
  }

  test_method_missing_hasMethod_noParameter_named() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  void m(int a) {}
}
class B extends A {
  m(a, {b}) {}
}
''');
    checkElementText(
        library,
        r'''
class A {
  void m(int a) {}
}
class B extends A {
  void m(int a, {dynamic b}) {}
}
''');
  }

  test_method_missing_hasMethod_noParameter_optional() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  void m(int a) {}
}
class B extends A {
  m(a, [b]) {}
}
''');
    checkElementText(
        library,
        r'''
class A {
  void m(int a) {}
}
class B extends A {
  void m(int a, [dynamic b]) {}
}
''');
  }

  test_method_missing_hasMethod_withoutTypes() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  m(a) {}
}
class B extends A {
  m(a) {}
}
''');
    checkElementText(
        library,
        r'''
class A {
  dynamic m(dynamic a) {}
}
class B extends A {
  dynamic m(dynamic a) {}
}
''');
  }

  test_method_missing_noMember() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  int foo(String a) => null;
}
class B extends A {
  m(a) {}
}
''');
    checkElementText(
        library,
        r'''
class A {
  int foo(String a) {}
}
class B extends A {
  dynamic m(dynamic a) {}
}
''');
  }

  test_method_missing_notMethod() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  int m = 42;
}
class B extends A {
  m(a) {}
}
''');
    checkElementText(
        library,
        r'''
class A {
  int m;
}
class B extends A {
  dynamic m(dynamic a) {}
}
''');
  }

  test_method_OK_sequence_extendsExtends_generic() async {
    var library = await _encodeDecodeLibrary(r'''
class A<K, V> {
  V m(K a) {}
}
class B<T> extends A<int, T> {}
class C extends B<String> {
  m(a) {}
}
''');
    checkElementText(
        library,
        r'''
class A<K, V> {
  V m(K a) {}
}
class B<T> extends A<int, T> {
}
class C extends B<String> {
  String m(int a) {}
}
''');
  }

  test_method_OK_sequence_inferMiddle_extendsExtends() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  String m(int a) {}
}
class B extends A {
  m(a) {}
}
class C extends B {
  m(a) {}
}
''');
    checkElementText(
        library,
        r'''
class A {
  String m(int a) {}
}
class B extends A {
  String m(int a) {}
}
class C extends B {
  String m(int a) {}
}
''');
  }

  test_method_OK_sequence_inferMiddle_extendsImplements() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  String m(int a) {}
}
class B implements A {
  m(a) {}
}
class C extends B {
  m(a) {}
}
''');
    checkElementText(
        library,
        r'''
class A {
  String m(int a) {}
}
class B implements A {
  String m(int a) {}
}
class C extends B {
  String m(int a) {}
}
''');
  }

  test_method_OK_sequence_inferMiddle_extendsWith() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  String m(int a) {}
}
class B extends Object with A {
  m(a) {}
}
class C extends B {
  m(a) {}
}
''');
    checkElementText(
        library,
        r'''
class A {
  String m(int a) {}
}
class B extends Object with A {
  synthetic B();
  String m(int a) {}
}
class C extends B {
  String m(int a) {}
}
''');
  }

  test_method_OK_single_extends_direct_generic() async {
    var library = await _encodeDecodeLibrary(r'''
class A<K, V> {
  V m(K a, double b) {}
}
class B extends A<int, String> {
  m(a, b) {}
}
''');
    checkElementText(
        library,
        r'''
class A<K, V> {
  V m(K a, double b) {}
}
class B extends A<int, String> {
  String m(int a, double b) {}
}
''');
  }

  test_method_OK_single_extends_direct_notGeneric() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  String m(int a) {}
}
class B extends A {
  m(a) {}
}
''');
    checkElementText(
        library,
        r'''
class A {
  String m(int a) {}
}
class B extends A {
  String m(int a) {}
}
''');
  }

  test_method_OK_single_extends_direct_notGeneric_named() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  String m(int a, {double b}) {}
}
class B extends A {
  m(a, {b}) {}
}
''');
    checkElementText(
        library,
        r'''
class A {
  String m(int a, {double b}) {}
}
class B extends A {
  String m(int a, {double b}) {}
}
''');
  }

  test_method_OK_single_extends_direct_notGeneric_positional() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  String m(int a, [double b]) {}
}
class B extends A {
  m(a, [b]) {}
}
''');
    checkElementText(
        library,
        r'''
class A {
  String m(int a, [double b]) {}
}
class B extends A {
  String m(int a, [double b]) {}
}
''');
  }

  test_method_OK_single_extends_indirect_generic() async {
    var library = await _encodeDecodeLibrary(r'''
class A<K, V> {
  V m(K a) {}
}
class B<T> extends A<int, T> {}
class C extends B<String> {
  m(a) {}
}
''');
    checkElementText(
        library,
        r'''
class A<K, V> {
  V m(K a) {}
}
class B<T> extends A<int, T> {
}
class C extends B<String> {
  String m(int a) {}
}
''');
  }

  test_method_OK_single_implements_direct_generic() async {
    var library = await _encodeDecodeLibrary(r'''
abstract class A<K, V> {
  V m(K a);
}
class B implements A<int, String> {
  m(a) {}
}
''');
    checkElementText(
        library,
        r'''
abstract class A<K, V> {
  V m(K a);
}
class B implements A<int, String> {
  String m(int a) {}
}
''');
  }

  test_method_OK_single_implements_direct_notGeneric() async {
    var library = await _encodeDecodeLibrary(r'''
abstract class A {
  String m(int a);
}
class B implements A {
  m(a) {}
}
''');
    checkElementText(
        library,
        r'''
abstract class A {
  String m(int a);
}
class B implements A {
  String m(int a) {}
}
''');
  }

  test_method_OK_single_implements_indirect_generic() async {
    var library = await _encodeDecodeLibrary(r'''
abstract class A<K, V> {
  V m(K a);
}
abstract class B<T1, T2> extends A<T2, T1> {}
class C implements B<int, String> {
  m(a) {}
}
''');
    checkElementText(
        library,
        r'''
abstract class A<K, V> {
  V m(K a);
}
abstract class B<T1, T2> extends A<T2, T1> {
}
class C implements B<int, String> {
  int m(String a) {}
}
''');
  }

  test_method_OK_single_withExtends_notGeneric() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  String m(int a) {}
}
class B extends Object with A {
  m(a) {}
}
''');
    checkElementText(
        library,
        r'''
class A {
  String m(int a) {}
}
class B extends Object with A {
  synthetic B();
  String m(int a) {}
}
''');
  }

  test_method_OK_two_extendsImplements_generic() async {
    var library = await _encodeDecodeLibrary(r'''
class A<K, V> {
  V m(K a) {}
}
class B<T> {
  T m(int a) {}
}
class C extends A<int, String> implements B<String> {
  m(a) {}
}
''');
    checkElementText(
        library,
        r'''
class A<K, V> {
  V m(K a) {}
}
class B<T> {
  T m(int a) {}
}
class C extends A<int, String> implements B<String> {
  String m(int a) {}
}
''');
  }

  test_method_OK_two_extendsImplements_notGeneric() async {
    var library = await _encodeDecodeLibrary(r'''
class A {
  String m(int a) {}
}
class B {
  String m(int a) {}
}
class C extends A implements B {
  m(a) {}
}
''');
    checkElementText(
        library,
        r'''
class A {
  String m(int a) {}
}
class B {
  String m(int a) {}
}
class C extends A implements B {
  String m(int a) {}
}
''');
  }

  Future<LibraryElement> _encodeDecodeLibrary(String text) async {
    String path = _p('/test.dart');
    provider.newFile(path, text);
    UnitElementResult result = await driver.getUnitElement(path);
    return result.element.library;
  }

  String _p(String path) => provider.convertPath(path);
}
