// Copyright (c) 2019, 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 'package:analyzer/dart/element/type.dart'; import 'package:nnbd_migration/src/decorated_type.dart'; import 'package:nnbd_migration/src/edit_plan.dart'; import 'package:nnbd_migration/src/hint_action.dart'; import 'package:nnbd_migration/src/nullability_node.dart'; import 'package:test/test.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; import 'migration_visitor_test_base.dart'; main() { defineReflectiveSuite(() { defineReflectiveTests(NodeBuilderTest); }); } @reflectiveTest class NodeBuilderTest extends MigrationVisitorTestBase { /// Gets the [DecoratedType] associated with the function declaration whose /// name matches [search]. DecoratedType decoratedFunctionType(String search) => variables.decoratedElementType( findNode.functionDeclaration(search).declaredElement); DecoratedType decoratedTypeParameterBound(String search) => variables.decoratedTypeParameterBound( findNode.typeParameter(search).declaredElement); Future test_catch_clause_with_stacktrace_with_on() async { await analyze(''' void f() { try {} on String catch (ex, st) {} } '''); var exceptionType = variables.decoratedElementType(findNode.simple('ex').staticElement); expect(exceptionType.node, TypeMatcher()); var stackTraceType = variables.decoratedElementType(findNode.simple('st').staticElement); assertEdge(stackTraceType.node, never, hard: true, checkable: false); } Future test_catch_clause_with_stacktrace_without_on() async { await analyze(''' void f() { try {} catch (ex, st) {} } '''); var exceptionType = variables.decoratedElementType(findNode.simple('ex').staticElement); expect(exceptionType.node.isImmutable, false); var stackTraceType = variables.decoratedElementType(findNode.simple('st').staticElement); assertEdge(stackTraceType.node, never, hard: true, checkable: false); } Future test_catch_clause_without_catch() async { await analyze(''' void f() { try {} on String {} } '''); // No assertions, since no variables are declared; we just want to make sure // we don't crash. } Future test_catch_clause_without_stacktrace_with_on() async { await analyze(''' void f() { try {} on String catch (ex) {} } '''); var exceptionType = variables.decoratedElementType(findNode.simple('ex').staticElement); expect(exceptionType.node, TypeMatcher()); } Future test_catch_clause_without_stacktrace_without_on() async { await analyze(''' void f() { try {} catch (ex) {} } '''); var exceptionType = variables.decoratedElementType(findNode.simple('ex').staticElement); expect(exceptionType.node.isImmutable, false); } Future test_class_alias_synthetic_constructors_no_parameters() async { await analyze(''' class C { C.a(); C.b(); } mixin M {} class D = C with M; '''); var constructors = findElement.class_('D').constructors; expect(constructors, hasLength(2)); var a = findElement.constructor('a', of: 'D'); var aType = variables.decoratedElementType(a); _assertType(aType.type, 'D Function()'); expect(aType.node, same(never)); expect(aType.typeArguments, isEmpty); _assertType(aType.returnType.type, 'D'); expect(aType.returnType.node, same(never)); var b = findElement.constructor('b', of: 'D'); var bType = variables.decoratedElementType(b); _assertType(bType.type, 'D Function()'); expect(bType.node, same(never)); expect(bType.typeArguments, isEmpty); _assertType(bType.returnType.type, 'D'); expect(bType.returnType.node, same(never)); } Future test_class_alias_synthetic_constructors_with_parameters() async { await analyze(''' class C { C.a(int i); C.b([int i]); C.c({int i}); C.d(List x); } mixin M {} class D = C with M; '''); var constructors = findElement.class_('D').constructors; expect(constructors, hasLength(4)); var a = findElement.constructor('a', of: 'D'); var aType = variables.decoratedElementType(a); _assertType(aType.type, 'D Function(int)'); expect(aType.node, same(never)); expect(aType.typeArguments, isEmpty); _assertType(aType.returnType.type, 'D'); expect(aType.returnType.node, same(never)); expect(aType.positionalParameters, hasLength(1)); _assertType(aType.positionalParameters[0].type, 'int'); expect(aType.positionalParameters[0].node, TypeMatcher()); expect(aType.namedParameters, isEmpty); var b = findElement.constructor('b', of: 'D'); var bType = variables.decoratedElementType(b); _assertType(bType.type, 'D Function([int])'); expect(bType.node, same(never)); expect(bType.typeArguments, isEmpty); _assertType(bType.returnType.type, 'D'); expect(bType.returnType.node, same(never)); expect(bType.positionalParameters, hasLength(1)); _assertType(bType.positionalParameters[0].type, 'int'); expect(bType.positionalParameters[0].node, TypeMatcher()); expect(bType.namedParameters, isEmpty); var c = findElement.constructor('c', of: 'D'); var cType = variables.decoratedElementType(c); _assertType(cType.type, 'D Function({int i})'); expect(cType.node, same(never)); expect(cType.typeArguments, isEmpty); _assertType(cType.returnType.type, 'D'); expect(cType.returnType.node, same(never)); expect(cType.positionalParameters, isEmpty); expect(cType.namedParameters, hasLength(1)); expect(cType.namedParameters, contains('i')); _assertType(cType.namedParameters['i'].type, 'int'); expect( cType.namedParameters['i'].node, TypeMatcher()); var d = findElement.constructor('d', of: 'D'); var dType = variables.decoratedElementType(d); _assertType(dType.type, 'D Function(List)'); expect(dType.node, same(never)); expect(dType.typeArguments, isEmpty); _assertType(dType.returnType.type, 'D'); expect(dType.returnType.node, same(never)); expect(dType.positionalParameters, hasLength(1)); _assertType(dType.positionalParameters[0].type, 'List'); expect(dType.positionalParameters[0].node, TypeMatcher()); expect(dType.positionalParameters[0].typeArguments, hasLength(1)); _assertType(dType.positionalParameters[0].typeArguments[0].type, 'int'); expect(dType.positionalParameters[0].typeArguments[0].node, TypeMatcher()); expect(dType.namedParameters, isEmpty); } Future test_class_alias_synthetic_constructors_with_parameters_generic() async { await analyze(''' class C { C(T t); } mixin M {} class D = C with M; '''); var dConstructor = findElement.unnamedConstructor('D'); var dConstructorType = variables.decoratedElementType(dConstructor); _assertType(dConstructorType.type, 'D Function(U)'); expect(dConstructorType.node, same(never)); expect(dConstructorType.typeFormals, isEmpty); _assertType(dConstructorType.returnType.type, 'D'); expect(dConstructorType.returnType.node, same(never)); var typeArguments = dConstructorType.returnType.typeArguments; expect(typeArguments, hasLength(1)); _assertType(typeArguments[0].type, 'U'); expect(typeArguments[0].node, same(never)); var dParams = dConstructorType.positionalParameters; expect(dParams, hasLength(1)); _assertType(dParams[0].type, 'U'); expect(dParams[0].node, TypeMatcher()); } Future test_class_with_default_constructor() async { await analyze(''' class C {} '''); var defaultConstructor = findElement.class_('C').constructors.single; var decoratedConstructorType = variables.decoratedElementType(defaultConstructor); _assertType(decoratedConstructorType.type, 'C Function()'); expect(decoratedConstructorType.node, same(never)); _assertType(decoratedConstructorType.returnType.type, 'C'); expect(decoratedConstructorType.returnType.node, same(never)); } Future test_class_with_default_constructor_generic() async { await analyze(''' class C {} '''); var defaultConstructor = findElement.class_('C').constructors.single; var decoratedConstructorType = variables.decoratedElementType(defaultConstructor); _assertType(decoratedConstructorType.type, 'C Function()'); expect(decoratedConstructorType.node, same(never)); expect(decoratedConstructorType.typeArguments, isEmpty); var returnType = decoratedConstructorType.returnType; _assertType(returnType.type, 'C'); expect(returnType.node, same(never)); expect(returnType.typeArguments, hasLength(2)); _assertType(returnType.typeArguments[0].type, 'T'); expect(returnType.typeArguments[0].node, same(never)); _assertType(returnType.typeArguments[1].type, 'U'); expect(returnType.typeArguments[1].node, same(never)); } Future test_constructor_factory() async { await analyze(''' class C { C._(); factory C() => C._(); } '''); var decoratedType = decoratedConstructorDeclaration('C(').returnType; expect(decoratedType.node, same(never)); } Future test_constructor_metadata() async { await analyze(''' class A { final Object x; const A(this.x); } class C { @A([]) C(); } '''); var node = decoratedTypeAnnotation('int').node; expect(node, TypeMatcher()); } Future test_constructor_returnType_implicit_dynamic() async { await analyze(''' class C { C(); } '''); var decoratedType = decoratedConstructorDeclaration('C(').returnType; expect(decoratedType.node, same(never)); } Future test_constructorFieldInitializer_visit_expression() async { await analyze(''' class C { C() : f = []; Object f; } '''); var node = decoratedTypeAnnotation('int').node; expect(node, TypeMatcher()); } Future test_directSupertypes_class_extends() async { await analyze(''' class C {} class D extends C {} '''); var types = decoratedDirectSupertypes('D'); var decorated = types[findElement.class_('C')]; _assertType(decorated.type, 'C'); expect(decorated.node, same(never)); expect(decorated.typeArguments, hasLength(2)); expect(decorated.typeArguments[0].node, same(decoratedTypeAnnotation('int').node)); expect(decorated.typeArguments[1].node, same(decoratedTypeAnnotation('V> {').node)); } Future test_directSupertypes_class_extends_default() async { await analyze(''' class C {} '''); var types = decoratedDirectSupertypes('C'); var decorated = types[typeProvider.objectType.element]; _assertType(decorated.type, 'Object'); assertEdge(decorated.node, never, hard: true, checkable: false); expect(decorated.typeArguments, isEmpty); } Future test_directSupertypes_class_implements() async { await analyze(''' class C {} class D implements C {} '''); var types = decoratedDirectSupertypes('D'); var decorated = types[findElement.class_('C')]; _assertType(decorated.type, 'C'); expect(decorated.node, same(never)); expect(decorated.typeArguments, hasLength(2)); expect(decorated.typeArguments[0].node, same(decoratedTypeAnnotation('int').node)); expect(decorated.typeArguments[1].node, same(decoratedTypeAnnotation('V> {').node)); } Future test_directSupertypes_class_with() async { await analyze(''' class C {} class D extends Object with C {} '''); var types = decoratedDirectSupertypes('D'); var decorated = types[findElement.class_('C')]; _assertType(decorated.type, 'C'); expect(decorated.node, same(never)); expect(decorated.typeArguments, hasLength(2)); expect(decorated.typeArguments[0].node, same(decoratedTypeAnnotation('int').node)); expect(decorated.typeArguments[1].node, same(decoratedTypeAnnotation('V> {').node)); } Future test_directSupertypes_classAlias_extends() async { await analyze(''' class M {} class C {} class D = C with M; '''); var types = decoratedDirectSupertypes('D'); var decorated = types[findElement.class_('C')]; _assertType(decorated.type, 'C'); expect(decorated.node, same(never)); expect(decorated.typeArguments, hasLength(2)); expect(decorated.typeArguments[0].node, same(decoratedTypeAnnotation('int').node)); expect(decorated.typeArguments[1].node, same(decoratedTypeAnnotation('V> w').node)); } Future test_directSupertypes_classAlias_implements() async { await analyze(''' class M {} class C {} class D = Object with M implements C; '''); var types = decoratedDirectSupertypes('D'); var decorated = types[findElement.class_('C')]; _assertType(decorated.type, 'C'); expect(decorated.node, same(never)); expect(decorated.typeArguments, hasLength(2)); expect(decorated.typeArguments[0].node, same(decoratedTypeAnnotation('int').node)); expect(decorated.typeArguments[1].node, same(decoratedTypeAnnotation('V>;').node)); } Future test_directSupertypes_classAlias_with() async { await analyze(''' class C {} class D = Object with C; '''); var types = decoratedDirectSupertypes('D'); var decorated = types[findElement.class_('C')]; _assertType(decorated.type, 'C'); expect(decorated.node, same(never)); expect(decorated.typeArguments, hasLength(2)); expect(decorated.typeArguments[0].node, same(decoratedTypeAnnotation('int').node)); expect(decorated.typeArguments[1].node, same(decoratedTypeAnnotation('V>;').node)); } Future test_directSupertypes_dartCoreClass() async { await analyze(''' abstract class D extends Iterable {} '''); var types = decoratedDirectSupertypes('D'); var super_ = types.values.single; _assertType(super_.type, 'Iterable'); expect(super_.node, same(never)); expect(super_.typeArguments, hasLength(1)); expect(super_.typeArguments[0].node, same(decoratedTypeAnnotation('V> {').node)); } Future test_directSupertypes_mixin_extends_default() async { await analyze(''' mixin C {} '''); var types = decoratedDirectSupertypes('C'); var decorated = types[typeProvider.objectType.element]; _assertType(decorated.type, 'Object'); assertEdge(decorated.node, never, hard: true, checkable: false); expect(decorated.typeArguments, isEmpty); } Future test_directSupertypes_mixin_implements() async { await analyze(''' class C {} mixin D implements C {} '''); var types = decoratedDirectSupertypes('D'); var decorated = types[findElement.class_('C')]; _assertType(decorated.type, 'C'); expect(decorated.node, same(never)); expect(decorated.typeArguments, hasLength(2)); expect(decorated.typeArguments[0].node, same(decoratedTypeAnnotation('int').node)); expect(decorated.typeArguments[1].node, same(decoratedTypeAnnotation('V> {').node)); } Future test_directSupertypes_mixin_on() async { await analyze(''' class C {} mixin D on C {} '''); var types = decoratedDirectSupertypes('D'); var decorated = types[findElement.class_('C')]; _assertType(decorated.type, 'C'); expect(decorated.node, same(never)); expect(decorated.typeArguments, hasLength(2)); expect(decorated.typeArguments[0].node, same(decoratedTypeAnnotation('int').node)); expect(decorated.typeArguments[1].node, same(decoratedTypeAnnotation('V> {').node)); } Future test_displayName_castType() async { await analyze('f(x) => x as int;'); expect(decoratedTypeAnnotation('int').node.displayName, 'cast type (test.dart:1:14)'); } Future test_displayName_constructedType() async { await analyze(''' class C { factory C() = D; } class D implements C {} '''); expect(decoratedTypeAnnotation('int').node.displayName, 'type argument 0 of constructed type (test.dart:2:19)'); } Future test_displayName_exceptionType_implicit() async { await analyze(''' f(void Function() g) { try { g(); } catch (e) {} } '''); expect( variables .decoratedElementType(findNode.simple('e)').staticElement) .node .displayName, 'f.e (test.dart:4:5)'); } Future test_displayName_exceptionType_no_variable() async { await analyze(''' f(void Function() g) { try { g(); } on String {} } '''); expect(decoratedTypeAnnotation('String').node.displayName, 'exception type (test.dart:4:8)'); } Future test_displayName_exceptionType_variable() async { await analyze(''' f(void Function() g) { try { g(); } on String catch (s) {} } '''); expect(decoratedTypeAnnotation('String').node.displayName, 'f.s (test.dart:4:8)'); } Future test_displayName_explicitParameterType_named() async { await analyze('void f({int x, int y}) {}'); expect(decoratedTypeAnnotation('int x').node.displayName, 'parameter x of f (test.dart:1:9)'); expect(decoratedTypeAnnotation('int y').node.displayName, 'parameter y of f (test.dart:1:16)'); } Future test_displayName_explicitParameterType_positional() async { await analyze('void f(int x, int y, [int z]) {}'); expect(decoratedTypeAnnotation('int x').node.displayName, 'parameter 0 of f (test.dart:1:8)'); expect(decoratedTypeAnnotation('int y').node.displayName, 'parameter 1 of f (test.dart:1:15)'); expect(decoratedTypeAnnotation('int z').node.displayName, 'parameter 2 of f (test.dart:1:23)'); } Future test_displayName_extendedType() async { await analyze('extension E on int {}'); expect(decoratedTypeAnnotation('int').node.displayName, 'extended type (test.dart:1:16)'); } Future test_displayName_field() async { await analyze('class C { int x; }'); expect(decoratedTypeAnnotation('int').node.displayName, 'C.x (test.dart:1:11)'); } Future test_displayName_for_loop_variable() async { await analyze('f(List x) { for (int y in x) {} }'); expect(decoratedTypeAnnotation('int y').node.displayName, 'f.y (test.dart:1:23)'); } Future test_displayName_functionExpressionInvocation_type_argument() async { await analyze('f(g) => g();'); expect(decoratedTypeAnnotation('int').node.displayName, 'type argument (test.dart:1:11)'); } Future test_displayName_listElementType() async { await analyze('f() => [];'); expect(decoratedTypeAnnotation('int').node.displayName, 'list element type (test.dart:1:9)'); } Future test_displayName_mapKeyType() async { await analyze('f() => {};'); expect(decoratedTypeAnnotation('int').node.displayName, 'map key type (test.dart:1:9)'); } Future test_displayName_mapValueType() async { await analyze('f() => {};'); expect(decoratedTypeAnnotation('String').node.displayName, 'map value type (test.dart:1:14)'); } Future test_displayName_methodInvocation_type_argument() async { await analyze('f(x) => x.g();'); expect(decoratedTypeAnnotation('int').node.displayName, 'type argument (test.dart:1:13)'); } Future test_displayName_setElementType() async { await analyze('f() => {};'); expect(decoratedTypeAnnotation('int').node.displayName, 'set element type (test.dart:1:9)'); } Future test_displayName_supertype() async { await analyze(''' class C {} class D extends C {} '''); expect(decoratedTypeAnnotation('int').node.displayName, 'type argument 0 of supertype of D (test.dart:2:19)'); } Future test_displayName_testedType() async { await analyze('f(x) => x is int;'); expect(decoratedTypeAnnotation('int').node.displayName, 'tested type (test.dart:1:14)'); } Future test_displayName_typeArgument() async { await analyze('var x = >[];'); expect(decoratedTypeAnnotation('int').node.displayName, 'type argument 0 of list element type (test.dart:1:15)'); } Future test_displayName_typedef_new_parameter() async { await analyze('typedef F = void Function(int x);'); expect(decoratedTypeAnnotation('int').node.displayName, 'parameter 0 of F (test.dart:1:27)'); } Future test_displayName_typedef_new_returnType() async { await analyze('typedef F = int Function();'); expect(decoratedTypeAnnotation('int').node.displayName, 'return type of F (test.dart:1:13)'); } Future test_displayName_typedef_old_parameter() async { await analyze('typedef void F(int x);'); expect(decoratedTypeAnnotation('int').node.displayName, 'parameter 0 of F (test.dart:1:16)'); } Future test_displayName_typedef_old_returnType() async { await analyze('typedef int F();'); expect(decoratedTypeAnnotation('int').node.displayName, 'return type of F (test.dart:1:9)'); } Future test_displayName_typeParameterBound() async { await analyze('class C {}'); expect(decoratedTypeAnnotation('num').node.displayName, 'bound of C.T (test.dart:1:19)'); } Future test_displayName_typeParameterBound_implicit() async { await analyze('class C {}'); expect( variables .decoratedTypeParameterBound( findElement.class_('C').typeParameters[0]) .node .displayName, 'bound of C.T (test.dart:1:19)'); } Future test_displayName_variable_local() async { await analyze('f() { int x; }'); expect( decoratedTypeAnnotation('int').node.displayName, 'f.x (test.dart:1:7)'); } Future test_displayName_variable_top_level() async { await analyze('int x;'); expect( decoratedTypeAnnotation('int').node.displayName, 'x (test.dart:1:1)'); } Future test_dynamic_type() async { await analyze(''' dynamic f() {} '''); var decoratedType = decoratedTypeAnnotation('dynamic'); expect(decoratedFunctionType('f').returnType, same(decoratedType)); assertNoEdge(always, decoratedType.node); } Future test_extended_type_no_add_hint_actions() async { await analyze(''' class A extends Object {} '''); final node = decoratedTypeAnnotation('Object').node; expect(node.hintActions, isEmpty); } Future test_field_type_implicit_dynamic() async { await analyze(''' class C { var x; } '''); var decoratedType = variables.decoratedElementType(findNode.simple('x').staticElement); expect(decoratedType.node.isImmutable, false); } Future test_field_type_inferred() async { await analyze(''' class C { var x = 1; } '''); var decoratedType = variables.decoratedElementType(findNode.simple('x').staticElement); expect(decoratedType.node, TypeMatcher()); } Future test_field_type_inferred_dynamic() async { await analyze(''' dynamic f() {} class C { var x = f(); } '''); var decoratedType = variables.decoratedElementType(findNode.simple('x').staticElement); expect(decoratedType.node.isImmutable, false); } Future test_field_type_simple() async { await analyze(''' class C { int f = 0; } '''); var decoratedType = decoratedTypeAnnotation('int'); expect(decoratedType.node, TypeMatcher()); expect( variables.decoratedElementType( findNode.fieldDeclaration('f').fields.variables[0].declaredElement), same(decoratedType)); } Future test_fieldFormalParameter_function_namedParameter_typed() async { await analyze(''' class C { Object f; C(void this.f({int i})); } '''); var ctor = findElement.unnamedConstructor('C'); var ctorParam = ctor.parameters[0]; var ctorType = variables.decoratedElementType(ctor); var ctorParamType = variables.decoratedElementType(ctorParam); expect(ctorType.positionalParameters[0], same(ctorParamType)); expect(ctorParamType.node, TypeMatcher()); expect(ctorParamType.namedParameters['i'], same(decoratedTypeAnnotation('int'))); } Future test_fieldFormalParameter_function_namedParameter_untyped() async { await analyze(''' class C { Object f; C(void this.f({i})); } '''); var ctor = findElement.unnamedConstructor('C'); var ctorParam = ctor.parameters[0]; var ctorType = variables.decoratedElementType(ctor); var ctorParamType = variables.decoratedElementType(ctorParam); expect(ctorType.positionalParameters[0], same(ctorParamType)); expect(ctorParamType.node, TypeMatcher()); _assertType(ctorParamType.namedParameters['i'].type, 'dynamic'); expect(ctorParamType.namedParameters['i'].node.isImmutable, false); } Future test_fieldFormalParameter_function_positionalParameter_typed() async { await analyze(''' class C { Object f; C(void this.f(int i)); } '''); var ctor = findElement.unnamedConstructor('C'); var ctorParam = ctor.parameters[0]; var ctorType = variables.decoratedElementType(ctor); var ctorParamType = variables.decoratedElementType(ctorParam); expect(ctorType.positionalParameters[0], same(ctorParamType)); expect(ctorParamType.node, TypeMatcher()); expect(ctorParamType.positionalParameters[0], same(decoratedTypeAnnotation('int'))); } Future test_fieldFormalParameter_function_positionalParameter_untyped() async { await analyze(''' class C { Object f; C(void this.f(i)); } '''); var ctor = findElement.unnamedConstructor('C'); var ctorParam = ctor.parameters[0]; var ctorType = variables.decoratedElementType(ctor); var ctorParamType = variables.decoratedElementType(ctorParam); expect(ctorType.positionalParameters[0], same(ctorParamType)); expect(ctorParamType.node, TypeMatcher()); _assertType(ctorParamType.positionalParameters[0].type, 'dynamic'); expect(ctorParamType.positionalParameters[0].node.isImmutable, false); } Future test_fieldFormalParameter_function_return_typed() async { await analyze(''' class C { Object f; C(int this.f()); } '''); var ctor = findElement.unnamedConstructor('C'); var ctorParam = ctor.parameters[0]; var ctorType = variables.decoratedElementType(ctor); var ctorParamType = variables.decoratedElementType(ctorParam); expect(ctorType.positionalParameters[0], same(ctorParamType)); expect(ctorParamType.node, TypeMatcher()); expect(ctorParamType.returnType, same(decoratedTypeAnnotation('int'))); } Future test_fieldFormalParameter_function_return_untyped() async { await analyze(''' class C { Object f; C(this.f()) {} } '''); var ctor = findElement.unnamedConstructor('C'); var ctorParam = ctor.parameters[0]; var ctorType = variables.decoratedElementType(ctor); var ctorParamType = variables.decoratedElementType(ctorParam); expect(ctorType.positionalParameters[0], same(ctorParamType)); expect(ctorParamType.node, TypeMatcher()); _assertType(ctorParamType.returnType.type, 'dynamic'); expect(ctorParamType.returnType.node.isImmutable, false); } Future test_fieldFormalParameter_named_no_default_required_hint() async { await analyze(''' class C { String s; C({/*required*/ this.s}); } '''); expect( variables.getRequiredHint( testSource, findNode.fieldFormalParameter('this.s')), isNotNull); } Future test_fieldFormalParameter_named_no_default_required_hint_annotation() async { await analyze(''' class C { String s; C({@deprecated /*required*/ this.s}); } '''); expect( variables.getRequiredHint( testSource, findNode.fieldFormalParameter('this.s')), isNotNull); } Future test_fieldFormalParameter_named_no_default_required_hint_function_typed() async { await analyze(''' class C { String Function() s; C({/*required*/ String this.s()}); } '''); expect( variables.getRequiredHint( testSource, findNode.fieldFormalParameter('this.s')), isNotNull); } Future test_fieldFormalParameter_named_no_default_required_hint_type() async { await analyze(''' class C { String s; C({/*required*/ String this.s}); } '''); expect( variables.getRequiredHint( testSource, findNode.fieldFormalParameter('this.s')), isNotNull); } Future test_fieldFormalParameter_typed() async { await analyze(''' class C { int i; C.named(int this.i); } '''); var decoratedConstructorParamType = decoratedConstructorDeclaration('named').positionalParameters[0]; expect(decoratedTypeAnnotation('int this'), same(decoratedConstructorParamType)); _assertType(decoratedConstructorParamType.type, 'int'); expect(decoratedConstructorParamType.node, TypeMatcher()); // Note: the edge builder will connect this node to the node for the type of // the field. } Future test_fieldFormalParameter_untyped() async { await analyze(''' class C { int i; C.named(this.i); } '''); var decoratedConstructorParamType = decoratedConstructorDeclaration('named').positionalParameters[0]; _assertType(decoratedConstructorParamType.type, 'int'); expect(decoratedConstructorParamType.node, TypeMatcher()); // Note: the edge builder will unify this implicit type with the type of the // field. } Future test_formalParameter_named_no_default_required_hint() async { await analyze(''' void f({/*required*/ String s}) {} '''); expect(variables.getRequiredHint(testSource, findNode.simpleParameter('s')), isNotNull); } Future test_formalParameter_named_no_default_required_hint_annotation() async { await analyze(''' void f({@deprecated /*required*/ String s}) {} '''); expect(variables.getRequiredHint(testSource, findNode.simpleParameter('s')), isNotNull); } Future test_formalParameter_named_no_default_required_hint_covariant() async { await analyze(''' class C { void f({/*required*/ covariant String s}) {} } '''); expect( variables.getRequiredHint( testSource, findNode.simpleParameter('String s')), isNotNull); } Future test_formalParameter_named_no_default_required_hint_final_type() async { await analyze(''' void f({/*required*/ final String s}) {} '''); expect(variables.getRequiredHint(testSource, findNode.simpleParameter('s')), isNotNull); } Future test_formalParameter_named_no_default_required_hint_no_type() async { await analyze(''' void f({/*required*/ s}) {} '''); expect(variables.getRequiredHint(testSource, findNode.simpleParameter('s')), isNotNull); } Future test_formalParameter_named_no_default_required_hint_var() async { await analyze(''' void f({/*required*/ var s}) {} '''); expect(variables.getRequiredHint(testSource, findNode.simpleParameter('s')), isNotNull); } Future test_function_explicit_returnType() async { await analyze(''' class C { int f() => null; } '''); var decoratedType = decoratedTypeAnnotation('int'); expect( decoratedType.node.displayName, 'return type of C.f (test.dart:2:3)'); } Future test_function_generic_bounded() async { await analyze(''' T f(T t) => t; '''); var bound = decoratedTypeParameterBound('T extends'); expect(decoratedTypeAnnotation('Object'), same(bound)); expect(bound.node, isNot(always)); expect(bound.type, typeProvider.objectType); } Future test_function_generic_implicit_bound() async { await analyze(''' T f(T t) => t; '''); var bound = decoratedTypeParameterBound('T>'); assertEdge(always, bound.node, hard: false); expect(bound.type, same(typeProvider.objectType)); } Future test_function_metadata() async { await analyze(''' class A { final Object x; const A(this.x); } @A([]) f() {} '''); var node = decoratedTypeAnnotation('int').node; expect(node, TypeMatcher()); } Future test_functionExpression() async { await analyze(''' void f() { var x = (int i) => 1; } '''); var functionExpressionElement = findNode.simpleParameter('int i').declaredElement.enclosingElement; var decoratedType = variables.decoratedElementType(functionExpressionElement); expect(decoratedType.positionalParameters[0], same(decoratedTypeAnnotation('int i'))); expect(decoratedType.node, same(never)); expect( decoratedType.returnType.node, TypeMatcher()); } Future test_functionExpression_returns_bottom() async { await analyze(''' void f() { var x = (int i) => throw 'foo'; } '''); var functionExpressionElement = findNode.simpleParameter('int i').declaredElement.enclosingElement; var decoratedType = variables.decoratedElementType(functionExpressionElement); expect( decoratedType.returnType.node, TypeMatcher()); } Future test_functionTypeAlias_generic() async { await analyze(''' typedef T F(U u); '''); var element = findElement.typeAlias('F'); var decoratedType = variables.decoratedElementType(element.aliasedElement); var t = element.typeParameters[0]; var u = element.typeParameters[1]; // typeFormals should be empty because this is not a generic function type, // it's a generic typedef that defines an ordinary (non-generic) function // type. expect(decoratedType.typeFormals, isEmpty); expect(decoratedType.returnType, same(decoratedTypeAnnotation('T F'))); expect( (decoratedType.returnType.type as TypeParameterType).element, same(t)); expect( decoratedType.returnType.node, TypeMatcher()); expect( (decoratedType.positionalParameters[0].type as TypeParameterType) .element, same(u)); expect(decoratedType.positionalParameters[0].node, TypeMatcher()); } Future test_functionTypeAlias_implicit_return_type() async { await analyze(''' typedef F(); '''); var decoratedType = variables .decoratedElementType(findElement.typeAlias('F').aliasedElement); expect(decoratedType.returnType.type.isDynamic, isTrue); expect(decoratedType.returnType.node.isImmutable, false); expect(decoratedType.typeFormals, isEmpty); } Future test_functionTypeAlias_simple() async { await analyze(''' typedef int F(String s); '''); var decoratedType = variables .decoratedElementType(findElement.typeAlias('F').aliasedElement); expect(decoratedType.returnType, same(decoratedTypeAnnotation('int'))); expect(decoratedType.typeFormals, isEmpty); expect(decoratedType.positionalParameters[0], same(decoratedTypeAnnotation('String'))); } Future test_functionTypedFormalParameter_named_no_default_required_hint() async { await analyze(''' void f({/*required*/ void s()}) {} '''); expect( variables.getRequiredHint( testSource, findNode.functionTypedFormalParameter('s')), isNotNull); } Future test_functionTypedFormalParameter_named_no_default_required_hint_no_return() async { await analyze(''' void f({/*required*/ s()}) {} '''); expect( variables.getRequiredHint( testSource, findNode.functionTypedFormalParameter('s')), isNotNull); } Future test_functionTypedFormalParameter_namedParameter_typed() async { await analyze(''' void f(void g({int i})) {} '''); var f = findElement.function('f'); var g = f.parameters[0]; var fType = variables.decoratedElementType(f); var gType = variables.decoratedElementType(g); expect(fType.positionalParameters[0], same(gType)); expect(gType.node, TypeMatcher()); expect(gType.namedParameters['i'], same(decoratedTypeAnnotation('int'))); } Future test_functionTypedFormalParameter_namedParameter_untyped() async { await analyze(''' void f(void g({i})) {} '''); var f = findElement.function('f'); var g = f.parameters[0]; var fType = variables.decoratedElementType(f); var gType = variables.decoratedElementType(g); expect(fType.positionalParameters[0], same(gType)); expect(gType.node, TypeMatcher()); _assertType(gType.namedParameters['i'].type, 'dynamic'); expect(gType.namedParameters['i'].node.isImmutable, false); } Future test_functionTypedFormalParameter_positionalParameter_typed() async { await analyze(''' void f(void g(int i)) {} '''); var f = findElement.function('f'); var g = f.parameters[0]; var fType = variables.decoratedElementType(f); var gType = variables.decoratedElementType(g); expect(fType.positionalParameters[0], same(gType)); expect(gType.node, TypeMatcher()); expect(gType.positionalParameters[0], same(decoratedTypeAnnotation('int'))); } Future test_functionTypedFormalParameter_positionalParameter_untyped() async { await analyze(''' void f(void g(i)) {} '''); var f = findElement.function('f'); var g = f.parameters[0]; var fType = variables.decoratedElementType(f); var gType = variables.decoratedElementType(g); expect(fType.positionalParameters[0], same(gType)); expect(gType.node, TypeMatcher()); _assertType(gType.positionalParameters[0].type, 'dynamic'); expect(gType.positionalParameters[0].node.isImmutable, false); } Future test_functionTypedFormalParameter_return_typed() async { await analyze(''' void f(int g()) {} '''); var f = findElement.function('f'); var g = f.parameters[0]; var fType = variables.decoratedElementType(f); var gType = variables.decoratedElementType(g); expect(fType.positionalParameters[0], same(gType)); expect(gType.node, TypeMatcher()); expect(gType.returnType, same(decoratedTypeAnnotation('int'))); } Future test_functionTypedFormalParameter_return_untyped() async { await analyze(''' void f(g()) {} '''); var f = findElement.function('f'); var g = f.parameters[0]; var fType = variables.decoratedElementType(f); var gType = variables.decoratedElementType(g); expect(fType.positionalParameters[0], same(gType)); expect(gType.node, TypeMatcher()); _assertType(gType.returnType.type, 'dynamic'); expect(gType.returnType.node.isImmutable, false); } Future test_genericFunctionType_formals() async { await analyze(''' void f(T Function(U) x) {} '''); var decoratedType = decoratedGenericFunctionTypeAnnotation('T Function'); expect(decoratedFunctionType('f').positionalParameters[0], same(decoratedType)); expect(decoratedType.node, TypeMatcher()); _assertType(decoratedType.type, 'T Function(U)'); expect(decoratedType.typeFormals, hasLength(2)); var t = decoratedType.typeFormals[0]; var u = decoratedType.typeFormals[1]; expect( (decoratedType.returnType.type as TypeParameterType).element, same(t)); expect( (decoratedType.positionalParameters[0].type as TypeParameterType) .element, same(u)); } Future test_genericFunctionType_namedParameterType() async { await analyze(''' void f(void Function({int y}) x) {} '''); var decoratedType = decoratedGenericFunctionTypeAnnotation('void Function({int y})'); expect(decoratedFunctionType('f').positionalParameters[0], same(decoratedType)); expect(decoratedType.node, TypeMatcher()); var decoratedIntType = decoratedTypeAnnotation('int'); expect(decoratedType.namedParameters['y'], same(decoratedIntType)); expect(decoratedIntType.node, isNotNull); expect(decoratedIntType.node, isNot(never)); } Future test_genericFunctionType_returnType() async { await analyze(''' void f(int Function() x) {} '''); var decoratedType = decoratedGenericFunctionTypeAnnotation('int Function()'); expect(decoratedFunctionType('f').positionalParameters[0], same(decoratedType)); expect(decoratedType.node, TypeMatcher()); var decoratedIntType = decoratedTypeAnnotation('int'); expect(decoratedType.returnType, same(decoratedIntType)); expect(decoratedIntType.node, isNotNull); expect(decoratedIntType.node, isNot(never)); expect(decoratedType.returnType.node.displayName, 'return type of parameter 0 of f (test.dart:1:8)'); } Future test_genericFunctionType_syntax_inferred_dynamic_return() async { await analyze(''' abstract class C { Function() f(); } '''); var decoratedFType = decoratedMethodType('f'); var decoratedFReturnType = decoratedFType.returnType; var decoratedFReturnReturnType = decoratedFReturnType.returnType; _assertType(decoratedFReturnReturnType.type, 'dynamic'); expect(decoratedFReturnReturnType.node.isImmutable, false); } Future test_genericFunctionType_unnamedParameterType() async { await analyze(''' void f(void Function(int) x) {} '''); var decoratedType = decoratedGenericFunctionTypeAnnotation('void Function(int)'); expect(decoratedFunctionType('f').positionalParameters[0], same(decoratedType)); expect(decoratedType.node, TypeMatcher()); var decoratedIntType = decoratedTypeAnnotation('int'); expect(decoratedType.positionalParameters[0], same(decoratedIntType)); expect(decoratedIntType.node, isNotNull); expect(decoratedIntType.node, isNot(never)); } Future test_genericTypeAlias_generic_inner() async { await analyze(''' typedef F = T Function(U u); '''); var element = findElement.typeAlias('F'); var decoratedType = variables.decoratedElementType(element.aliasedElement); expect(decoratedType, same(decoratedGenericFunctionTypeAnnotation('T Function'))); expect(decoratedType.typeFormals, hasLength(2)); var t = decoratedType.typeFormals[0]; var u = decoratedType.typeFormals[1]; expect(decoratedType.returnType, same(decoratedTypeAnnotation('T F'))); expect( (decoratedType.returnType.type as TypeParameterType).element, same(t)); expect( decoratedType.returnType.node, TypeMatcher()); expect( (decoratedType.positionalParameters[0].type as TypeParameterType) .element, same(u)); expect(decoratedType.positionalParameters[0].node, TypeMatcher()); } Future test_genericTypeAlias_generic_outer() async { await analyze(''' typedef F = T Function(U u); '''); var element = findElement.typeAlias('F'); var decoratedType = variables.decoratedElementType(element.aliasedElement); expect(decoratedType, same(decoratedGenericFunctionTypeAnnotation('T Function'))); var t = element.typeParameters[0]; var u = element.typeParameters[1]; // typeFormals should be empty because this is not a generic function type, // it's a generic typedef that defines an ordinary (non-generic) function // type. expect(decoratedType.typeFormals, isEmpty); expect(decoratedType.returnType, same(decoratedTypeAnnotation('T F'))); expect( (decoratedType.returnType.type as TypeParameterType).element, same(t)); expect( decoratedType.returnType.node, TypeMatcher()); expect( (decoratedType.positionalParameters[0].type as TypeParameterType) .element, same(u)); expect(decoratedType.positionalParameters[0].node, TypeMatcher()); } Future test_genericTypeAlias_implicit_return_type() async { await analyze(''' typedef F = Function(); '''); var decoratedType = variables .decoratedElementType(findElement.typeAlias('F').aliasedElement); expect(decoratedType, same(decoratedGenericFunctionTypeAnnotation('Function'))); expect(decoratedType.returnType.type.isDynamic, isTrue); expect(decoratedType.returnType.node.isImmutable, false); expect(decoratedType.typeFormals, isEmpty); } Future test_genericTypeAlias_simple() async { await analyze(''' typedef F = int Function(String s); '''); var decoratedType = variables .decoratedElementType(findElement.typeAlias('F').aliasedElement); expect(decoratedType, same(decoratedGenericFunctionTypeAnnotation('int Function'))); expect(decoratedType.returnType, same(decoratedTypeAnnotation('int'))); expect(decoratedType.typeFormals, isEmpty); expect(decoratedType.positionalParameters[0], same(decoratedTypeAnnotation('String'))); expect(decoratedType.returnType.node.displayName, 'return type of F (test.dart:1:13)'); } Future test_implicit_type_nested_no_add_hint_actions() async { await analyze(''' var x = [1]; '''); final node = variables .decoratedElementType(findNode .topLevelVariableDeclaration('x') .variables .variables[0] .declaredElement) .typeArguments[0] .node; expect(node.hintActions, isEmpty); } Future test_implicit_type_no_add_hint_actions() async { await analyze(''' var x = 1; '''); final node = variables .decoratedElementType(findNode .topLevelVariableDeclaration('x') .variables .variables[0] .declaredElement) .node; expect(node.hintActions, isEmpty); } Future test_interfaceType_generic_instantiate_to_dynamic() async { await analyze(''' void f(List x) {} '''); var decoratedListType = decoratedTypeAnnotation('List'); expect(decoratedFunctionType('f').positionalParameters[0], same(decoratedListType)); expect(decoratedListType.node, isNotNull); expect(decoratedListType.node, isNot(never)); var decoratedArgType = decoratedListType.typeArguments[0]; expect(decoratedArgType.node.isImmutable, false); } Future test_interfaceType_generic_instantiate_to_function_type() async { await analyze(''' class C {} void f(C x) {} '''); var decoratedCType = decoratedTypeAnnotation('C x'); expect(decoratedFunctionType('f').positionalParameters[0], same(decoratedCType)); expect(decoratedCType.node, TypeMatcher()); expect(decoratedCType.typeArguments, hasLength(1)); var decoratedArgType = decoratedCType.typeArguments[0]; expect(decoratedArgType.node, TypeMatcher()); expect(decoratedArgType.typeArguments, isEmpty); var decoratedArgReturnType = decoratedArgType.returnType; expect(decoratedArgReturnType.node, TypeMatcher()); expect(decoratedArgReturnType.typeArguments, isEmpty); } Future test_interfaceType_generic_instantiate_to_function_type_void() async { await analyze(''' class C {} void f(C x) {} '''); var decoratedCType = decoratedTypeAnnotation('C x'); expect(decoratedFunctionType('f').positionalParameters[0], same(decoratedCType)); expect(decoratedCType.node, TypeMatcher()); expect(decoratedCType.typeArguments, hasLength(1)); var decoratedArgType = decoratedCType.typeArguments[0]; expect(decoratedArgType.node, TypeMatcher()); expect(decoratedArgType.typeArguments, isEmpty); var decoratedArgReturnType = decoratedArgType.returnType; expect(decoratedArgReturnType.node.isImmutable, false); expect(decoratedArgReturnType.typeArguments, isEmpty); } Future test_interfaceType_generic_instantiate_to_generic_type() async { await analyze(''' class C {} class D> {} void f(D x) {} '''); var decoratedDType = decoratedTypeAnnotation('D x'); expect(decoratedFunctionType('f').positionalParameters[0], same(decoratedDType)); expect(decoratedDType.node, TypeMatcher()); expect(decoratedDType.typeArguments, hasLength(1)); var decoratedArgType = decoratedDType.typeArguments[0]; expect(decoratedArgType.node, TypeMatcher()); expect(decoratedArgType.typeArguments, hasLength(1)); var decoratedArgArgType = decoratedArgType.typeArguments[0]; expect(decoratedArgArgType.node, TypeMatcher()); expect(decoratedArgArgType.typeArguments, isEmpty); } Future test_interfaceType_generic_instantiate_to_generic_type_2() async { await analyze(''' class C {} class D, U extends C> {} void f(D x) {} '''); var decoratedDType = decoratedTypeAnnotation('D x'); expect(decoratedFunctionType('f').positionalParameters[0], same(decoratedDType)); expect(decoratedDType.node, TypeMatcher()); expect(decoratedDType.typeArguments, hasLength(2)); var decoratedArg0Type = decoratedDType.typeArguments[0]; expect(decoratedArg0Type.node, TypeMatcher()); expect(decoratedArg0Type.typeArguments, hasLength(2)); var decoratedArg0Arg0Type = decoratedArg0Type.typeArguments[0]; expect(decoratedArg0Arg0Type.node, TypeMatcher()); expect(decoratedArg0Arg0Type.typeArguments, isEmpty); var decoratedArg0Arg1Type = decoratedArg0Type.typeArguments[1]; expect(decoratedArg0Arg1Type.node, TypeMatcher()); expect(decoratedArg0Arg1Type.typeArguments, isEmpty); var decoratedArg1Type = decoratedDType.typeArguments[1]; expect(decoratedArg1Type.node, TypeMatcher()); expect(decoratedArg1Type.typeArguments, hasLength(2)); var decoratedArg1Arg0Type = decoratedArg1Type.typeArguments[0]; expect(decoratedArg1Arg0Type.node, TypeMatcher()); expect(decoratedArg1Arg0Type.typeArguments, isEmpty); var decoratedArg1Arg1Type = decoratedArg1Type.typeArguments[1]; expect(decoratedArg1Arg1Type.node, TypeMatcher()); expect(decoratedArg1Arg1Type.typeArguments, isEmpty); } Future test_interfaceType_generic_instantiate_to_object() async { await analyze(''' class C {} void f(C x) {} '''); var decoratedListType = decoratedTypeAnnotation('C x'); expect(decoratedFunctionType('f').positionalParameters[0], same(decoratedListType)); expect(decoratedListType.node, TypeMatcher()); expect(decoratedListType.typeArguments, hasLength(1)); var decoratedArgType = decoratedListType.typeArguments[0]; expect(decoratedArgType.node, TypeMatcher()); expect(decoratedArgType.typeArguments, isEmpty); } Future test_interfaceType_typeParameter() async { await analyze(''' void f(List x) {} '''); var decoratedListType = decoratedTypeAnnotation('List'); expect(decoratedFunctionType('f').positionalParameters[0], same(decoratedListType)); expect(decoratedListType.node, isNotNull); expect(decoratedListType.node, isNot(never)); var decoratedIntType = decoratedTypeAnnotation('int'); expect(decoratedListType.typeArguments[0], same(decoratedIntType)); expect(decoratedIntType.node, isNotNull); expect(decoratedIntType.node, isNot(never)); } Future test_local_function() async { await analyze(''' void f() { int g(int i) => 1; } '''); var decoratedType = decoratedFunctionType('g'); expect(decoratedType.returnType, same(decoratedTypeAnnotation('int g'))); expect(decoratedType.positionalParameters[0], same(decoratedTypeAnnotation('int i'))); expect(decoratedType.node, same(never)); } Future test_localVariable_type_implicit_dynamic() async { await analyze(''' main() { var x; } '''); var decoratedType = variables.decoratedElementType(findNode.simple('x').staticElement); expect(decoratedType.node.isImmutable, false); } Future test_localVariable_type_inferred() async { await analyze(''' main() { var x = 1; } '''); var decoratedType = variables.decoratedElementType(findNode.simple('x').staticElement); expect(decoratedType.node, TypeMatcher()); } Future test_localVariable_type_inferred_dynamic() async { await analyze(''' dynamic f() {} main() { var x = f(); } '''); var decoratedType = variables.decoratedElementType(findNode.simple('x').staticElement); expect(decoratedType.node.isImmutable, false); } Future test_localVariable_type_inferred_function() async { await analyze(''' main() { var x = () => 1; } '''); var decoratedType = variables.decoratedElementType(findNode.simple('x').staticElement); expect(decoratedType.returnType.node.displayName, 'return type of main.x (test.dart:2:7)'); } Future test_localVariable_type_inferred_generic() async { await analyze(''' main() { var x = {1: 2}; } '''); var decoratedType = variables.decoratedElementType(findNode.simple('x').staticElement); expect(decoratedType.typeArguments[0].node.displayName, 'type argument 0 of main.x (test.dart:2:7)'); expect(decoratedType.typeArguments[1].node.displayName, 'type argument 1 of main.x (test.dart:2:7)'); } Future test_method_generic_bounded() async { await analyze(''' class C { T f(T t) => t; } '''); var bound = decoratedTypeParameterBound('T extends'); expect(decoratedTypeAnnotation('Object'), same(bound)); expect(bound.node, isNot(always)); expect(bound.type, typeProvider.objectType); } Future test_method_generic_implicit_bound() async { await analyze(''' class C { T f(T t) => t; } '''); var bound = decoratedTypeParameterBound('T>'); assertEdge(always, bound.node, hard: false); expect(bound.type, same(typeProvider.objectType)); } Future test_method_metadata() async { await analyze(''' class A { final Object x; const A(this.x); } class C { @A([]) f() {} } '''); var node = decoratedTypeAnnotation('int').node; expect(node, TypeMatcher()); } Future test_method_parameterType_implicit_dynamic() async { await analyze(''' class C { void f(x) {} } '''); var decoratedType = decoratedMethodType('f').positionalParameters[0]; expect(decoratedType.node.isImmutable, false); } Future test_method_parameterType_implicit_dynamic_named() async { await analyze(''' class C { void f({x}) {} } '''); var decoratedType = decoratedMethodType('f').namedParameters['x']; expect(decoratedType.node.isImmutable, false); } Future test_method_parameterType_inferred() async { await analyze(''' class B { void f(int x) {} } class C extends B { void f/*C*/(x) {} } '''); var decoratedType = decoratedMethodType('f/*C*/').positionalParameters[0]; expect(decoratedType.node, TypeMatcher()); } Future test_method_parameterType_inferred_dynamic() async { await analyze(''' class B { void f(dynamic x) {} } class C extends B { void f/*C*/(x) {} } '''); var decoratedType = decoratedMethodType('f/*C*/').positionalParameters[0]; expect(decoratedType.node.isImmutable, false); } Future test_method_parameterType_inferred_dynamic_named() async { await analyze(''' class B { void f({dynamic x = 0}) {} } class C extends B { void f/*C*/({x = 0}) {} } '''); var decoratedType = decoratedMethodType('f/*C*/').namedParameters['x']; expect(decoratedType.node.isImmutable, false); } Future test_method_parameterType_inferred_generic_function_typed_no_bound() async { await analyze(''' class B { void f/*B*/(T Function() x) {} } class C extends B { void f/*C*/(x) {} } '''); var decoratedBaseType = decoratedMethodType('f/*B*/').positionalParameters[0]; var decoratedType = decoratedMethodType('f/*C*/').positionalParameters[0]; var decoratedTypeFormalBound = decoratedTypeParameterBounds .get((decoratedType.type as FunctionType).typeFormals[0]); _assertType(decoratedTypeFormalBound.type, 'Object'); var decoratedBaseTypeFormalBound = decoratedTypeParameterBounds .get((decoratedBaseType.type as FunctionType).typeFormals[0]); expect(decoratedTypeFormalBound.node, isNot(same(decoratedBaseTypeFormalBound.node))); } Future test_method_parameterType_inferred_generic_function_typed_with_bound() async { await analyze(''' class B { void f/*B*/(T Function() x) {} } class C extends B { void f/*C*/(x) {} } '''); var decoratedBaseType = decoratedMethodType('f/*B*/').positionalParameters[0]; var decoratedType = decoratedMethodType('f/*C*/').positionalParameters[0]; var decoratedTypeFormalBound = decoratedTypeParameterBounds .get((decoratedType.type as FunctionType).typeFormals[0]); _assertType(decoratedTypeFormalBound.type, 'num'); var decoratedBaseTypeFormalBound = decoratedTypeParameterBounds .get((decoratedBaseType.type as FunctionType).typeFormals[0]); expect(decoratedTypeFormalBound.node, isNot(same(decoratedBaseTypeFormalBound.node))); } Future test_method_parameterType_inferred_named() async { await analyze(''' class B { void f({int x = 0}) {} } class C extends B { void f/*C*/({x = 0}) {} } '''); var decoratedType = decoratedMethodType('f/*C*/').namedParameters['x']; expect(decoratedType.node, TypeMatcher()); } Future test_method_returnType_implicit_dynamic() async { await analyze(''' class C { f() => 1; } '''); var decoratedType = decoratedMethodType('f').returnType; expect(decoratedType.node.isImmutable, false); } Future test_method_returnType_inferred() async { await analyze(''' class B { int f() => 1; } class C extends B { f/*C*/() => 1; } '''); var decoratedType = decoratedMethodType('f/*C*/').returnType; expect(decoratedType.node, TypeMatcher()); } Future test_method_returnType_inferred_dynamic() async { await analyze(''' class B { dynamic f() => 1; } class C extends B { f/*C*/() => 1; } '''); var decoratedType = decoratedMethodType('f/*C*/').returnType; expect(decoratedType.node.isImmutable, false); } Future test_parameters() async { await analyze(''' void foo({List values}) { values.where((i) => true); } '''); // No assertions; just checking that it doesn't crash. } Future test_topLevelFunction_parameterType_implicit_dynamic() async { await analyze(''' void f(x) {} '''); var decoratedType = variables.decoratedElementType(findNode.simple('x').staticElement); expect(decoratedFunctionType('f').positionalParameters[0], same(decoratedType)); expect(decoratedType.type.isDynamic, isTrue); } Future test_topLevelFunction_parameterType_named_no_default() async { await analyze(''' void f({String s}) {} '''); var decoratedType = decoratedTypeAnnotation('String'); var functionType = decoratedFunctionType('f'); expect(functionType.namedParameters['s'], same(decoratedType)); expect(decoratedType.node, isNotNull); expect(decoratedType.node, isNot(never)); expect(decoratedType.node, isNot(always)); expect(functionType.namedParameters['s'].node.isPossiblyOptional, true); } Future test_topLevelFunction_parameterType_named_no_default_required() async { addMetaPackage(); await analyze(''' import 'package:meta/meta.dart'; void f({@required String s}) {} '''); var decoratedType = decoratedTypeAnnotation('String'); var functionType = decoratedFunctionType('f'); expect(functionType.namedParameters['s'], same(decoratedType)); expect(decoratedType.node, isNotNull); expect(decoratedType.node, isNot(never)); expect(decoratedType.node, isNot(always)); expect(functionType.namedParameters['s'].node.isPossiblyOptional, false); } Future test_topLevelFunction_parameterType_named_no_default_required_hint() async { addMetaPackage(); await analyze(''' import 'package:meta/meta.dart'; void f({/*required*/ String s}) {} '''); var decoratedType = decoratedTypeAnnotation('String'); var functionType = decoratedFunctionType('f'); expect(functionType.namedParameters['s'], same(decoratedType)); expect(decoratedType.node, isNotNull); expect(decoratedType.node, isNot(never)); expect(decoratedType.node, isNot(always)); expect(functionType.namedParameters['s'].node.isPossiblyOptional, false); expect(variables.getRequiredHint(testSource, findNode.simpleParameter('s')), isNotNull); } Future test_topLevelFunction_parameterType_named_with_default() async { await analyze(''' void f({String s: 'x'}) {} '''); var decoratedType = decoratedTypeAnnotation('String'); var functionType = decoratedFunctionType('f'); expect(functionType.namedParameters['s'], same(decoratedType)); expect(decoratedType.node, isNotNull); expect(decoratedType.node, isNot(never)); expect(functionType.namedParameters['s'].node.isPossiblyOptional, false); } Future test_topLevelFunction_parameterType_positionalOptional() async { await analyze(''' void f([int i]) {} '''); var decoratedType = decoratedTypeAnnotation('int'); expect(decoratedFunctionType('f').positionalParameters[0], same(decoratedType)); expect(decoratedType.node, isNotNull); expect(decoratedType.node, isNot(never)); } Future test_topLevelFunction_parameterType_simple() async { await analyze(''' void f(int i) {} '''); var decoratedType = decoratedTypeAnnotation('int'); expect(decoratedFunctionType('f').positionalParameters[0], same(decoratedType)); expect(decoratedType.node, isNotNull); expect(decoratedType.node, isNot(never)); } Future test_topLevelFunction_returnType_implicit_dynamic() async { await analyze(''' f() {} '''); var decoratedType = decoratedFunctionType('f').returnType; expect(decoratedType.type.isDynamic, isTrue); } Future test_topLevelFunction_returnType_simple() async { await analyze(''' int f() => 0; '''); var decoratedType = decoratedTypeAnnotation('int'); expect(decoratedFunctionType('f').returnType, same(decoratedType)); expect(decoratedType.node, isNotNull); expect(decoratedType.node, isNot(never)); } Future test_topLevelVariable_type_implicit_dynamic() async { await analyze(''' var x; '''); var decoratedType = variables.decoratedElementType(findNode.simple('x').staticElement); expect(decoratedType.node.isImmutable, false); } Future test_topLevelVariable_type_inferred() async { await analyze(''' var x = 1; '''); var decoratedType = variables.decoratedElementType(findNode.simple('x').staticElement); expect(decoratedType.node, TypeMatcher()); } Future test_topLevelVariable_type_inferred_dynamic() async { await analyze(''' dynamic f() {} var x = f(); '''); var decoratedType = variables.decoratedElementType(findNode.simple('x').staticElement); expect(decoratedType.node.isImmutable, false); } Future test_type_add_non_null_hint() async { await analyze(''' void f(int i) {} '''); final node = decoratedTypeAnnotation('int').node; expect(node.hintActions, contains(HintActionKind.addNonNullableHint)); expect( node.hintActions[HintActionKind.addNonNullableHint] .applyTo(super.testCode), ''' void f(int/*!*/ i) {} '''); } Future test_type_add_null_hint() async { await analyze(''' void f(int i) {} '''); final node = decoratedTypeAnnotation('int').node; expect(node.hintActions, contains(HintActionKind.addNullableHint)); expect( node.hintActions[HintActionKind.addNullableHint] .applyTo(super.testCode), ''' void f(int/*?*/ i) {} '''); } Future test_type_comment_bang() async { await analyze(''' void f(int/*!*/ i) {} '''); final node = decoratedTypeAnnotation('int').node; assertEdge(node, never, hard: true, checkable: false); expect( node.hintActions, isNot(contains(HintActionKind.addNonNullableHint))); expect(node.hintActions, isNot(contains(HintActionKind.addNullableHint))); expect(node.hintActions, isNot(contains(HintActionKind.changeToNonNullableHint))); expect( node.hintActions[HintActionKind.removeNonNullableHint] .applyTo(super.testCode), ''' void f(int i) {} '''); expect( node.hintActions[HintActionKind.changeToNullableHint] .applyTo(super.testCode), ''' void f(int/*?*/ i) {} '''); } Future test_type_comment_question() async { await analyze(''' void f(int/*?*/ i) {} '''); final node = decoratedTypeAnnotation('int').node; assertUnion(always, node); expect( node.hintActions, isNot(contains(HintActionKind.addNonNullableHint))); expect(node.hintActions, isNot(contains(HintActionKind.addNullableHint))); expect( node.hintActions, isNot(contains(HintActionKind.changeToNullableHint))); expect( node.hintActions[HintActionKind.removeNullableHint] .applyTo(super.testCode), ''' void f(int i) {} '''); expect( node.hintActions[HintActionKind.changeToNonNullableHint] .applyTo(super.testCode), ''' void f(int/*!*/ i) {} '''); } Future test_type_nested_add_non_null_hint() async { await analyze(''' void f(List i) {} '''); final node = decoratedTypeAnnotation('int').node; expect(node.hintActions, contains(HintActionKind.addNonNullableHint)); expect( node.hintActions[HintActionKind.addNonNullableHint] .applyTo(super.testCode), ''' void f(List i) {} '''); } Future test_type_nested_add_null_hint() async { await analyze(''' void f(List i) {} '''); final node = decoratedTypeAnnotation('int').node; expect(node.hintActions, contains(HintActionKind.addNullableHint)); expect( node.hintActions[HintActionKind.addNullableHint] .applyTo(super.testCode), ''' void f(List i) {} '''); } Future test_type_parameter_explicit_bound() async { await analyze(''' class C {} '''); var bound = decoratedTypeParameterBound('T'); expect(decoratedTypeAnnotation('Object'), same(bound)); expect(bound.node, isNot(always)); expect(bound.type, typeProvider.objectType); } Future test_type_parameter_implicit_bound() async { // The implicit bound of `T` is automatically `Object?`. TODO(paulberry): // consider making it possible for type inference to infer an explicit bound // of `Object`. await analyze(''' class C {} '''); var bound = decoratedTypeParameterBound('T'); assertEdge(always, bound.node, hard: false); expect(bound.type, same(typeProvider.objectType)); } Future test_typedef_reference_generic_instantiated() async { await analyze(''' typedef F = T Function(); F f; '''); // The instantiation of F should produce fresh nullability nodes, distinct // from the ones in the typedef (they will be unified by the edge builder). // This is necessary because there is no guarantee of whether the typedef or // its usage will be visited first. var typedefDecoratedType = variables .decoratedElementType(findElement.typeAlias('F').aliasedElement); var decoratedType = decoratedTypeAnnotation('F'); expect(decoratedType.node, TypeMatcher()); expect(decoratedType.node, isNot(same(typedefDecoratedType.node))); _assertType(decoratedType.returnType.type, 'int'); expect( decoratedType.returnType.node, TypeMatcher()); expect(decoratedType.returnType.node, isNot(same(typedefDecoratedType.returnType.node))); } Future test_typedef_reference_generic_uninstantiated() async { await analyze(''' typedef F = T Function(); F f; '''); // The instantiation of F should produce fresh nullability nodes, distinct // from the ones in the typedef (they will be unified by the edge builder). // This is necessary because there is no guarantee of whether the typedef or // its usage will be visited first. var typedefDecoratedType = variables .decoratedElementType(findElement.typeAlias('F').aliasedElement); var decoratedType = decoratedTypeAnnotation('F f'); expect(decoratedType.node, TypeMatcher()); expect(decoratedType.node, isNot(same(typedefDecoratedType.node))); _assertType(decoratedType.returnType.type, 'T'); expect( decoratedType.returnType.node, TypeMatcher()); expect(decoratedType.returnType.node, isNot(same(typedefDecoratedType.returnType.node))); var decoratedTypeFormalBound = decoratedTypeParameterBounds .get((decoratedType.type as FunctionType).typeFormals[0]); _assertType(decoratedTypeFormalBound.type, 'num'); expect(decoratedTypeFormalBound.node.displayName, 'bound of type formal T of f (test.dart:2:1)'); var decoratedTypedefTypeFormalBound = decoratedTypeParameterBounds .get((typedefDecoratedType.type as FunctionType).typeFormals[0]); expect(decoratedTypeFormalBound.node, isNot(same(decoratedTypedefTypeFormalBound.node))); } Future test_typedef_reference_simple() async { await analyze(''' typedef int F(String s); F f; '''); // The instantiation of F should produce fresh nullability nodes, distinct // from the ones in the typedef (they will be unified by the edge builder). // This is necessary because there is no guarantee of whether the typedef or // its usage will be visited first. var typedefDecoratedType = variables .decoratedElementType(findElement.typeAlias('F').aliasedElement); var decoratedType = decoratedTypeAnnotation('F f'); expect(decoratedType.node, TypeMatcher()); expect(decoratedType.node, isNot(same(typedefDecoratedType.node))); _assertType(decoratedType.returnType.type, 'int'); expect( decoratedType.returnType.node, TypeMatcher()); expect(decoratedType.returnType.node, isNot(same(typedefDecoratedType.returnType.node))); expect(typedefDecoratedType.returnType.node.displayName, 'return type of F (test.dart:1:9)'); expect(decoratedType.returnType.node.displayName, 'return type of f (test.dart:2:1)'); _assertType(decoratedType.positionalParameters[0].type, 'String'); expect(decoratedType.positionalParameters[0].node, TypeMatcher()); expect(decoratedType.positionalParameters[0].node, isNot(same(typedefDecoratedType.positionalParameters[0].node))); expect(decoratedType.positionalParameters[0].node.displayName, 'parameter 0 of f (test.dart:2:1)'); } Future test_typedef_reference_simple_named_parameter() async { await analyze(''' typedef int F({String s}); F f; '''); // The instantiation of F should produce fresh nullability nodes, distinct // from the ones in the typedef (they will be unified by the edge builder). // This is necessary because there is no guarantee of whether the typedef or // its usage will be visited first. var decoratedType = decoratedTypeAnnotation('F f'); expect(decoratedType.namedParameters['s'].node.displayName, 'parameter s of f (test.dart:2:1)'); } Future test_typedef_reference_simple_two_parameters() async { await analyze(''' typedef int F(String s, int i); F f; '''); // The instantiation of F should produce fresh nullability nodes, distinct // from the ones in the typedef (they will be unified by the edge builder). // This is necessary because there is no guarantee of whether the typedef or // its usage will be visited first. var decoratedType = decoratedTypeAnnotation('F f'); expect(decoratedType.positionalParameters[0].node.displayName, 'parameter 0 of f (test.dart:2:1)'); expect(decoratedType.positionalParameters[1].node.displayName, 'parameter 1 of f (test.dart:2:1)'); } Future test_typedef_rhs_nullability() async { await analyze(''' typedef F = void Function(); '''); var decorated = decoratedGenericFunctionTypeAnnotation('void Function()'); expect(decorated.node, same(never)); } Future test_variableDeclaration_late_final_hint_simple() async { await analyze('/*late final*/ int i;'); expect( variables.getLateHint( testSource, findNode.variableDeclarationList('int i')), isNotNull); } Future test_variableDeclaration_late_hint_after_metadata() async { await analyze('@deprecated /*late*/ int i;'); expect( variables.getLateHint( testSource, findNode.variableDeclarationList('int i')), isNotNull); } Future test_variableDeclaration_late_hint_multiple_comments() async { await analyze('/*other*/ /*late*/ int i;'); expect( variables.getLateHint( testSource, findNode.variableDeclarationList('int i')), isNotNull); } Future test_variableDeclaration_late_hint_simple() async { await analyze('/*late*/ int i;'); expect( variables.getLateHint( testSource, findNode.variableDeclarationList('int i')), isNotNull); } Future test_variableDeclaration_late_hint_with_spaces() async { await analyze('/* late */ int i;'); expect( variables.getLateHint( testSource, findNode.variableDeclarationList('int i')), isNotNull); } Future test_variableDeclaration_type_simple() async { await analyze(''' main() { int i; } '''); var decoratedType = decoratedTypeAnnotation('int'); expect(decoratedType.node, TypeMatcher()); } Future test_variableDeclaration_visit_initializer() async { await analyze(''' class C {} void f(C c) { var x = c as C; } '''); var decoratedType = decoratedTypeAnnotation('int'); expect(decoratedType.node, TypeMatcher()); } Future test_void_type() async { await analyze(''' void f() {} '''); var decoratedType = decoratedTypeAnnotation('void'); expect(decoratedFunctionType('f').returnType, same(decoratedType)); assertNoEdge(always, decoratedType.node); } void _assertType(DartType type, String expected) { var typeStr = type.getDisplayString(withNullability: false); expect(typeStr, expected); } }