blob: 7ee2030e03ea0f67b24ba78606aa0ded1e82a668 [file] [log] [blame]
// Copyright (c) 2016, 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.
library analyzer.test.generated.static_type_analyzer_test;
import 'dart:collection';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/static_type_analyzer.dart';
import 'package:analyzer/src/generated/testing/ast_test_factory.dart';
import 'package:analyzer/src/generated/testing/element_factory.dart';
import 'package:analyzer/src/generated/testing/token_factory.dart';
import 'package:analyzer/src/source/source_resource.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'analysis_context_factory.dart';
import 'resolver_test_case.dart';
import 'test_support.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(StaticTypeAnalyzerTest);
defineReflectiveTests(StaticTypeAnalyzer2Test);
});
}
/// Wrapper around the test package's `fail` function.
///
/// Unlike the test package's `fail` function, this function is not annotated
/// with @alwaysThrows, so we can call it at the top of a test method without
/// causing the rest of the method to be flagged as dead code.
void _fail(String message) {
fail(message);
}
/**
* Like [StaticTypeAnalyzerTest], but as end-to-end tests.
*/
@reflectiveTest
class StaticTypeAnalyzer2Test extends StaticTypeAnalyzer2TestShared {
test_FunctionExpressionInvocation_block() async {
String code = r'''
main() {
var foo = (() { return 1; })();
}
''';
await resolveTestUnit(code);
expectInitializerType('foo', previewDart2 ? 'int' : 'dynamic', isNull);
}
test_FunctionExpressionInvocation_curried() async {
String code = r'''
typedef int F();
F f() => null;
main() {
var foo = f()();
}
''';
await resolveTestUnit(code);
expectInitializerType('foo', 'int', isNull);
}
test_FunctionExpressionInvocation_expression() async {
String code = r'''
main() {
var foo = (() => 1)();
}
''';
await resolveTestUnit(code);
expectInitializerType('foo', 'int', isNull);
}
test_MethodInvocation_nameType_localVariable() async {
String code = r"""
typedef Foo();
main() {
Foo foo;
foo();
}
""";
await resolveTestUnit(code);
// "foo" should be resolved to the "Foo" type
expectIdentifierType("foo();", new isInstanceOf<FunctionType>());
}
test_MethodInvocation_nameType_parameter_FunctionTypeAlias() async {
String code = r"""
typedef Foo();
main(Foo foo) {
foo();
}
""";
await resolveTestUnit(code);
// "foo" should be resolved to the "Foo" type
expectIdentifierType("foo();", new isInstanceOf<FunctionType>());
}
test_MethodInvocation_nameType_parameter_propagatedType() async {
String code = r"""
typedef Foo();
main(p) {
if (p is Foo) {
p();
}
}
""";
await resolveTestUnit(code);
if (previewDart2) {
expectIdentifierType("p()", '() → dynamic');
} else {
expectIdentifierType("p()", DynamicTypeImpl.instance,
predicate((type) => type.displayName == '() → dynamic'));
}
}
test_staticMethods_classTypeParameters() async {
String code = r'''
class C<T> {
static void m() => null;
}
main() {
print(C.m);
}
''';
await resolveTestUnit(code);
expectFunctionType('m);', '() → void');
}
test_staticMethods_classTypeParameters_genericMethod() async {
String code = r'''
class C<T> {
static void m<S>(S s) {
void f<U>(S s, U u) {}
print(f);
}
}
main() {
print(C.m);
}
''';
await resolveTestUnit(code);
// C - m
TypeParameterType typeS;
{
FunctionTypeImpl type = expectFunctionType('m);', '<S>(S) → void',
elementTypeParams: '[S]',
typeFormals: '[S]',
identifierType: previewDart2 ? '<S>(S) → void' : '(dynamic) → void');
typeS = type.typeFormals[0].type;
type = type.instantiate([DynamicTypeImpl.instance]);
expect(type.toString(), '(dynamic) → void');
expect(type.typeParameters.toString(), '[S]');
expect(type.typeArguments, [DynamicTypeImpl.instance]);
expect(type.typeFormals, isEmpty);
}
// C - m - f
{
FunctionTypeImpl type = expectFunctionType('f);', '<U>(S, U) → void',
elementTypeParams: '[U]',
typeParams: '[S]',
typeArgs: '[S]',
typeFormals: '[U]',
identifierType:
previewDart2 ? '<U>(S, U) → void' : '(S, dynamic) → void');
type = type.instantiate([DynamicTypeImpl.instance]);
expect(type.toString(), '(S, dynamic) → void');
expect(type.typeParameters.toString(), '[S, U]');
expect(type.typeArguments, [typeS, DynamicTypeImpl.instance]);
expect(type.typeFormals, isEmpty);
}
}
}
@reflectiveTest
class StaticTypeAnalyzerTest extends EngineTestCase {
/**
* The error listener to which errors will be reported.
*/
GatheringErrorListener _listener;
/**
* The resolver visitor used to create the analyzer.
*/
ResolverVisitor _visitor;
/**
* The analyzer being used to analyze the test cases.
*/
StaticTypeAnalyzer _analyzer;
/**
* The type provider used to access the types.
*/
TypeProvider _typeProvider;
AnalysisOptions _analysisOptions;
bool get previewDart2 => _analysisOptions.previewDart2;
/**
* The type system used to analyze the test cases.
*/
TypeSystem get _typeSystem => _visitor.typeSystem;
void fail_visitFunctionExpressionInvocation() {
_fail("Not yet tested");
_listener.assertNoErrors();
}
void fail_visitMethodInvocation() {
_fail("Not yet tested");
_listener.assertNoErrors();
}
void fail_visitSimpleIdentifier() {
_fail("Not yet tested");
_listener.assertNoErrors();
}
@override
void setUp() {
super.setUp();
_listener = new GatheringErrorListener();
_analyzer = _createAnalyzer();
}
void test_flatten_derived() {
// class Derived<T> extends Future<T> { ... }
ClassElementImpl derivedClass =
ElementFactory.classElement2('Derived', ['T']);
derivedClass.supertype = _typeProvider.futureType
.instantiate([derivedClass.typeParameters[0].type]);
InterfaceType intType = _typeProvider.intType;
DartType dynamicType = _typeProvider.dynamicType;
InterfaceType derivedIntType = derivedClass.type.instantiate([intType]);
// flatten(Derived) = dynamic
InterfaceType derivedDynamicType =
derivedClass.type.instantiate([dynamicType]);
expect(_flatten(derivedDynamicType), dynamicType);
// flatten(Derived<int>) = int
expect(_flatten(derivedIntType), intType);
// flatten(Derived<Derived>) = Derived
expect(_flatten(derivedClass.type.instantiate([derivedDynamicType])),
derivedDynamicType);
// flatten(Derived<Derived<int>>) = Derived<int>
expect(_flatten(derivedClass.type.instantiate([derivedIntType])),
derivedIntType);
}
void test_flatten_inhibit_recursion() {
// class A extends B
// class B extends A
ClassElementImpl classA = ElementFactory.classElement2('A', []);
ClassElementImpl classB = ElementFactory.classElement2('B', []);
classA.supertype = classB.type;
classB.supertype = classA.type;
// flatten(A) = A and flatten(B) = B, since neither class contains Future
// in its class hierarchy. Even though there is a loop in the class
// hierarchy, flatten() should terminate.
expect(_flatten(classA.type), classA.type);
expect(_flatten(classB.type), classB.type);
}
void test_flatten_related_derived_types() {
InterfaceType intType = _typeProvider.intType;
InterfaceType numType = _typeProvider.numType;
// class Derived<T> extends Future<T>
ClassElementImpl derivedClass =
ElementFactory.classElement2('Derived', ['T']);
derivedClass.supertype = _typeProvider.futureType
.instantiate([derivedClass.typeParameters[0].type]);
InterfaceType derivedType = derivedClass.type;
// class A extends Derived<int> implements Derived<num> { ... }
ClassElementImpl classA =
ElementFactory.classElement('A', derivedType.instantiate([intType]));
classA.interfaces = <InterfaceType>[
derivedType.instantiate([numType])
];
// class B extends Future<num> implements Future<int> { ... }
ClassElementImpl classB =
ElementFactory.classElement('B', derivedType.instantiate([numType]));
classB.interfaces = <InterfaceType>[
derivedType.instantiate([intType])
];
// flatten(A) = flatten(B) = int, since int is more specific than num.
// The code in flatten() that inhibits infinite recursion shouldn't be
// fooled by the fact that Derived appears twice in the type hierarchy.
expect(_flatten(classA.type), intType);
expect(_flatten(classB.type), intType);
}
void test_flatten_related_types() {
InterfaceType futureType = _typeProvider.futureType;
InterfaceType intType = _typeProvider.intType;
InterfaceType numType = _typeProvider.numType;
// class A extends Future<int> implements Future<num> { ... }
ClassElementImpl classA =
ElementFactory.classElement('A', futureType.instantiate([intType]));
classA.interfaces = <InterfaceType>[
futureType.instantiate([numType])
];
// class B extends Future<num> implements Future<int> { ... }
ClassElementImpl classB =
ElementFactory.classElement('B', futureType.instantiate([numType]));
classB.interfaces = <InterfaceType>[
futureType.instantiate([intType])
];
// flatten(A) = flatten(B) = int, since int is more specific than num.
expect(_flatten(classA.type), intType);
expect(_flatten(classB.type), intType);
}
void test_flatten_simple() {
InterfaceType intType = _typeProvider.intType;
DartType dynamicType = _typeProvider.dynamicType;
InterfaceType futureDynamicType = _typeProvider.futureDynamicType;
InterfaceType futureIntType =
_typeProvider.futureType.instantiate([intType]);
InterfaceType futureFutureDynamicType =
_typeProvider.futureType.instantiate([futureDynamicType]);
InterfaceType futureFutureIntType =
_typeProvider.futureType.instantiate([futureIntType]);
// flatten(int) = int
expect(_flatten(intType), intType);
// flatten(dynamic) = dynamic
expect(_flatten(dynamicType), dynamicType);
// flatten(Future) = dynamic
expect(_flatten(futureDynamicType), dynamicType);
// flatten(Future<int>) = int
expect(_flatten(futureIntType), intType);
// flatten(Future<Future>) = Future<dynamic>
expect(_flatten(futureFutureDynamicType), futureDynamicType);
// flatten(Future<Future<int>>) = Future<int>
expect(_flatten(futureFutureIntType), futureIntType);
}
void test_flatten_unrelated_types() {
InterfaceType futureType = _typeProvider.futureType;
InterfaceType intType = _typeProvider.intType;
InterfaceType stringType = _typeProvider.stringType;
// class A extends Future<int> implements Future<String> { ... }
ClassElementImpl classA =
ElementFactory.classElement('A', futureType.instantiate([intType]));
classA.interfaces = <InterfaceType>[
futureType.instantiate([stringType])
];
// class B extends Future<String> implements Future<int> { ... }
ClassElementImpl classB =
ElementFactory.classElement('B', futureType.instantiate([stringType]));
classB.interfaces = <InterfaceType>[
futureType.instantiate([intType])
];
// flatten(A) = A and flatten(B) = B, since neither string nor int is more
// specific than the other.
expect(_flatten(classA.type), classA.type);
expect(_flatten(classB.type), classB.type);
}
void test_visitAdjacentStrings() {
// "a" "b"
Expression node = AstTestFactory
.adjacentStrings([_resolvedString("a"), _resolvedString("b")]);
expect(_analyze(node), same(_typeProvider.stringType));
_listener.assertNoErrors();
}
void test_visitAsExpression() {
// class A { ... this as B ... }
// class B extends A {}
ClassElement superclass = ElementFactory.classElement2("A");
InterfaceType superclassType = superclass.type;
ClassElement subclass = ElementFactory.classElement("B", superclassType);
Expression node = AstTestFactory.asExpression(
AstTestFactory.thisExpression(), AstTestFactory.typeName(subclass));
expect(_analyze3(node, superclassType), same(subclass.type));
_listener.assertNoErrors();
}
void test_visitAssignmentExpression_compound_II() {
validate(TokenType operator) {
InterfaceType numType = _typeProvider.numType;
InterfaceType intType = _typeProvider.intType;
SimpleIdentifier identifier = _resolvedVariable(intType, "i");
AssignmentExpression node = AstTestFactory.assignmentExpression(
identifier, operator, _resolvedInteger(1));
MethodElement plusMethod = getMethod(numType, "+");
node.staticElement = plusMethod;
expect(_analyze(node), same(intType));
_listener.assertNoErrors();
}
validate(TokenType.MINUS_EQ);
validate(TokenType.PERCENT_EQ);
validate(TokenType.PLUS_EQ);
validate(TokenType.STAR_EQ);
validate(TokenType.TILDE_SLASH_EQ);
}
void test_visitAssignmentExpression_compound_lazy() {
validate(TokenType operator) {
InterfaceType boolType = _typeProvider.boolType;
SimpleIdentifier identifier = _resolvedVariable(boolType, "b");
AssignmentExpression node = AstTestFactory.assignmentExpression(
identifier, operator, _resolvedBool(true));
expect(_analyze(node), same(boolType));
_listener.assertNoErrors();
}
validate(TokenType.AMPERSAND_AMPERSAND_EQ);
validate(TokenType.BAR_BAR_EQ);
}
void test_visitAssignmentExpression_compound_plusID() {
validate(TokenType operator) {
InterfaceType numType = _typeProvider.numType;
InterfaceType intType = _typeProvider.intType;
InterfaceType doubleType = _typeProvider.doubleType;
SimpleIdentifier identifier = _resolvedVariable(intType, "i");
AssignmentExpression node = AstTestFactory.assignmentExpression(
identifier, operator, _resolvedDouble(1.0));
MethodElement plusMethod = getMethod(numType, "+");
node.staticElement = plusMethod;
expect(_analyze(node), same(doubleType));
_listener.assertNoErrors();
}
validate(TokenType.MINUS_EQ);
validate(TokenType.PERCENT_EQ);
validate(TokenType.PLUS_EQ);
validate(TokenType.STAR_EQ);
}
void test_visitAssignmentExpression_compoundIfNull_differentTypes() {
// double d; d ??= 0
Expression node = AstTestFactory.assignmentExpression(
_resolvedVariable(_typeProvider.doubleType, 'd'),
TokenType.QUESTION_QUESTION_EQ,
_resolvedInteger(0));
expect(_analyze(node), same(_typeProvider.numType));
_listener.assertNoErrors();
}
void test_visitAssignmentExpression_compoundIfNull_sameTypes() {
// int i; i ??= 0
Expression node = AstTestFactory.assignmentExpression(
_resolvedVariable(_typeProvider.intType, 'i'),
TokenType.QUESTION_QUESTION_EQ,
_resolvedInteger(0));
expect(_analyze(node), same(_typeProvider.intType));
_listener.assertNoErrors();
}
void test_visitAssignmentExpression_simple() {
// i = 0
InterfaceType intType = _typeProvider.intType;
Expression node = AstTestFactory.assignmentExpression(
_resolvedVariable(intType, "i"), TokenType.EQ, _resolvedInteger(0));
expect(_analyze(node), same(intType));
_listener.assertNoErrors();
}
void test_visitAwaitExpression_flattened() {
// await e, where e has type Future<Future<int>>
InterfaceType intType = _typeProvider.intType;
InterfaceType futureIntType =
_typeProvider.futureType.instantiate(<DartType>[intType]);
InterfaceType futureFutureIntType =
_typeProvider.futureType.instantiate(<DartType>[futureIntType]);
Expression node = AstTestFactory
.awaitExpression(_resolvedVariable(futureFutureIntType, 'e'));
expect(_analyze(node), same(futureIntType));
_listener.assertNoErrors();
}
void test_visitAwaitExpression_simple() {
// await e, where e has type Future<int>
InterfaceType intType = _typeProvider.intType;
InterfaceType futureIntType =
_typeProvider.futureType.instantiate(<DartType>[intType]);
Expression node =
AstTestFactory.awaitExpression(_resolvedVariable(futureIntType, 'e'));
expect(_analyze(node), same(intType));
_listener.assertNoErrors();
}
void test_visitBinaryExpression_equals() {
// 2 == 3
Expression node = AstTestFactory.binaryExpression(
_resolvedInteger(2), TokenType.EQ_EQ, _resolvedInteger(3));
expect(_analyze(node), same(_typeProvider.boolType));
_listener.assertNoErrors();
}
void test_visitBinaryExpression_ifNull() {
// 1 ?? 1.5
Expression node = AstTestFactory.binaryExpression(
_resolvedInteger(1), TokenType.QUESTION_QUESTION, _resolvedDouble(1.5));
expect(_analyze(node), same(_typeProvider.numType));
_listener.assertNoErrors();
}
void test_visitBinaryExpression_logicalAnd() {
// false && true
Expression node = AstTestFactory.binaryExpression(
AstTestFactory.booleanLiteral(false),
TokenType.AMPERSAND_AMPERSAND,
AstTestFactory.booleanLiteral(true));
expect(_analyze(node), same(_typeProvider.boolType));
_listener.assertNoErrors();
}
void test_visitBinaryExpression_logicalOr() {
// false || true
Expression node = AstTestFactory.binaryExpression(
AstTestFactory.booleanLiteral(false),
TokenType.BAR_BAR,
AstTestFactory.booleanLiteral(true));
expect(_analyze(node), same(_typeProvider.boolType));
_listener.assertNoErrors();
}
void test_visitBinaryExpression_minusID_propagated() {
// a - b
BinaryExpression node = AstTestFactory.binaryExpression(
_propagatedVariable(_typeProvider.intType, 'a'),
TokenType.MINUS,
_propagatedVariable(_typeProvider.doubleType, 'b'));
node.propagatedElement = getMethod(_typeProvider.numType, "+");
_analyze(node);
expect(node.propagatedType,
previewDart2 ? isNull : same(_typeProvider.doubleType));
_listener.assertNoErrors();
}
void test_visitBinaryExpression_notEquals() {
// 2 != 3
Expression node = AstTestFactory.binaryExpression(
_resolvedInteger(2), TokenType.BANG_EQ, _resolvedInteger(3));
expect(_analyze(node), same(_typeProvider.boolType));
_listener.assertNoErrors();
}
void test_visitBinaryExpression_plusID() {
// 1 + 2.0
BinaryExpression node = AstTestFactory.binaryExpression(
_resolvedInteger(1), TokenType.PLUS, _resolvedDouble(2.0));
node.staticElement = getMethod(_typeProvider.numType, "+");
expect(_analyze(node), same(_typeProvider.doubleType));
_listener.assertNoErrors();
}
void test_visitBinaryExpression_plusII() {
// 1 + 2
BinaryExpression node = AstTestFactory.binaryExpression(
_resolvedInteger(1), TokenType.PLUS, _resolvedInteger(2));
node.staticElement = getMethod(_typeProvider.numType, "+");
expect(_analyze(node), same(_typeProvider.intType));
_listener.assertNoErrors();
}
void test_visitBinaryExpression_plusII_propagated() {
// a + b
BinaryExpression node = AstTestFactory.binaryExpression(
_propagatedVariable(_typeProvider.intType, 'a'),
TokenType.PLUS,
_propagatedVariable(_typeProvider.intType, 'b'));
node.propagatedElement = getMethod(_typeProvider.numType, "+");
_analyze(node);
expect(node.propagatedType,
previewDart2 ? isNull : same(_typeProvider.intType));
_listener.assertNoErrors();
}
void test_visitBinaryExpression_slash() {
// 2 / 2
BinaryExpression node = AstTestFactory.binaryExpression(
_resolvedInteger(2), TokenType.SLASH, _resolvedInteger(2));
node.staticElement = getMethod(_typeProvider.numType, "/");
expect(_analyze(node), same(_typeProvider.doubleType));
_listener.assertNoErrors();
}
void test_visitBinaryExpression_star_notSpecial() {
// class A {
// A operator *(double value);
// }
// (a as A) * 2.0
ClassElementImpl classA = ElementFactory.classElement2("A");
InterfaceType typeA = classA.type;
MethodElement operator =
ElementFactory.methodElement("*", typeA, [_typeProvider.doubleType]);
classA.methods = <MethodElement>[operator];
BinaryExpression node = AstTestFactory.binaryExpression(
AstTestFactory.asExpression(
AstTestFactory.identifier3("a"), AstTestFactory.typeName(classA)),
TokenType.PLUS,
_resolvedDouble(2.0));
node.staticElement = operator;
expect(_analyze(node), same(typeA));
_listener.assertNoErrors();
}
void test_visitBinaryExpression_starID() {
// 1 * 2.0
BinaryExpression node = AstTestFactory.binaryExpression(
_resolvedInteger(1), TokenType.PLUS, _resolvedDouble(2.0));
node.staticElement = getMethod(_typeProvider.numType, "*");
expect(_analyze(node), same(_typeProvider.doubleType));
_listener.assertNoErrors();
}
void test_visitBooleanLiteral_false() {
// false
Expression node = AstTestFactory.booleanLiteral(false);
expect(_analyze(node), same(_typeProvider.boolType));
_listener.assertNoErrors();
}
void test_visitBooleanLiteral_true() {
// true
Expression node = AstTestFactory.booleanLiteral(true);
expect(_analyze(node), same(_typeProvider.boolType));
_listener.assertNoErrors();
}
void test_visitCascadeExpression() {
// a..length
Expression node = AstTestFactory.cascadeExpression(
_resolvedString("a"), [AstTestFactory.propertyAccess2(null, "length")]);
expect(_analyze(node), same(_typeProvider.stringType));
_listener.assertNoErrors();
}
void test_visitConditionalExpression_differentTypes() {
// true ? 1.0 : 0
Expression node = AstTestFactory.conditionalExpression(
AstTestFactory.booleanLiteral(true),
_resolvedDouble(1.0),
_resolvedInteger(0));
expect(_analyze(node), same(_typeProvider.numType));
_listener.assertNoErrors();
}
void test_visitConditionalExpression_sameTypes() {
// true ? 1 : 0
Expression node = AstTestFactory.conditionalExpression(
AstTestFactory.booleanLiteral(true),
_resolvedInteger(1),
_resolvedInteger(0));
expect(_analyze(node), same(_typeProvider.intType));
_listener.assertNoErrors();
}
void test_visitDoubleLiteral() {
// 4.33
Expression node = AstTestFactory.doubleLiteral(4.33);
expect(_analyze(node), same(_typeProvider.doubleType));
_listener.assertNoErrors();
}
void test_visitFunctionExpression_async_block() {
// () async {}
BlockFunctionBody body = AstTestFactory.blockFunctionBody2();
body.keyword = TokenFactory.tokenFromString('async');
FunctionExpression node = _resolvedFunctionExpression(
AstTestFactory.formalParameterList([]), body);
DartType resultType = _analyze(node);
_assertFunctionType(
_typeProvider.futureDynamicType, null, null, null, resultType);
_listener.assertNoErrors();
}
void test_visitFunctionExpression_async_expression() {
// () async => e, where e has type int
InterfaceType intType = _typeProvider.intType;
InterfaceType futureIntType =
_typeProvider.futureType.instantiate(<DartType>[intType]);
Expression expression = _resolvedVariable(intType, 'e');
ExpressionFunctionBody body =
AstTestFactory.expressionFunctionBody(expression);
body.keyword = TokenFactory.tokenFromString('async');
FunctionExpression node = _resolvedFunctionExpression(
AstTestFactory.formalParameterList([]), body);
DartType resultType = _analyze(node);
if (previewDart2) {
_assertFunctionType(
_typeProvider.futureType
.instantiate(<DartType>[_typeProvider.dynamicType]),
null,
null,
null,
resultType);
} else {
_assertFunctionType(futureIntType, null, null, null, resultType);
}
_listener.assertNoErrors();
}
void test_visitFunctionExpression_async_expression_flatten() {
// () async => e, where e has type Future<int>
InterfaceType intType = _typeProvider.intType;
InterfaceType futureIntType =
_typeProvider.futureType.instantiate(<DartType>[intType]);
Expression expression = _resolvedVariable(futureIntType, 'e');
ExpressionFunctionBody body =
AstTestFactory.expressionFunctionBody(expression);
body.keyword = TokenFactory.tokenFromString('async');
FunctionExpression node = _resolvedFunctionExpression(
AstTestFactory.formalParameterList([]), body);
DartType resultType = _analyze(node);
if (previewDart2) {
_assertFunctionType(
_typeProvider.futureType
.instantiate(<DartType>[_typeProvider.dynamicType]),
null,
null,
null,
resultType);
} else {
_assertFunctionType(futureIntType, null, null, null, resultType);
}
_listener.assertNoErrors();
}
void test_visitFunctionExpression_async_expression_flatten_twice() {
// () async => e, where e has type Future<Future<int>>
InterfaceType intType = _typeProvider.intType;
InterfaceType futureIntType =
_typeProvider.futureType.instantiate(<DartType>[intType]);
InterfaceType futureFutureIntType =
_typeProvider.futureType.instantiate(<DartType>[futureIntType]);
Expression expression = _resolvedVariable(futureFutureIntType, 'e');
ExpressionFunctionBody body =
AstTestFactory.expressionFunctionBody(expression);
body.keyword = TokenFactory.tokenFromString('async');
FunctionExpression node = _resolvedFunctionExpression(
AstTestFactory.formalParameterList([]), body);
DartType resultType = _analyze(node);
if (previewDart2) {
_assertFunctionType(
_typeProvider.futureType
.instantiate(<DartType>[_typeProvider.dynamicType]),
null,
null,
null,
resultType);
} else {
_assertFunctionType(futureIntType, null, null, null, resultType);
}
_listener.assertNoErrors();
}
void test_visitFunctionExpression_generator_async() {
// () async* {}
BlockFunctionBody body = AstTestFactory.blockFunctionBody2();
body.keyword = TokenFactory.tokenFromString('async');
body.star = TokenFactory.tokenFromType(TokenType.STAR);
FunctionExpression node = _resolvedFunctionExpression(
AstTestFactory.formalParameterList([]), body);
DartType resultType = _analyze(node);
_assertFunctionType(
_typeProvider.streamDynamicType, null, null, null, resultType);
_listener.assertNoErrors();
}
void test_visitFunctionExpression_generator_sync() {
// () sync* {}
BlockFunctionBody body = AstTestFactory.blockFunctionBody2();
body.keyword = TokenFactory.tokenFromString('sync');
body.star = TokenFactory.tokenFromType(TokenType.STAR);
FunctionExpression node = _resolvedFunctionExpression(
AstTestFactory.formalParameterList([]), body);
DartType resultType = _analyze(node);
_assertFunctionType(
_typeProvider.iterableDynamicType, null, null, null, resultType);
_listener.assertNoErrors();
}
void test_visitFunctionExpression_named_block() {
// ({p1 : 0, p2 : 0}) {}
DartType dynamicType = _typeProvider.dynamicType;
FormalParameter p1 = AstTestFactory.namedFormalParameter(
AstTestFactory.simpleFormalParameter3("p1"), _resolvedInteger(0));
_setType(p1, dynamicType);
FormalParameter p2 = AstTestFactory.namedFormalParameter(
AstTestFactory.simpleFormalParameter3("p2"), _resolvedInteger(0));
_setType(p2, dynamicType);
FunctionExpression node = _resolvedFunctionExpression(
AstTestFactory.formalParameterList([p1, p2]),
AstTestFactory.blockFunctionBody2());
_analyze5(p1);
_analyze5(p2);
DartType resultType = _analyze(node);
Map<String, DartType> expectedNamedTypes = new HashMap<String, DartType>();
expectedNamedTypes["p1"] = dynamicType;
expectedNamedTypes["p2"] = dynamicType;
_assertFunctionType(
dynamicType, null, null, expectedNamedTypes, resultType);
_listener.assertNoErrors();
}
void test_visitFunctionExpression_named_expression() {
// ({p : 0}) -> 0;
DartType dynamicType = _typeProvider.dynamicType;
FormalParameter p = AstTestFactory.namedFormalParameter(
AstTestFactory.simpleFormalParameter3("p"), _resolvedInteger(0));
_setType(p, dynamicType);
FunctionExpression node = _resolvedFunctionExpression(
AstTestFactory.formalParameterList([p]),
AstTestFactory.expressionFunctionBody(_resolvedInteger(0)));
_analyze5(p);
DartType resultType = _analyze(node);
Map<String, DartType> expectedNamedTypes = new HashMap<String, DartType>();
expectedNamedTypes["p"] = dynamicType;
if (previewDart2) {
_assertFunctionType(
dynamicType, null, null, expectedNamedTypes, resultType);
} else {
_assertFunctionType(
_typeProvider.intType, null, null, expectedNamedTypes, resultType);
}
_listener.assertNoErrors();
}
void test_visitFunctionExpression_normal_block() {
// (p1, p2) {}
DartType dynamicType = _typeProvider.dynamicType;
FormalParameter p1 = AstTestFactory.simpleFormalParameter3("p1");
_setType(p1, dynamicType);
FormalParameter p2 = AstTestFactory.simpleFormalParameter3("p2");
_setType(p2, dynamicType);
FunctionExpression node = _resolvedFunctionExpression(
AstTestFactory.formalParameterList([p1, p2]),
AstTestFactory.blockFunctionBody2());
_analyze5(p1);
_analyze5(p2);
DartType resultType = _analyze(node);
_assertFunctionType(dynamicType, <DartType>[dynamicType, dynamicType], null,
null, resultType);
_listener.assertNoErrors();
}
void test_visitFunctionExpression_normal_expression() {
// (p1, p2) -> 0
DartType dynamicType = _typeProvider.dynamicType;
FormalParameter p = AstTestFactory.simpleFormalParameter3("p");
_setType(p, dynamicType);
FunctionExpression node = _resolvedFunctionExpression(
AstTestFactory.formalParameterList([p]),
AstTestFactory.expressionFunctionBody(_resolvedInteger(0)));
_analyze5(p);
DartType resultType = _analyze(node);
if (previewDart2) {
_assertFunctionType(
dynamicType, <DartType>[dynamicType], null, null, resultType);
} else {
_assertFunctionType(_typeProvider.intType, <DartType>[dynamicType], null,
null, resultType);
}
_listener.assertNoErrors();
}
void test_visitFunctionExpression_normalAndNamed_block() {
// (p1, {p2 : 0}) {}
DartType dynamicType = _typeProvider.dynamicType;
FormalParameter p1 = AstTestFactory.simpleFormalParameter3("p1");
_setType(p1, dynamicType);
FormalParameter p2 = AstTestFactory.namedFormalParameter(
AstTestFactory.simpleFormalParameter3("p2"), _resolvedInteger(0));
_setType(p2, dynamicType);
FunctionExpression node = _resolvedFunctionExpression(
AstTestFactory.formalParameterList([p1, p2]),
AstTestFactory.blockFunctionBody2());
_analyze5(p2);
DartType resultType = _analyze(node);
Map<String, DartType> expectedNamedTypes = new HashMap<String, DartType>();
expectedNamedTypes["p2"] = dynamicType;
_assertFunctionType(dynamicType, <DartType>[dynamicType], null,
expectedNamedTypes, resultType);
_listener.assertNoErrors();
}
void test_visitFunctionExpression_normalAndNamed_expression() {
// (p1, {p2 : 0}) -> 0
DartType dynamicType = _typeProvider.dynamicType;
FormalParameter p1 = AstTestFactory.simpleFormalParameter3("p1");
_setType(p1, dynamicType);
FormalParameter p2 = AstTestFactory.namedFormalParameter(
AstTestFactory.simpleFormalParameter3("p2"), _resolvedInteger(0));
_setType(p2, dynamicType);
FunctionExpression node = _resolvedFunctionExpression(
AstTestFactory.formalParameterList([p1, p2]),
AstTestFactory.expressionFunctionBody(_resolvedInteger(0)));
_analyze5(p2);
DartType resultType = _analyze(node);
Map<String, DartType> expectedNamedTypes = new HashMap<String, DartType>();
expectedNamedTypes["p2"] = dynamicType;
if (previewDart2) {
_assertFunctionType(dynamicType, <DartType>[dynamicType], null,
expectedNamedTypes, resultType);
} else {
_assertFunctionType(_typeProvider.intType, <DartType>[dynamicType], null,
expectedNamedTypes, resultType);
}
_listener.assertNoErrors();
}
void test_visitFunctionExpression_normalAndPositional_block() {
// (p1, [p2 = 0]) {}
DartType dynamicType = _typeProvider.dynamicType;
FormalParameter p1 = AstTestFactory.simpleFormalParameter3("p1");
_setType(p1, dynamicType);
FormalParameter p2 = AstTestFactory.positionalFormalParameter(
AstTestFactory.simpleFormalParameter3("p2"), _resolvedInteger(0));
_setType(p2, dynamicType);
FunctionExpression node = _resolvedFunctionExpression(
AstTestFactory.formalParameterList([p1, p2]),
AstTestFactory.blockFunctionBody2());
_analyze5(p1);
_analyze5(p2);
DartType resultType = _analyze(node);
_assertFunctionType(dynamicType, <DartType>[dynamicType],
<DartType>[dynamicType], null, resultType);
_listener.assertNoErrors();
}
void test_visitFunctionExpression_normalAndPositional_expression() {
// (p1, [p2 = 0]) -> 0
DartType dynamicType = _typeProvider.dynamicType;
FormalParameter p1 = AstTestFactory.simpleFormalParameter3("p1");
_setType(p1, dynamicType);
FormalParameter p2 = AstTestFactory.positionalFormalParameter(
AstTestFactory.simpleFormalParameter3("p2"), _resolvedInteger(0));
_setType(p2, dynamicType);
FunctionExpression node = _resolvedFunctionExpression(
AstTestFactory.formalParameterList([p1, p2]),
AstTestFactory.expressionFunctionBody(_resolvedInteger(0)));
_analyze5(p1);
_analyze5(p2);
DartType resultType = _analyze(node);
if (previewDart2) {
_assertFunctionType(dynamicType, <DartType>[dynamicType],
<DartType>[dynamicType], null, resultType);
} else {
_assertFunctionType(_typeProvider.intType, <DartType>[dynamicType],
<DartType>[dynamicType], null, resultType);
}
_listener.assertNoErrors();
}
void test_visitFunctionExpression_positional_block() {
// ([p1 = 0, p2 = 0]) {}
DartType dynamicType = _typeProvider.dynamicType;
FormalParameter p1 = AstTestFactory.positionalFormalParameter(
AstTestFactory.simpleFormalParameter3("p1"), _resolvedInteger(0));
_setType(p1, dynamicType);
FormalParameter p2 = AstTestFactory.positionalFormalParameter(
AstTestFactory.simpleFormalParameter3("p2"), _resolvedInteger(0));
_setType(p2, dynamicType);
FunctionExpression node = _resolvedFunctionExpression(
AstTestFactory.formalParameterList([p1, p2]),
AstTestFactory.blockFunctionBody2());
_analyze5(p1);
_analyze5(p2);
DartType resultType = _analyze(node);
_assertFunctionType(dynamicType, null, <DartType>[dynamicType, dynamicType],
null, resultType);
_listener.assertNoErrors();
}
void test_visitFunctionExpression_positional_expression() {
// ([p = 0]) -> 0
DartType dynamicType = _typeProvider.dynamicType;
FormalParameter p = AstTestFactory.positionalFormalParameter(
AstTestFactory.simpleFormalParameter3("p"), _resolvedInteger(0));
_setType(p, dynamicType);
FunctionExpression node = _resolvedFunctionExpression(
AstTestFactory.formalParameterList([p]),
AstTestFactory.expressionFunctionBody(_resolvedInteger(0)));
_analyze5(p);
DartType resultType = _analyze(node);
if (previewDart2) {
_assertFunctionType(
dynamicType, null, <DartType>[dynamicType], null, resultType);
} else {
_assertFunctionType(_typeProvider.intType, null, <DartType>[dynamicType],
null, resultType);
}
_listener.assertNoErrors();
}
void test_visitIndexExpression_getter() {
// List a;
// a[2]
InterfaceType listType = _typeProvider.listType;
SimpleIdentifier identifier = _resolvedVariable(listType, "a");
IndexExpression node =
AstTestFactory.indexExpression(identifier, _resolvedInteger(2));
MethodElement indexMethod = listType.element.methods[0];
node.staticElement = indexMethod;
expect(_analyze(node), same(listType.typeArguments[0]));
_listener.assertNoErrors();
}
void test_visitIndexExpression_setter() {
// List a;
// a[2] = 0
InterfaceType listType = _typeProvider.listType;
SimpleIdentifier identifier = _resolvedVariable(listType, "a");
IndexExpression node =
AstTestFactory.indexExpression(identifier, _resolvedInteger(2));
MethodElement indexMethod = listType.element.methods[1];
node.staticElement = indexMethod;
AstTestFactory.assignmentExpression(
node, TokenType.EQ, AstTestFactory.integer(0));
expect(_analyze(node), same(listType.typeArguments[0]));
_listener.assertNoErrors();
}
void test_visitIndexExpression_typeParameters() {
// List<int> list = ...
// list[0]
InterfaceType intType = _typeProvider.intType;
InterfaceType listType = _typeProvider.listType;
// (int) -> E
MethodElement methodElement = getMethod(listType, "[]");
// "list" has type List<int>
SimpleIdentifier identifier = AstTestFactory.identifier3("list");
InterfaceType listOfIntType = listType.instantiate(<DartType>[intType]);
identifier.staticType = listOfIntType;
// list[0] has MethodElement element (int) -> E
IndexExpression indexExpression =
AstTestFactory.indexExpression(identifier, AstTestFactory.integer(0));
MethodElement indexMethod = MethodMember.from(methodElement, listOfIntType);
indexExpression.staticElement = indexMethod;
// analyze and assert result of the index expression
expect(_analyze(indexExpression), same(intType));
_listener.assertNoErrors();
}
void test_visitIndexExpression_typeParameters_inSetterContext() {
// List<int> list = ...
// list[0] = 0;
InterfaceType intType = _typeProvider.intType;
InterfaceType listType = _typeProvider.listType;
// (int, E) -> void
MethodElement methodElement = getMethod(listType, "[]=");
// "list" has type List<int>
SimpleIdentifier identifier = AstTestFactory.identifier3("list");
InterfaceType listOfIntType = listType.instantiate(<DartType>[intType]);
identifier.staticType = listOfIntType;
// list[0] has MethodElement element (int) -> E
IndexExpression indexExpression =
AstTestFactory.indexExpression(identifier, AstTestFactory.integer(0));
MethodElement indexMethod = MethodMember.from(methodElement, listOfIntType);
indexExpression.staticElement = indexMethod;
// list[0] should be in a setter context
AstTestFactory.assignmentExpression(
indexExpression, TokenType.EQ, AstTestFactory.integer(0));
// analyze and assert result of the index expression
expect(_analyze(indexExpression), same(intType));
_listener.assertNoErrors();
}
void test_visitInstanceCreationExpression_named() {
// new C.m()
ClassElementImpl classElement = ElementFactory.classElement2("C");
String constructorName = "m";
ConstructorElementImpl constructor =
ElementFactory.constructorElement2(classElement, constructorName);
classElement.constructors = <ConstructorElement>[constructor];
InstanceCreationExpression node = AstTestFactory
.instanceCreationExpression2(
null,
AstTestFactory.typeName(classElement),
[AstTestFactory.identifier3(constructorName)]);
node.staticElement = constructor;
expect(_analyze(node), same(classElement.type));
_listener.assertNoErrors();
}
void test_visitInstanceCreationExpression_typeParameters() {
// new C<I>()
ClassElementImpl elementC = ElementFactory.classElement2("C", ["E"]);
ClassElementImpl elementI = ElementFactory.classElement2("I");
ConstructorElementImpl constructor =
ElementFactory.constructorElement2(elementC, null);
elementC.constructors = <ConstructorElement>[constructor];
TypeName typeName =
AstTestFactory.typeName(elementC, [AstTestFactory.typeName(elementI)]);
typeName.type = elementC.type.instantiate(<DartType>[elementI.type]);
InstanceCreationExpression node =
AstTestFactory.instanceCreationExpression2(null, typeName);
node.staticElement = constructor;
InterfaceType interfaceType = _analyze(node) as InterfaceType;
List<DartType> typeArgs = interfaceType.typeArguments;
expect(typeArgs.length, 1);
expect(typeArgs[0], elementI.type);
_listener.assertNoErrors();
}
void test_visitInstanceCreationExpression_unnamed() {
// new C()
ClassElementImpl classElement = ElementFactory.classElement2("C");
ConstructorElementImpl constructor =
ElementFactory.constructorElement2(classElement, null);
classElement.constructors = <ConstructorElement>[constructor];
InstanceCreationExpression node =
AstTestFactory.instanceCreationExpression2(
null, AstTestFactory.typeName(classElement));
node.staticElement = constructor;
expect(_analyze(node), same(classElement.type));
_listener.assertNoErrors();
}
void test_visitIntegerLiteral() {
// 42
Expression node = _resolvedInteger(42);
expect(_analyze(node), same(_typeProvider.intType));
_listener.assertNoErrors();
}
void test_visitIsExpression_negated() {
// a is! String
Expression node = AstTestFactory.isExpression(
_resolvedString("a"), true, AstTestFactory.typeName4("String"));
expect(_analyze(node), same(_typeProvider.boolType));
_listener.assertNoErrors();
}
void test_visitIsExpression_notNegated() {
// a is String
Expression node = AstTestFactory.isExpression(
_resolvedString("a"), false, AstTestFactory.typeName4("String"));
expect(_analyze(node), same(_typeProvider.boolType));
_listener.assertNoErrors();
}
void test_visitListLiteral_empty() {
// []
Expression node = AstTestFactory.listLiteral();
DartType resultType = _analyze(node);
_assertType2(
_typeProvider.listType
.instantiate(<DartType>[_typeProvider.dynamicType]),
resultType);
_listener.assertNoErrors();
}
void test_visitListLiteral_nonEmpty() {
// [0]
Expression node = AstTestFactory.listLiteral([_resolvedInteger(0)]);
DartType resultType = _analyze(node);
if (previewDart2) {
_assertType2(
_typeProvider.listType.instantiate(<DartType>[_typeProvider.intType]),
resultType);
} else {
_assertType2(
_typeProvider.listType
.instantiate(<DartType>[_typeProvider.dynamicType]),
resultType);
}
_listener.assertNoErrors();
}
void test_visitListLiteral_unresolved() {
_analyzer = _createAnalyzer(strongMode: true);
// [a] // where 'a' is not resolved
Identifier identifier = AstTestFactory.identifier3('a');
Expression node = AstTestFactory.listLiteral([identifier]);
DartType resultType = _analyze(node);
_assertType2(
_typeProvider.listType
.instantiate(<DartType>[_typeProvider.dynamicType]),
resultType);
_listener.assertNoErrors();
}
void test_visitListLiteral_unresolved_multiple() {
_analyzer = _createAnalyzer(strongMode: true);
// [0, a, 1] // where 'a' is not resolved
Identifier identifier = AstTestFactory.identifier3('a');
Expression node = AstTestFactory
.listLiteral([_resolvedInteger(0), identifier, _resolvedInteger(1)]);
DartType resultType = _analyze(node);
_assertType2(
_typeProvider.listType.instantiate(<DartType>[_typeProvider.intType]),
resultType);
_listener.assertNoErrors();
}
void test_visitMapLiteral_empty() {
// {}
Expression node = AstTestFactory.mapLiteral2();
DartType resultType = _analyze(node);
_assertType2(
_typeProvider.mapType.instantiate(
<DartType>[_typeProvider.dynamicType, _typeProvider.dynamicType]),
resultType);
_listener.assertNoErrors();
}
void test_visitMapLiteral_nonEmpty() {
// {"k" : 0}
Expression node = AstTestFactory.mapLiteral2(
[AstTestFactory.mapLiteralEntry("k", _resolvedInteger(0))]);
DartType resultType = _analyze(node);
if (previewDart2) {
_assertType2(
_typeProvider.mapType.instantiate(
<DartType>[_typeProvider.dynamicType, _typeProvider.intType]),
resultType);
} else {
_assertType2(
_typeProvider.mapType.instantiate(
<DartType>[_typeProvider.dynamicType, _typeProvider.dynamicType]),
resultType);
}
_listener.assertNoErrors();
}
void test_visitMethodInvocation_then() {
// then()
Expression node = AstTestFactory.methodInvocation(null, "then");
_analyze(node);
_listener.assertNoErrors();
}
void test_visitNamedExpression() {
// n: a
Expression node =
AstTestFactory.namedExpression2("n", _resolvedString("a"));
expect(_analyze(node), same(_typeProvider.stringType));
_listener.assertNoErrors();
}
void test_visitNullLiteral() {
// null
Expression node = AstTestFactory.nullLiteral();
expect(_analyze(node), same(_typeProvider.nullType));
_listener.assertNoErrors();
}
void test_visitParenthesizedExpression() {
// (0)
Expression node =
AstTestFactory.parenthesizedExpression(_resolvedInteger(0));
expect(_analyze(node), same(_typeProvider.intType));
_listener.assertNoErrors();
}
void test_visitPostfixExpression_minusMinus() {
// 0--
PostfixExpression node = AstTestFactory.postfixExpression(
_resolvedInteger(0), TokenType.MINUS_MINUS);
expect(_analyze(node), same(_typeProvider.intType));
_listener.assertNoErrors();
}
void test_visitPostfixExpression_plusPlus() {
// 0++
PostfixExpression node = AstTestFactory.postfixExpression(
_resolvedInteger(0), TokenType.PLUS_PLUS);
expect(_analyze(node), same(_typeProvider.intType));
_listener.assertNoErrors();
}
void test_visitPrefixedIdentifier_getter() {
DartType boolType = _typeProvider.boolType;
PropertyAccessorElementImpl getter =
ElementFactory.getterElement("b", false, boolType);
PrefixedIdentifier node = AstTestFactory.identifier5("a", "b");
node.identifier.staticElement = getter;
expect(_analyze(node), same(boolType));
_listener.assertNoErrors();
}
void test_visitPrefixedIdentifier_setter() {
DartType boolType = _typeProvider.boolType;
FieldElementImpl field =
ElementFactory.fieldElement("b", false, false, false, boolType);
PropertyAccessorElement setter = field.setter;
PrefixedIdentifier node = AstTestFactory.identifier5("a", "b");
node.identifier.staticElement = setter;
expect(_analyze(node), same(boolType));
_listener.assertNoErrors();
}
void test_visitPrefixedIdentifier_variable() {
VariableElementImpl variable = ElementFactory.localVariableElement2("b");
variable.type = _typeProvider.boolType;
PrefixedIdentifier node = AstTestFactory.identifier5("a", "b");
node.identifier.staticElement = variable;
expect(_analyze(node), same(_typeProvider.boolType));
_listener.assertNoErrors();
}
void test_visitPrefixExpression_bang() {
// !0
PrefixExpression node =
AstTestFactory.prefixExpression(TokenType.BANG, _resolvedInteger(0));
expect(_analyze(node), same(_typeProvider.boolType));
_listener.assertNoErrors();
}
void test_visitPrefixExpression_minus() {
// -0
PrefixExpression node =
AstTestFactory.prefixExpression(TokenType.MINUS, _resolvedInteger(0));
MethodElement minusMethod = getMethod(_typeProvider.numType, "-");
node.staticElement = minusMethod;
expect(_analyze(node), same(_typeProvider.numType));
_listener.assertNoErrors();
}
void test_visitPrefixExpression_minusMinus() {
// --0
PrefixExpression node = AstTestFactory.prefixExpression(
TokenType.MINUS_MINUS, _resolvedInteger(0));
MethodElement minusMethod = getMethod(_typeProvider.numType, "-");
node.staticElement = minusMethod;
expect(_analyze(node), same(_typeProvider.intType));
_listener.assertNoErrors();
}
void test_visitPrefixExpression_not() {
// !true
Expression node = AstTestFactory.prefixExpression(
TokenType.BANG, AstTestFactory.booleanLiteral(true));
expect(_analyze(node), same(_typeProvider.boolType));
_listener.assertNoErrors();
}
void test_visitPrefixExpression_plusPlus() {
// ++0
PrefixExpression node = AstTestFactory.prefixExpression(
TokenType.PLUS_PLUS, _resolvedInteger(0));
MethodElement plusMethod = getMethod(_typeProvider.numType, "+");
node.staticElement = plusMethod;
expect(_analyze(node), same(_typeProvider.intType));
_listener.assertNoErrors();
}
void test_visitPrefixExpression_tilde() {
// ~0
PrefixExpression node =
AstTestFactory.prefixExpression(TokenType.TILDE, _resolvedInteger(0));
MethodElement tildeMethod = getMethod(_typeProvider.intType, "~");
node.staticElement = tildeMethod;
expect(_analyze(node), same(_typeProvider.intType));
_listener.assertNoErrors();
}
void test_visitPropertyAccess_propagated_getter() {
DartType boolType = _typeProvider.boolType;
PropertyAccessorElementImpl getter =
ElementFactory.getterElement("b", false, boolType);
PropertyAccess node =
AstTestFactory.propertyAccess2(AstTestFactory.identifier3("a"), "b");
node.propertyName.propagatedElement = getter;
expect(_analyze2(node, false), previewDart2 ? isNull : same(boolType));
_listener.assertNoErrors();
}
void test_visitPropertyAccess_propagated_setter() {
DartType boolType = _typeProvider.boolType;
FieldElementImpl field =
ElementFactory.fieldElement("b", false, false, false, boolType);
PropertyAccessorElement setter = field.setter;
PropertyAccess node =
AstTestFactory.propertyAccess2(AstTestFactory.identifier3("a"), "b");
node.propertyName.propagatedElement = setter;
expect(_analyze2(node, false), previewDart2 ? isNull : same(boolType));
_listener.assertNoErrors();
}
void test_visitPropertyAccess_static_getter() {
DartType boolType = _typeProvider.boolType;
PropertyAccessorElementImpl getter =
ElementFactory.getterElement("b", false, boolType);
PropertyAccess node =
AstTestFactory.propertyAccess2(AstTestFactory.identifier3("a"), "b");
node.propertyName.staticElement = getter;
expect(_analyze(node), same(boolType));
_listener.assertNoErrors();
}
void test_visitPropertyAccess_static_setter() {
DartType boolType = _typeProvider.boolType;
FieldElementImpl field =
ElementFactory.fieldElement("b", false, false, false, boolType);
PropertyAccessorElement setter = field.setter;
PropertyAccess node =
AstTestFactory.propertyAccess2(AstTestFactory.identifier3("a"), "b");
node.propertyName.staticElement = setter;
expect(_analyze(node), same(boolType));
_listener.assertNoErrors();
}
void test_visitSimpleIdentifier_dynamic() {
// "dynamic"
SimpleIdentifier identifier = AstTestFactory.identifier3('dynamic');
DynamicElementImpl element = DynamicElementImpl.instance;
identifier.staticElement = element;
identifier.staticType = _typeProvider.typeType;
expect(_analyze(identifier), same(_typeProvider.typeType));
_listener.assertNoErrors();
}
void test_visitSimpleStringLiteral() {
// "a"
Expression node = _resolvedString("a");
expect(_analyze(node), same(_typeProvider.stringType));
_listener.assertNoErrors();
}
void test_visitStringInterpolation() {
// "a${'b'}c"
Expression node = AstTestFactory.string([
AstTestFactory.interpolationString("a", "a"),
AstTestFactory.interpolationExpression(_resolvedString("b")),
AstTestFactory.interpolationString("c", "c")
]);
expect(_analyze(node), same(_typeProvider.stringType));
_listener.assertNoErrors();
}
void test_visitSuperExpression() {
// super
InterfaceType superType = ElementFactory.classElement2("A").type;
InterfaceType thisType = ElementFactory.classElement("B", superType).type;
Expression node = AstTestFactory.superExpression();
expect(_analyze3(node, thisType), same(thisType));
_listener.assertNoErrors();
}
void test_visitSymbolLiteral() {
expect(_analyze(AstTestFactory.symbolLiteral(["a"])),
same(_typeProvider.symbolType));
}
void test_visitThisExpression() {
// this
InterfaceType thisType = ElementFactory
.classElement("B", ElementFactory.classElement2("A").type)
.type;
Expression node = AstTestFactory.thisExpression();
expect(_analyze3(node, thisType), same(thisType));
_listener.assertNoErrors();
}
void test_visitThrowExpression_withoutValue() {
// throw
Expression node = AstTestFactory.throwExpression();
expect(_analyze(node), same(_typeProvider.bottomType));
_listener.assertNoErrors();
}
void test_visitThrowExpression_withValue() {
// throw 0
Expression node = AstTestFactory.throwExpression2(_resolvedInteger(0));
expect(_analyze(node), same(_typeProvider.bottomType));
_listener.assertNoErrors();
}
/**
* Return the type associated with the given expression after the static type analyzer has
* computed a type for it.
*
* @param node the expression with which the type is associated
* @return the type associated with the expression
*/
DartType _analyze(Expression node) => _analyze4(node, null, true);
/**
* Return the type associated with the given expression after the static or propagated type
* analyzer has computed a type for it.
*
* @param node the expression with which the type is associated
* @param useStaticType `true` if the static type is being requested, and `false` if
* the propagated type is being requested
* @return the type associated with the expression
*/
DartType _analyze2(Expression node, bool useStaticType) =>
_analyze4(node, null, useStaticType);
/**
* Return the type associated with the given expression after the static type analyzer has
* computed a type for it.
*
* @param node the expression with which the type is associated
* @param thisType the type of 'this'
* @return the type associated with the expression
*/
DartType _analyze3(Expression node, InterfaceType thisType) =>
_analyze4(node, thisType, true);
/**
* Return the type associated with the given expression after the static type analyzer has
* computed a type for it.
*
* @param node the expression with which the type is associated
* @param thisType the type of 'this'
* @param useStaticType `true` if the static type is being requested, and `false` if
* the propagated type is being requested
* @return the type associated with the expression
*/
DartType _analyze4(
Expression node, InterfaceType thisType, bool useStaticType) {
_analyzer.thisType = thisType;
node.accept(_analyzer);
if (useStaticType) {
return node.staticType;
} else {
return node.propagatedType;
}
}
/**
* Return the type associated with the given parameter after the static type analyzer has computed
* a type for it.
*
* @param node the parameter with which the type is associated
* @return the type associated with the parameter
*/
DartType _analyze5(FormalParameter node) {
node.accept(_analyzer);
return (node.identifier.staticElement as ParameterElement).type;
}
/**
* Assert that the actual type is a function type with the expected characteristics.
*
* @param expectedReturnType the expected return type of the function
* @param expectedNormalTypes the expected types of the normal parameters
* @param expectedOptionalTypes the expected types of the optional parameters
* @param expectedNamedTypes the expected types of the named parameters
* @param actualType the type being tested
*/
void _assertFunctionType(
DartType expectedReturnType,
List<DartType> expectedNormalTypes,
List<DartType> expectedOptionalTypes,
Map<String, DartType> expectedNamedTypes,
DartType actualType) {
EngineTestCase.assertInstanceOf(
(obj) => obj is FunctionType, FunctionType, actualType);
FunctionType functionType = actualType as FunctionType;
List<DartType> normalTypes = functionType.normalParameterTypes;
if (expectedNormalTypes == null) {
expect(normalTypes, hasLength(0));
} else {
int expectedCount = expectedNormalTypes.length;
expect(normalTypes, hasLength(expectedCount));
for (int i = 0; i < expectedCount; i++) {
expect(normalTypes[i], same(expectedNormalTypes[i]));
}
}
List<DartType> optionalTypes = functionType.optionalParameterTypes;
if (expectedOptionalTypes == null) {
expect(optionalTypes, hasLength(0));
} else {
int expectedCount = expectedOptionalTypes.length;
expect(optionalTypes, hasLength(expectedCount));
for (int i = 0; i < expectedCount; i++) {
expect(optionalTypes[i], same(expectedOptionalTypes[i]));
}
}
Map<String, DartType> namedTypes = functionType.namedParameterTypes;
if (expectedNamedTypes == null) {
expect(namedTypes, hasLength(0));
} else {
expect(namedTypes, hasLength(expectedNamedTypes.length));
expectedNamedTypes.forEach((String name, DartType type) {
expect(namedTypes[name], same(type));
});
}
expect(functionType.returnType, equals(expectedReturnType));
}
void _assertType(
InterfaceTypeImpl expectedType, InterfaceTypeImpl actualType) {
expect(actualType.displayName, expectedType.displayName);
expect(actualType.element, expectedType.element);
List<DartType> expectedArguments = expectedType.typeArguments;
int length = expectedArguments.length;
List<DartType> actualArguments = actualType.typeArguments;
expect(actualArguments, hasLength(length));
for (int i = 0; i < length; i++) {
_assertType2(expectedArguments[i], actualArguments[i]);
}
}
void _assertType2(DartType expectedType, DartType actualType) {
if (expectedType is InterfaceTypeImpl) {
EngineTestCase.assertInstanceOf(
(obj) => obj is InterfaceTypeImpl, InterfaceTypeImpl, actualType);
_assertType(expectedType, actualType as InterfaceTypeImpl);
}
// TODO(brianwilkerson) Compare other kinds of types then make this a shared
// utility method.
}
/**
* Create the analyzer used by the tests.
*/
StaticTypeAnalyzer _createAnalyzer({bool strongMode: false}) {
MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
InternalAnalysisContext context;
if (strongMode) {
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
options.strongMode = true;
context = AnalysisContextFactory.contextWithCoreAndOptions(options,
resourceProvider: resourceProvider);
} else {
context = AnalysisContextFactory.contextWithCore(
resourceProvider: resourceProvider);
}
_analysisOptions = context.analysisOptions;
Source source = new FileSource(resourceProvider.getFile("/lib.dart"));
CompilationUnitElementImpl definingCompilationUnit =
new CompilationUnitElementImpl("lib.dart");
definingCompilationUnit.librarySource =
definingCompilationUnit.source = source;
LibraryElementImpl definingLibrary =
new LibraryElementImpl.forNode(context, null);
definingLibrary.definingCompilationUnit = definingCompilationUnit;
_typeProvider = context.typeProvider;
_visitor = new ResolverVisitor(
definingLibrary, source, _typeProvider, _listener,
nameScope: new LibraryScope(definingLibrary));
_visitor.overrideManager.enterScope();
return _visitor.typeAnalyzer;
}
DartType _flatten(DartType type) => type.flattenFutures(_typeSystem);
/**
* Return a simple identifier that has been resolved to a variable element with the given type.
*
* @param type the type of the variable being represented
* @param variableName the name of the variable
* @return a simple identifier that has been resolved to a variable element with the given type
*/
SimpleIdentifier _propagatedVariable(
InterfaceType type, String variableName) {
SimpleIdentifier identifier = AstTestFactory.identifier3(variableName);
VariableElementImpl element =
ElementFactory.localVariableElement(identifier);
element.type = type;
identifier.staticType = _typeProvider.dynamicType;
identifier.propagatedElement = element;
identifier.propagatedType = type;
return identifier;
}
/**
* Return a boolean literal with the given [value] that has been resolved to
* the correct type.
*/
BooleanLiteral _resolvedBool(bool value) {
BooleanLiteral literal = AstTestFactory.booleanLiteral(value);
literal.staticType = _typeProvider.intType;
return literal;
}
/**
* Return an integer literal that has been resolved to the correct type.
*
* @param value the value of the literal
* @return an integer literal that has been resolved to the correct type
*/
DoubleLiteral _resolvedDouble(double value) {
DoubleLiteral literal = AstTestFactory.doubleLiteral(value);
literal.staticType = _typeProvider.doubleType;
return literal;
}
/**
* Create a function expression that has an element associated with it, where the element has an
* incomplete type associated with it (just like the one
* [ElementBuilder.visitFunctionExpression] would have built if we had
* run it).
*
* @param parameters the parameters to the function
* @param body the body of the function
* @return a resolved function expression
*/
FunctionExpression _resolvedFunctionExpression(
FormalParameterList parameters, FunctionBody body) {
List<ParameterElement> parameterElements = new List<ParameterElement>();
for (FormalParameter parameter in parameters.parameters) {
ParameterElementImpl element =
new ParameterElementImpl.forNode(parameter.identifier);
// ignore: deprecated_member_use
element.parameterKind = parameter.kind;
element.type = _typeProvider.dynamicType;
parameter.identifier.staticElement = element;
parameterElements.add(element);
}
FunctionExpression node =
AstTestFactory.functionExpression2(parameters, body);
FunctionElementImpl element = new FunctionElementImpl.forNode(null);
element.parameters = parameterElements;
element.type = new FunctionTypeImpl(element);
node.element = element;
return node;
}
/**
* Return an integer literal that has been resolved to the correct type.
*
* @param value the value of the literal
* @return an integer literal that has been resolved to the correct type
*/
IntegerLiteral _resolvedInteger(int value) {
IntegerLiteral literal = AstTestFactory.integer(value);
literal.staticType = _typeProvider.intType;
return literal;
}
/**
* Return a string literal that has been resolved to the correct type.
*
* @param value the value of the literal
* @return a string literal that has been resolved to the correct type
*/
SimpleStringLiteral _resolvedString(String value) {
SimpleStringLiteral string = AstTestFactory.string2(value);
string.staticType = _typeProvider.stringType;
return string;
}
/**
* Return a simple identifier that has been resolved to a variable element with the given type.
*
* @param type the type of the variable being represented
* @param variableName the name of the variable
* @return a simple identifier that has been resolved to a variable element with the given type
*/
SimpleIdentifier _resolvedVariable(InterfaceType type, String variableName) {
SimpleIdentifier identifier = AstTestFactory.identifier3(variableName);
VariableElementImpl element =
ElementFactory.localVariableElement(identifier);
element.type = type;
identifier.staticElement = element;
identifier.staticType = type;
return identifier;
}
/**
* Set the type of the given parameter to the given type.
*
* @param parameter the parameter whose type is to be set
* @param type the new type of the given parameter
*/
void _setType(FormalParameter parameter, DartType type) {
SimpleIdentifier identifier = parameter.identifier;
Element element = identifier.staticElement;
if (element is! ParameterElement) {
element = new ParameterElementImpl.forNode(identifier);
identifier.staticElement = element;
}
(element as ParameterElementImpl).type = type;
}
}