Chromium Code Reviews| Index: pkg/analyzer/test/generated/resolver_test.dart |
| diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart |
| index 7c6becec92feec3e38b318e920735725e0697e53..69de77e1ed359e0d48ad8aea7e0be1d927c42875 100644 |
| --- a/pkg/analyzer/test/generated/resolver_test.dart |
| +++ b/pkg/analyzer/test/generated/resolver_test.dart |
| @@ -68,6 +68,7 @@ main() { |
| runReflectiveTests(SimpleResolverTest); |
| runReflectiveTests(StrictModeTest); |
| runReflectiveTests(TypePropagationTest); |
| + runReflectiveTests(StrongModeDownwardsInferenceTest); |
| runReflectiveTests(StrongModeStaticTypeAnalyzer2Test); |
| runReflectiveTests(StrongModeTypePropagationTest); |
| } |
| @@ -12127,6 +12128,971 @@ int f() { |
| } |
| /** |
| + * Strong mode static analyzer downwards inference tests |
| + */ |
| +@reflectiveTest |
| +class StrongModeDownwardsInferenceTest extends ResolverTestCase { |
| + TypeAssertions _assertions; |
| + AsserterBuilder<Element, DartType> _hasElement; |
| + AsserterBuilder<DartType, DartType> _isType; |
| + AsserterBuilder2<Asserter<DartType>, Asserter<DartType>, |
| + DartType> _isFunction2Of; |
| + AsserterBuilderBuilder<Asserter<DartType>, List<Asserter<DartType>>, |
| + DartType> _isInstantiationOf; |
| + Asserter<DartType> _isInt; |
| + Asserter<DartType> _isNum; |
| + Asserter<DartType> _isString; |
| + Asserter<DartType> _isDynamic; |
| + AsserterBuilder<Asserter<DartType>, InterfaceType> _isListOf; |
| + AsserterBuilder2<Asserter<DartType>, Asserter<DartType>, |
| + InterfaceType> _isMapOf; |
| + |
| + @override |
| + void setUp() { |
| + AnalysisOptionsImpl options = new AnalysisOptionsImpl(); |
| + options.strongMode = true; |
| + resetWithOptions(options); |
| + _assertions = new TypeAssertions(typeProvider); |
| + _isType = _assertions.isType; |
| + _hasElement = _assertions.hasElement; |
| + _isInstantiationOf = _assertions.isInstantiationOf; |
| + _isInt = _assertions.isInt; |
| + _isNum = _assertions.isNum; |
| + _isString = _assertions.isString; |
| + _isDynamic = _assertions.isDynamic; |
| + _isListOf = _assertions.isListOf; |
| + _isMapOf = _assertions.isMapOf; |
| + _isFunction2Of = _assertions.isFunction2Of; |
| + } |
| + |
| + void test_cascadeExpression() { |
| + String code = r''' |
| + class A<T> { |
| + List<T> map(T a, List<T> mapper(T x)) => mapper(a); |
| + } |
| + |
| + void main () { |
| + A<int> a = new A()..map(0, (x) => [x]); |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "main"); |
| + CascadeExpression fetch(int i) { |
| + VariableDeclarationStatement stmt = statements[i]; |
| + VariableDeclaration decl = stmt.variables.variables[0]; |
| + CascadeExpression exp = decl.initializer; |
| + return exp; |
| + } |
| + Element elementA = AstFinder.getClass(unit, "A").element; |
| + |
| + CascadeExpression cascade = fetch(0); |
| + _isInstantiationOf(_hasElement(elementA))([_isInt])(cascade.staticType); |
| + MethodInvocation invoke = cascade.cascadeSections[0]; |
| + FunctionExpression function = invoke.argumentList.arguments[1]; |
| + ExecutableElement f0 = function.element; |
| + _isListOf(_isInt)(f0.type.returnType); |
| + expect(f0.type.normalParameterTypes[0], typeProvider.intType); |
| + } |
| + |
| + void test_constructorInitializer_propagation() { |
| + String code = r''' |
| + class A { |
| + List<String> x; |
| + A() : this.x = []; |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + ConstructorDeclaration constructor = |
| + AstFinder.getConstructorInClass(unit, "A", null); |
| + ConstructorFieldInitializer assignment = constructor.initializers[0]; |
| + Expression exp = assignment.expression; |
| + _isListOf(_isString)(exp.staticType); |
| + } |
| + |
| + void test_factoryConstructor_propagation() { |
| + String code = r''' |
| + class A<T> { |
| + factory A() { return new B(); } |
| + } |
| + class B<S> extends A<S> {} |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + |
| + ConstructorDeclaration constructor = |
| + AstFinder.getConstructorInClass(unit, "A", null); |
| + BlockFunctionBody body = constructor.body; |
| + ReturnStatement stmt = body.block.statements[0]; |
| + InstanceCreationExpression exp = stmt.expression; |
| + ClassElement elementB = AstFinder.getClass(unit, "B").element; |
| + ClassElement elementA = AstFinder.getClass(unit, "A").element; |
| + expect(exp.constructorName.type.type.element, elementB); |
| + _isInstantiationOf(_hasElement(elementB))( |
| + [_isType(elementA.typeParameters[0].type)])(exp.staticType); |
| + } |
| + |
| + void test_fieldDeclaration_propagation() { |
| + String code = r''' |
| + class A { |
| + List<String> f0 = ["hello"]; |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + |
| + VariableDeclaration field = AstFinder.getFieldInClass(unit, "A", "f0"); |
| + |
| + _isListOf(_isString)(field.initializer.staticType); |
| + } |
| + |
| + void test_functionDeclaration_body_propagation() { |
| + String code = r''' |
| + typedef T Function2<S, T>(S x); |
| + |
| + List<int> test1() => []; |
| + |
| + Function2<int, int> test2 (int x) { |
| + Function2<String, int> inner() { |
| + return (x) => x.length; |
| + } |
| + return (x) => x; |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + |
| + Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt); |
| + |
| + FunctionDeclaration test1 = AstFinder.getTopLevelFunction(unit, "test1"); |
| + ExpressionFunctionBody body = test1.functionExpression.body; |
| + assertListOfInt(body.expression.staticType); |
| + |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "test2"); |
| + |
| + FunctionDeclaration inner = |
| + (statements[0] as FunctionDeclarationStatement).functionDeclaration; |
| + BlockFunctionBody body0 = inner.functionExpression.body; |
| + ReturnStatement return0 = body0.block.statements[0]; |
| + Expression anon0 = return0.expression; |
| + FunctionType type0 = anon0.staticType; |
| + expect(type0.returnType, typeProvider.intType); |
| + expect(type0.normalParameterTypes[0], typeProvider.stringType); |
| + |
| + FunctionExpression anon1 = (statements[1] as ReturnStatement).expression; |
| + FunctionType type1 = anon1.element.type; |
| + expect(type1.returnType, typeProvider.intType); |
| + expect(type1.normalParameterTypes[0], typeProvider.intType); |
| + } |
| + |
| + void test_functionLiteral_assignment_typedArguments() { |
| + String code = r''' |
| + typedef T Function2<S, T>(S x); |
| + |
| + void main () { |
| + Function2<int, String> l0 = (int x) => null; |
| + Function2<int, String> l1 = (int x) => "hello"; |
| + Function2<int, String> l2 = (String x) => "hello"; |
| + Function2<int, String> l3 = (int x) => 3; |
| + Function2<int, String> l4 = (int x) {return 3;}; |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "main"); |
| + DartType literal(int i) { |
| + VariableDeclarationStatement stmt = statements[i]; |
| + VariableDeclaration decl = stmt.variables.variables[0]; |
| + FunctionExpression exp = decl.initializer; |
| + return exp.element.type; |
| + } |
| + _isFunction2Of(_isInt, _isString)(literal(0)); |
| + _isFunction2Of(_isInt, _isString)(literal(1)); |
| + _isFunction2Of(_isString, _isString)(literal(2)); |
| + _isFunction2Of(_isInt, _isInt)(literal(3)); |
| + _isFunction2Of(_isInt, _isString)(literal(4)); |
| + } |
| + |
| + void test_functionLiteral_assignment_unTypedArguments() { |
| + String code = r''' |
| + typedef T Function2<S, T>(S x); |
| + |
| + void main () { |
| + Function2<int, String> l0 = (x) => null; |
| + Function2<int, String> l1 = (x) => "hello"; |
| + Function2<int, String> l2 = (x) => "hello"; |
| + Function2<int, String> l3 = (x) => 3; |
| + Function2<int, String> l4 = (x) {return 3;}; |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "main"); |
| + DartType literal(int i) { |
| + VariableDeclarationStatement stmt = statements[i]; |
| + VariableDeclaration decl = stmt.variables.variables[0]; |
| + FunctionExpression exp = decl.initializer; |
| + return exp.element.type; |
| + } |
| + _isFunction2Of(_isInt, _isString)(literal(0)); |
| + _isFunction2Of(_isInt, _isString)(literal(1)); |
| + _isFunction2Of(_isInt, _isString)(literal(2)); |
| + _isFunction2Of(_isInt, _isInt)(literal(3)); |
| + _isFunction2Of(_isInt, _isString)(literal(4)); |
| + } |
| + |
| + void test_functionLiteral_body_propagation() { |
| + String code = r''' |
| + typedef T Function2<S, T>(S x); |
| + |
| + void main () { |
| + Function2<int, List<String>> l0 = (int x) => ["hello"]; |
| + Function2<int, List<String>> l1 = (String x) => ["hello"]; |
| + Function2<int, List<String>> l2 = (int x) => [3]; |
| + Function2<int, List<String>> l3 = (int x) {return [3];}; |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "main"); |
| + Expression functionReturnValue(int i) { |
| + VariableDeclarationStatement stmt = statements[i]; |
| + VariableDeclaration decl = stmt.variables.variables[0]; |
| + FunctionExpression exp = decl.initializer; |
| + FunctionBody body = exp.body; |
| + if (body is ExpressionFunctionBody) { |
| + return body.expression; |
| + } else { |
| + Statement stmt = (body as BlockFunctionBody).block.statements[0]; |
| + return (stmt as ReturnStatement).expression; |
| + } |
| + } |
| + Asserter<InterfaceType> assertListOfString = _isListOf(_isString); |
| + assertListOfString(functionReturnValue(0).staticType); |
| + assertListOfString(functionReturnValue(1).staticType); |
| + assertListOfString(functionReturnValue(2).staticType); |
| + assertListOfString(functionReturnValue(3).staticType); |
| + } |
| + |
| + void test_functionLiteral_functionExpressionInvocation_typedArguments() { |
| + String code = r''' |
| + class Mapper<F, T> { |
| + T map(T mapper(F x)) => mapper(null); |
| + } |
| + |
| + void main () { |
| + (new Mapper<int, String>().map)((int x) => null); |
| + (new Mapper<int, String>().map)((int x) => "hello"); |
| + (new Mapper<int, String>().map)((String x) => "hello"); |
| + (new Mapper<int, String>().map)((int x) => 3); |
| + (new Mapper<int, String>().map)((int x) {return 3;}); |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "main"); |
| + DartType literal(int i) { |
| + ExpressionStatement stmt = statements[i]; |
| + FunctionExpressionInvocation invk = stmt.expression; |
| + FunctionExpression exp = invk.argumentList.arguments[0]; |
| + return exp.element.type; |
| + } |
| + _isFunction2Of(_isInt, _isString)(literal(0)); |
| + _isFunction2Of(_isInt, _isString)(literal(1)); |
| + _isFunction2Of(_isString, _isString)(literal(2)); |
| + _isFunction2Of(_isInt, _isInt)(literal(3)); |
| + _isFunction2Of(_isInt, _isString)(literal(4)); |
| + } |
| + |
| + void test_functionLiteral_functionExpressionInvocation_unTypedArguments() { |
| + String code = r''' |
| + class Mapper<F, T> { |
| + T map(T mapper(F x)) => mapper(null); |
| + } |
| + |
| + void main () { |
| + (new Mapper<int, String>().map)((x) => null); |
| + (new Mapper<int, String>().map)((x) => "hello"); |
| + (new Mapper<int, String>().map)((x) => "hello"); |
| + (new Mapper<int, String>().map)((x) => 3); |
| + (new Mapper<int, String>().map)((x) {return 3;}); |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "main"); |
| + DartType literal(int i) { |
| + ExpressionStatement stmt = statements[i]; |
| + FunctionExpressionInvocation invk = stmt.expression; |
| + FunctionExpression exp = invk.argumentList.arguments[0]; |
| + return exp.element.type; |
| + } |
| + _isFunction2Of(_isInt, _isString)(literal(0)); |
| + _isFunction2Of(_isInt, _isString)(literal(1)); |
| + _isFunction2Of(_isInt, _isString)(literal(2)); |
| + _isFunction2Of(_isInt, _isInt)(literal(3)); |
| + _isFunction2Of(_isInt, _isString)(literal(4)); |
| + } |
| + |
| + void test_functionLiteral_functionInvocation_typedArguments() { |
| + String code = r''' |
| + String map(String mapper(int x)) => mapper(null); |
| + |
| + void main () { |
| + map((int x) => null); |
| + map((int x) => "hello"); |
| + map((String x) => "hello"); |
| + map((int x) => 3); |
| + map((int x) {return 3;}); |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "main"); |
| + DartType literal(int i) { |
| + ExpressionStatement stmt = statements[i]; |
| + MethodInvocation invk = stmt.expression; |
| + FunctionExpression exp = invk.argumentList.arguments[0]; |
| + return exp.element.type; |
| + } |
| + _isFunction2Of(_isInt, _isString)(literal(0)); |
| + _isFunction2Of(_isInt, _isString)(literal(1)); |
| + _isFunction2Of(_isString, _isString)(literal(2)); |
| + _isFunction2Of(_isInt, _isInt)(literal(3)); |
| + _isFunction2Of(_isInt, _isString)(literal(4)); |
| + } |
| + |
| + void test_functionLiteral_functionInvocation_unTypedArguments() { |
| + String code = r''' |
| + String map(String mapper(int x)) => mapper(null); |
| + |
| + void main () { |
| + map((x) => null); |
| + map((x) => "hello"); |
| + map((x) => "hello"); |
| + map((x) => 3); |
| + map((x) {return 3;}); |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "main"); |
| + DartType literal(int i) { |
| + ExpressionStatement stmt = statements[i]; |
| + MethodInvocation invk = stmt.expression; |
| + FunctionExpression exp = invk.argumentList.arguments[0]; |
| + return exp.element.type; |
| + } |
| + _isFunction2Of(_isInt, _isString)(literal(0)); |
| + _isFunction2Of(_isInt, _isString)(literal(1)); |
| + _isFunction2Of(_isInt, _isString)(literal(2)); |
| + _isFunction2Of(_isInt, _isInt)(literal(3)); |
| + _isFunction2Of(_isInt, _isString)(literal(4)); |
| + } |
| + |
| + void test_functionLiteral_methodInvocation_typedArguments() { |
| + String code = r''' |
| + class Mapper<F, T> { |
| + T map(T mapper(F x)) => mapper(null); |
| + } |
| + |
| + void main () { |
| + new Mapper<int, String>().map((int x) => null); |
| + new Mapper<int, String>().map((int x) => "hello"); |
| + new Mapper<int, String>().map((String x) => "hello"); |
| + new Mapper<int, String>().map((int x) => 3); |
| + new Mapper<int, String>().map((int x) {return 3;}); |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "main"); |
| + DartType literal(int i) { |
| + ExpressionStatement stmt = statements[i]; |
| + MethodInvocation invk = stmt.expression; |
| + FunctionExpression exp = invk.argumentList.arguments[0]; |
| + return exp.element.type; |
| + } |
| + _isFunction2Of(_isInt, _isString)(literal(0)); |
| + _isFunction2Of(_isInt, _isString)(literal(1)); |
| + _isFunction2Of(_isString, _isString)(literal(2)); |
| + _isFunction2Of(_isInt, _isInt)(literal(3)); |
| + _isFunction2Of(_isInt, _isString)(literal(4)); |
| + } |
| + |
| + void test_functionLiteral_methodInvocation_unTypedArguments() { |
| + String code = r''' |
| + class Mapper<F, T> { |
| + T map(T mapper(F x)) => mapper(null); |
| + } |
| + |
| + void main () { |
| + new Mapper<int, String>().map((x) => null); |
| + new Mapper<int, String>().map((x) => "hello"); |
| + new Mapper<int, String>().map((x) => "hello"); |
| + new Mapper<int, String>().map((x) => 3); |
| + new Mapper<int, String>().map((x) {return 3;}); |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "main"); |
| + DartType literal(int i) { |
| + ExpressionStatement stmt = statements[i]; |
| + MethodInvocation invk = stmt.expression; |
| + FunctionExpression exp = invk.argumentList.arguments[0]; |
| + return exp.element.type; |
| + } |
| + _isFunction2Of(_isInt, _isString)(literal(0)); |
| + _isFunction2Of(_isInt, _isString)(literal(1)); |
| + _isFunction2Of(_isInt, _isString)(literal(2)); |
| + _isFunction2Of(_isInt, _isInt)(literal(3)); |
| + _isFunction2Of(_isInt, _isString)(literal(4)); |
| + } |
| + |
| + void test_functionLiteral_unTypedArgument_propagation() { |
| + String code = r''' |
| + typedef T Function2<S, T>(S x); |
| + |
| + void main () { |
| + Function2<int, int> l0 = (x) => x; |
| + Function2<int, int> l1 = (x) => x+1; |
| + Function2<int, String> l2 = (x) => x; |
| + Function2<int, String> l3 = (x) => x.toLowerCase(); |
| + Function2<String, String> l4 = (x) => x.toLowerCase(); |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "main"); |
| + Expression functionReturnValue(int i) { |
| + VariableDeclarationStatement stmt = statements[i]; |
| + VariableDeclaration decl = stmt.variables.variables[0]; |
| + FunctionExpression exp = decl.initializer; |
| + FunctionBody body = exp.body; |
| + if (body is ExpressionFunctionBody) { |
| + return body.expression; |
| + } else { |
| + Statement stmt = (body as BlockFunctionBody).block.statements[0]; |
| + return (stmt as ReturnStatement).expression; |
| + } |
| + } |
| + expect(functionReturnValue(0).staticType, typeProvider.intType); |
| + expect(functionReturnValue(1).staticType, typeProvider.intType); |
| + expect(functionReturnValue(2).staticType, typeProvider.intType); |
| + expect(functionReturnValue(3).staticType, typeProvider.dynamicType); |
| + expect(functionReturnValue(4).staticType, typeProvider.stringType); |
| + } |
| + |
| + void test_instanceCreation() { |
| + String code = r''' |
| + class A<S, T> { |
| + S x; |
| + T y; |
| + A(this.x, this.y); |
| + A.named(this.x, this.y); |
| + } |
| + |
| + class B<S, T> extends A<T, S> { |
| + B(S y, T x) : super(x, y); |
| + B.named(S y, T x) : super.named(x, y); |
| + } |
| + |
| + class C<S> extends B<S, S> { |
| + C(S a) : super(a, a); |
| + C.named(S a) : super.named(a, a); |
| + } |
| + |
| + class D<S, T> extends B<T, int> { |
| + D(T a) : super(a, 3); |
| + D.named(T a) : super.named(a, 3); |
| + } |
| + |
| + class E<S, T> extends A<C<S>, T> { |
| + E(T a) : super(null, a); |
| + } |
| + |
| + class F<S, T> extends A<S, T> { |
| + F(S x, T y, {List<S> a, List<T> b}) : super(x, y); |
| + F.named(S x, T y, [S a, T b]) : super(a, b); |
| + } |
| + |
| + void test0() { |
| + A<int, String> a0 = new A(3, "hello"); |
|
Jennifer Messerly
2015/11/23 22:11:58
formatting is a little off in this string literal.
Leaf
2015/12/01 21:49:12
Done.
|
| + A<int, String> a1 = new A.named(3, "hello"); |
| + A<int, String> a2 = new A<int, String>(3, "hello"); |
| + A<int, String> a3 = new A<int, String>.named(3, "hello"); |
| + A<int, String> a4 = new A<int, dynamic>(3, "hello"); |
| + A<int, String> a5 = new A<dynamic, dynamic>.named(3, "hello"); |
| + } |
| + void test1() { |
| + A<int, String> a0 = new A("hello", 3); |
| + A<int, String> a1 = new A.named("hello", 3); |
| + } |
| + void test2() { |
| + A<int, String> a0 = new B("hello", 3); |
| + A<int, String> a1 = new B.named("hello", 3); |
| + A<int, String> a2 = new B<String, int>("hello", 3); |
| + A<int, String> a3 = new B<String, int>.named("hello", 3); |
| + A<int, String> a4 = new B<String, dynamic>("hello", 3); |
| + A<int, String> a5 = new B<dynamic, dynamic>.named("hello", 3); |
| + } |
| + void test3() { |
| + A<int, String> a0 = new B(3, "hello"); |
| + A<int, String> a1 = new B.named(3, "hello"); |
| + } |
| + void test4() { |
| + A<int, int> a0 = new C(3); |
| + A<int, int> a1 = new C.named(3); |
| + A<int, int> a2 = new C<int>(3); |
| + A<int, int> a3 = new C<int>.named(3); |
| + A<int, int> a4 = new C<dynamic>(3); |
| + A<int, int> a5 = new C<dynamic>.named(3); |
| + } |
| + void test5() { |
| + A<int, int> a0 = new C("hello"); |
| + A<int, int> a1 = new C.named("hello"); |
| + } |
| + void test6() { |
| + A<int, String> a0 = new D("hello"); |
| + A<int, String> a1 = new D.named("hello"); |
| + A<int, String> a2 = new D<int, String>("hello"); |
| + A<int, String> a3 = new D<String, String>.named("hello"); |
| + A<int, String> a4 = new D<num, dynamic>("hello"); |
| + A<int, String> a5 = new D<dynamic, dynamic>.named("hello"); |
| + } |
| + void test7() { |
| + A<int, String> a0 = new D(3); |
| + A<int, String> a1 = new D.named(3); |
| + } |
| + void test8() { // Currently we only allow variable constraints. Test that we reject. |
|
Jennifer Messerly
2015/11/23 22:11:58
long line here
Leaf
2015/12/01 21:49:12
Done.
|
| + A<C<int>, String> a0 = new E("hello"); |
| + } |
| + void test9() { // Check named and optional arguments |
| + A<int, String> a0 = new F(3, "hello", a: [3], b: ["hello"]); |
| + A<int, String> a1 = new F(3, "hello", a: ["hello"], b:[3]); |
| + A<int, String> a2 = new F.named(3, "hello", 3, "hello"); |
| + A<int, String> a3 = new F.named(3, "hello"); |
| + A<int, String> a4 = new F.named(3, "hello", "hello", 3); |
| + A<int, String> a5 = new F.named(3, "hello", "hello"); |
| + } |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + |
| + Expression rhs(VariableDeclarationStatement stmt) { |
| + VariableDeclaration decl = stmt.variables.variables[0]; |
| + Expression exp = decl.initializer; |
| + return exp; |
| + } |
| + |
| + void hasType(Asserter<DartType> assertion, Expression exp) => |
| + assertion(exp.staticType); |
| + |
| + Element elementA = AstFinder.getClass(unit, "A").element; |
| + Element elementB = AstFinder.getClass(unit, "B").element; |
| + Element elementC = AstFinder.getClass(unit, "C").element; |
| + Element elementD = AstFinder.getClass(unit, "D").element; |
| + Element elementE = AstFinder.getClass(unit, "E").element; |
| + Element elementF = AstFinder.getClass(unit, "F").element; |
| + |
| + AsserterBuilder<List<Asserter<DartType>>, DartType> assertAOf = |
| + _isInstantiationOf(_hasElement(elementA)); |
| + AsserterBuilder<List<Asserter<DartType>>, DartType> assertBOf = |
| + _isInstantiationOf(_hasElement(elementB)); |
| + AsserterBuilder<List<Asserter<DartType>>, DartType> assertCOf = |
| + _isInstantiationOf(_hasElement(elementC)); |
| + AsserterBuilder<List<Asserter<DartType>>, DartType> assertDOf = |
| + _isInstantiationOf(_hasElement(elementD)); |
| + AsserterBuilder<List<Asserter<DartType>>, DartType> assertEOf = |
| + _isInstantiationOf(_hasElement(elementE)); |
| + AsserterBuilder<List<Asserter<DartType>>, DartType> assertFOf = |
| + _isInstantiationOf(_hasElement(elementF)); |
| + |
| + { |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "test0"); |
| + |
| + hasType(assertAOf([_isInt, _isString]), rhs(statements[0])); |
| + hasType(assertAOf([_isInt, _isString]), rhs(statements[0])); |
| + hasType(assertAOf([_isInt, _isString]), rhs(statements[1])); |
| + hasType(assertAOf([_isInt, _isString]), rhs(statements[2])); |
| + hasType(assertAOf([_isInt, _isString]), rhs(statements[3])); |
| + hasType(assertAOf([_isInt, _isDynamic]), rhs(statements[4])); |
| + hasType(assertAOf([_isDynamic, _isDynamic]), rhs(statements[5])); |
| + } |
| + |
| + { |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "test1"); |
| + hasType(assertAOf([_isInt, _isString]), rhs(statements[0])); |
| + hasType(assertAOf([_isInt, _isString]), rhs(statements[1])); |
| + } |
| + |
| + { |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "test2"); |
| + hasType(assertBOf([_isString, _isInt]), rhs(statements[0])); |
| + hasType(assertBOf([_isString, _isInt]), rhs(statements[1])); |
| + hasType(assertBOf([_isString, _isInt]), rhs(statements[2])); |
| + hasType(assertBOf([_isString, _isInt]), rhs(statements[3])); |
| + hasType(assertBOf([_isString, _isDynamic]), rhs(statements[4])); |
| + hasType(assertBOf([_isDynamic, _isDynamic]), rhs(statements[5])); |
| + } |
| + |
| + { |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "test3"); |
| + hasType(assertBOf([_isString, _isInt]), rhs(statements[0])); |
| + hasType(assertBOf([_isString, _isInt]), rhs(statements[1])); |
| + } |
| + |
| + { |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "test4"); |
| + hasType(assertCOf([_isInt]), rhs(statements[0])); |
| + hasType(assertCOf([_isInt]), rhs(statements[1])); |
| + hasType(assertCOf([_isInt]), rhs(statements[2])); |
| + hasType(assertCOf([_isInt]), rhs(statements[3])); |
| + hasType(assertCOf([_isDynamic]), rhs(statements[4])); |
| + hasType(assertCOf([_isDynamic]), rhs(statements[5])); |
| + } |
| + |
| + { |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "test5"); |
| + hasType(assertCOf([_isInt]), rhs(statements[0])); |
| + hasType(assertCOf([_isInt]), rhs(statements[1])); |
| + } |
| + |
| + { |
| + // The first type parameter is not constrained by the |
| + // context. We could choose a tighter type, but currently |
| + // we just use dynamic. |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "test6"); |
| + hasType(assertDOf([_isDynamic, _isString]), rhs(statements[0])); |
| + hasType(assertDOf([_isDynamic, _isString]), rhs(statements[1])); |
| + hasType(assertDOf([_isInt, _isString]), rhs(statements[2])); |
| + hasType(assertDOf([_isString, _isString]), rhs(statements[3])); |
| + hasType(assertDOf([_isNum, _isDynamic]), rhs(statements[4])); |
| + hasType(assertDOf([_isDynamic, _isDynamic]), rhs(statements[5])); |
| + } |
| + |
| + { |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "test7"); |
| + hasType(assertDOf([_isDynamic, _isString]), rhs(statements[0])); |
| + hasType(assertDOf([_isDynamic, _isString]), rhs(statements[1])); |
| + } |
| + |
| + { |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "test8"); |
| + hasType(assertEOf([_isDynamic, _isDynamic]), rhs(statements[0])); |
| + } |
| + |
| + { |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "test9"); |
| + hasType(assertFOf([_isInt, _isString]), rhs(statements[0])); |
| + hasType(assertFOf([_isInt, _isString]), rhs(statements[1])); |
| + hasType(assertFOf([_isInt, _isString]), rhs(statements[2])); |
| + hasType(assertFOf([_isInt, _isString]), rhs(statements[3])); |
| + hasType(assertFOf([_isInt, _isString]), rhs(statements[4])); |
| + hasType(assertFOf([_isInt, _isString]), rhs(statements[5])); |
| + } |
| + } |
| + |
| + void test_listLiteral_nested() { |
| + String code = r''' |
| + void main () { |
| + List<List<int>> l0 = [[]]; |
| + Iterable<List<int>> l1 = [[3]]; |
| + Iterable<List<int>> l2 = [[3], [4]]; |
| + List<List<int>> l3 = [["hello", 3], []]; |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "main"); |
| + ListLiteral literal(int i) { |
| + VariableDeclarationStatement stmt = statements[i]; |
| + VariableDeclaration decl = stmt.variables.variables[0]; |
| + ListLiteral exp = decl.initializer; |
| + return exp; |
| + } |
| + |
| + Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt); |
| + Asserter<InterfaceType> assertListOfListOfInt = _isListOf(assertListOfInt); |
| + |
| + assertListOfListOfInt(literal(0).staticType); |
| + assertListOfListOfInt(literal(1).staticType); |
| + assertListOfListOfInt(literal(2).staticType); |
| + assertListOfListOfInt(literal(3).staticType); |
| + |
| + assertListOfInt(literal(1).elements[0].staticType); |
| + assertListOfInt(literal(2).elements[0].staticType); |
| + assertListOfInt(literal(3).elements[0].staticType); |
| + } |
| + |
| + void test_listLiteral_simple() { |
| + String code = r''' |
| + void main () { |
| + List<int> l0 = []; |
| + List<int> l1 = [3]; |
| + List<int> l2 = ["hello"]; |
| + List<int> l3 = ["hello", 3]; |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "main"); |
| + DartType literal(int i) { |
| + VariableDeclarationStatement stmt = statements[i]; |
| + VariableDeclaration decl = stmt.variables.variables[0]; |
| + ListLiteral exp = decl.initializer; |
| + return exp.staticType; |
| + } |
| + |
| + Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt); |
| + |
| + assertListOfInt(literal(0)); |
| + assertListOfInt(literal(1)); |
| + assertListOfInt(literal(2)); |
| + assertListOfInt(literal(3)); |
| + } |
| + |
| + void test_listLiteral_simple_const() { |
| + String code = r''' |
| + void main () { |
| + const List<int> c0 = const []; |
| + const List<int> c1 = const [3]; |
| + const List<int> c2 = const ["hello"]; |
| + const List<int> c3 = const ["hello", 3]; |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "main"); |
| + DartType literal(int i) { |
| + VariableDeclarationStatement stmt = statements[i]; |
| + VariableDeclaration decl = stmt.variables.variables[0]; |
| + ListLiteral exp = decl.initializer; |
| + return exp.staticType; |
| + } |
| + |
| + Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt); |
| + |
| + assertListOfInt(literal(0)); |
| + assertListOfInt(literal(1)); |
| + assertListOfInt(literal(2)); |
| + assertListOfInt(literal(3)); |
| + } |
| + |
| + void test_listLiteral_simple_disabled() { |
| + String code = r''' |
| + void main () { |
| + List<int> l0 = <num>[]; |
| + List<int> l1 = <num>[3]; |
| + List<int> l2 = <String>["hello"]; |
| + List<int> l3 = <dynamic>["hello", 3]; |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "main"); |
| + DartType literal(int i) { |
| + VariableDeclarationStatement stmt = statements[i]; |
| + VariableDeclaration decl = stmt.variables.variables[0]; |
| + ListLiteral exp = decl.initializer; |
| + return exp.staticType; |
| + } |
| + |
| + _isListOf(_isNum)(literal(0)); |
| + _isListOf(_isNum)(literal(1)); |
| + _isListOf(_isString)(literal(2)); |
| + _isListOf(_isDynamic)(literal(3)); |
| + } |
| + |
| + void test_listLiteral_simple_subtype() { |
| + String code = r''' |
| + void main () { |
| + Iterable<int> l0 = []; |
| + Iterable<int> l1 = [3]; |
| + Iterable<int> l2 = ["hello"]; |
| + Iterable<int> l3 = ["hello", 3]; |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "main"); |
| + DartType literal(int i) { |
| + VariableDeclarationStatement stmt = statements[i]; |
| + VariableDeclaration decl = stmt.variables.variables[0]; |
| + ListLiteral exp = decl.initializer; |
| + return exp.staticType; |
| + } |
| + |
| + Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt); |
| + |
| + assertListOfInt(literal(0)); |
| + assertListOfInt(literal(1)); |
| + assertListOfInt(literal(2)); |
| + assertListOfInt(literal(3)); |
| + } |
| + |
| + void test_mapLiteral_nested() { |
| + String code = r''' |
| + void main () { |
| + Map<int, List<String>> l0 = {}; |
| + Map<int, List<String>> l1 = {3: ["hello"]}; |
| + Map<int, List<String>> l2 = {"hello": ["hello"]}; |
| + Map<int, List<String>> l3 = {3: [3]}; |
| + Map<int, List<String>> l4 = {3:["hello"], "hello": [3]}; |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "main"); |
| + MapLiteral literal(int i) { |
| + VariableDeclarationStatement stmt = statements[i]; |
| + VariableDeclaration decl = stmt.variables.variables[0]; |
| + MapLiteral exp = decl.initializer; |
| + return exp; |
| + } |
| + |
| + Asserter<InterfaceType> assertListOfString = _isListOf(_isString); |
| + Asserter<InterfaceType> assertMapOfIntToListOfString = |
| + _isMapOf(_isInt, assertListOfString); |
| + |
| + assertMapOfIntToListOfString(literal(0).staticType); |
| + assertMapOfIntToListOfString(literal(1).staticType); |
| + assertMapOfIntToListOfString(literal(2).staticType); |
| + assertMapOfIntToListOfString(literal(3).staticType); |
| + assertMapOfIntToListOfString(literal(4).staticType); |
| + |
| + assertListOfString(literal(1).entries[0].value.staticType); |
| + assertListOfString(literal(2).entries[0].value.staticType); |
| + assertListOfString(literal(3).entries[0].value.staticType); |
| + assertListOfString(literal(4).entries[0].value.staticType); |
| + } |
| + |
| + void test_mapLiteral_simple() { |
| + String code = r''' |
| + void main () { |
| + Map<int, String> l0 = {}; |
| + Map<int, String> l1 = {3: "hello"}; |
| + Map<int, String> l2 = {"hello": "hello"}; |
| + Map<int, String> l3 = {3: 3}; |
| + Map<int, String> l4 = {3:"hello", "hello": 3}; |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "main"); |
| + DartType literal(int i) { |
| + VariableDeclarationStatement stmt = statements[i]; |
| + VariableDeclaration decl = stmt.variables.variables[0]; |
| + MapLiteral exp = decl.initializer; |
| + return exp.staticType; |
| + } |
| + |
| + Asserter<InterfaceType> assertMapOfIntToString = |
| + _isMapOf(_isInt, _isString); |
| + |
| + assertMapOfIntToString(literal(0)); |
| + assertMapOfIntToString(literal(1)); |
| + assertMapOfIntToString(literal(2)); |
| + assertMapOfIntToString(literal(3)); |
| + } |
| + |
| + void test_mapLiteral_simple_disabled() { |
| + String code = r''' |
| + void main () { |
| + Map<int, String> l0 = <int, dynamic>{}; |
| + Map<int, String> l1 = <int, dynamic>{3: "hello"}; |
| + Map<int, String> l2 = <int, dynamic>{"hello": "hello"}; |
| + Map<int, String> l3 = <int, dynamic>{3: 3}; |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + List<Statement> statements = |
| + AstFinder.getStatementsInTopLevelFunction(unit, "main"); |
| + DartType literal(int i) { |
| + VariableDeclarationStatement stmt = statements[i]; |
| + VariableDeclaration decl = stmt.variables.variables[0]; |
| + MapLiteral exp = decl.initializer; |
| + return exp.staticType; |
| + } |
| + |
| + Asserter<InterfaceType> assertMapOfIntToDynamic = |
| + _isMapOf(_isInt, _isDynamic); |
| + |
| + assertMapOfIntToDynamic(literal(0)); |
| + assertMapOfIntToDynamic(literal(1)); |
| + assertMapOfIntToDynamic(literal(2)); |
| + assertMapOfIntToDynamic(literal(3)); |
| + } |
| + |
| + void test_methodDeclaration_body_propagation() { |
| + String code = r''' |
| + class A { |
| + List<String> m0(int x) => ["hello"]; |
| + List<String> m1(int x) {return [3];}; |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + Expression methodReturnValue(String methodName) { |
| + MethodDeclaration method = |
| + AstFinder.getMethodInClass(unit, "A", methodName); |
| + FunctionBody body = method.body; |
| + if (body is ExpressionFunctionBody) { |
| + return body.expression; |
| + } else { |
| + Statement stmt = (body as BlockFunctionBody).block.statements[0]; |
| + return (stmt as ReturnStatement).expression; |
| + } |
| + } |
| + Asserter<InterfaceType> assertListOfString = _isListOf(_isString); |
| + assertListOfString(methodReturnValue("m0").staticType); |
| + assertListOfString(methodReturnValue("m1").staticType); |
| + } |
| + |
| + void test_redirectingConstructor_propagation() { |
| + String code = r''' |
| + class A { |
| + A() : this.named([]); |
| + A.named(List<String> x); |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + |
| + ConstructorDeclaration constructor = |
| + AstFinder.getConstructorInClass(unit, "A", null); |
| + RedirectingConstructorInvocation invocation = constructor.initializers[0]; |
| + Expression exp = invocation.argumentList.arguments[0]; |
| + _isListOf(_isString)(exp.staticType); |
| + } |
| + |
| + void test_superConstructorInvocation_propagation() { |
| + String code = r''' |
| + class B { |
| + B(List<String>); |
| + } |
| + class A extends B { |
| + A() : super([]); |
| + } |
| + '''; |
| + CompilationUnit unit = resolveSource(code); |
| + |
| + ConstructorDeclaration constructor = |
| + AstFinder.getConstructorInClass(unit, "A", null); |
| + SuperConstructorInvocation invocation = constructor.initializers[0]; |
| + Expression exp = invocation.argumentList.arguments[0]; |
| + _isListOf(_isString)(exp.staticType); |
| + } |
| +} |
| + |
| +/** |
| * Strong mode static analyzer end to end tests |
| */ |
| @reflectiveTest |