blob: b7d14462fdda6319a3da69c1adf32e94ce43822b [file] [log] [blame]
/*
* Copyright (c) 2013, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.dart.engine.resolver;
import com.google.dart.engine.ast.Block;
import com.google.dart.engine.ast.BlockFunctionBody;
import com.google.dart.engine.ast.ClassDeclaration;
import com.google.dart.engine.ast.CompilationUnit;
import com.google.dart.engine.ast.ConditionalExpression;
import com.google.dart.engine.ast.Expression;
import com.google.dart.engine.ast.ExpressionStatement;
import com.google.dart.engine.ast.FormalParameter;
import com.google.dart.engine.ast.FunctionDeclaration;
import com.google.dart.engine.ast.FunctionExpression;
import com.google.dart.engine.ast.IfStatement;
import com.google.dart.engine.ast.IndexExpression;
import com.google.dart.engine.ast.ListLiteral;
import com.google.dart.engine.ast.MethodInvocation;
import com.google.dart.engine.ast.NodeList;
import com.google.dart.engine.ast.PrefixedIdentifier;
import com.google.dart.engine.ast.ReturnStatement;
import com.google.dart.engine.ast.SimpleFormalParameter;
import com.google.dart.engine.ast.SimpleIdentifier;
import com.google.dart.engine.ast.Statement;
import com.google.dart.engine.ast.VariableDeclarationStatement;
import com.google.dart.engine.ast.WhileStatement;
import com.google.dart.engine.element.LibraryElement;
import com.google.dart.engine.error.StaticWarningCode;
import com.google.dart.engine.source.Source;
import com.google.dart.engine.type.FunctionType;
import com.google.dart.engine.type.InterfaceType;
import com.google.dart.engine.type.Type;
import junit.framework.AssertionFailedError;
public class TypePropagationTest extends ResolverTestCase {
public void fail_mergePropagatedTypesAtJoinPoint_1() throws Exception {
// https://code.google.com/p/dart/issues/detail?id=19929
assertTypeOfMarkedExpression(
createSource(
"f1(x) {",
" var y = [];",
" if (x) {",
" y = 0;",
" } else {",
" y = '';",
" }",
" // Propagated type is [List] here: incorrect.",
" // Best we can do is [Object]?",
" return y; // marker",
"}"),
// Don't care about the static type.
null,
// TODO(collinsn):
// In general, it might be more useful to compute a (structural)
// intersection of interfaces here;
// the best nominal type may be much less precise.
//
// The same concern applies in the other [fail_merge*] tests expecting [dynamic] below.
getTypeProvider().getDynamicType());
}
public void fail_mergePropagatedTypesAtJoinPoint_2() throws Exception {
// https://code.google.com/p/dart/issues/detail?id=19929
assertTypeOfMarkedExpression(
createSource(
"f2(x) {",
" var y = [];",
" if (x) {",
" y = 0;",
" } else {",
" }",
" // Propagated type is [List] here: incorrect.",
" // Best we can do is [Object]?",
" return y; // marker",
"}"),
// Don't care about the static type.
null,
getTypeProvider().getDynamicType());
}
public void fail_mergePropagatedTypesAtJoinPoint_3() throws Exception {
// https://code.google.com/p/dart/issues/detail?id=19929
assertTypeOfMarkedExpression(
createSource(
"f4(x) {",
" var y = [];",
" if (x) {",
" y = 0;",
" } else {",
" y = 1.5;",
" }",
" // Propagated type is [List] here: incorrect.",
" // A correct answer is the least upper bound of [int] and [double],",
" // i.e. [num].",
" return y; // marker",
"}"),
// Don't care about the static type.
null,
getTypeProvider().getNumType());
}
public void fail_mergePropagatedTypesAtJoinPoint_5() throws Exception {
// https://code.google.com/p/dart/issues/detail?id=19929
assertTypeOfMarkedExpression(
createSource(
"f6(x,y) {",
" var z = [];",
" if (x || (z = y) < 0) {",
" } else {",
" z = 0;",
" }",
" // Propagated type is [List] here: incorrect.",
" // Best we can do is [Object]?",
" return z; // marker",
"}"),
// Don't care about the static type.
null,
getTypeProvider().getDynamicType());
}
public void fail_mergePropagatedTypesAtJoinPoint_7() throws Exception {
// https://code.google.com/p/dart/issues/detail?id=19929
//
// In general [continue]s are unsafe for the purposes of [isAbruptTerminationStatement].
//
// This is like example 6, but less tricky: the code in the branch that
// [continue]s is in effect after the [if].
String code = createSource(
"f() {",
" var x = 0;",
" var c = false;",
" var d = true;",
" while (d) {",
" if (c) {",
" d = false;",
" } else {",
" x = '';",
" c = true;",
" continue;",
" }",
" x; // marker",
" }",
"}");
Type t = findMarkedIdentifier(code, "; // marker").getPropagatedType();
assertTrue(getTypeProvider().getIntType().isSubtypeOf(t));
assertTrue(getTypeProvider().getStringType().isSubtypeOf(t));
}
public void fail_mergePropagatedTypesAtJoinPoint_8() throws Exception {
// https://code.google.com/p/dart/issues/detail?id=19929
//
// In nested loops [breaks]s are unsafe for the purposes of [isAbruptTerminationStatement].
//
// This is a combination of 6 and 7: we use an unlabeled [break]
// like a continue for the outer loop / like a labeled [break] to
// jump just above the [if].
String code = createSource(
"f() {",
" var x = 0;",
" var c = false;",
" var d = true;",
" while (d) {",
" while (d) {",
" if (c) {",
" d = false;",
" } else {",
" x = '';",
" c = true;",
" break;",
" }",
" x; // marker",
" }",
" }",
"}");
Type t = findMarkedIdentifier(code, "; // marker").getPropagatedType();
assertTrue(getTypeProvider().getIntType().isSubtypeOf(t));
assertTrue(getTypeProvider().getStringType().isSubtypeOf(t));
}
public void fail_propagatedReturnType_functionExpression() throws Exception {
// TODO(scheglov) disabled because we don't resolve function expression
String code = createSource(//
"main() {",
" var v = (() {return 42;})();",
"}");
assertPropagatedReturnType(
code,
getTypeProvider().getDynamicType(),
getTypeProvider().getIntType());
}
public void test_as() throws Exception {
Source source = addSource(createSource(//
"class A {",
" bool get g => true;",
"}",
"A f(var p) {",
" if ((p as A).g) {",
" return p;",
" } else {",
" return null;",
" }",
"}"));
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
ClassDeclaration classA = (ClassDeclaration) unit.getDeclarations().get(0);
InterfaceType typeA = classA.getElement().getType();
FunctionDeclaration function = (FunctionDeclaration) unit.getDeclarations().get(1);
BlockFunctionBody body = (BlockFunctionBody) function.getFunctionExpression().getBody();
IfStatement ifStatement = (IfStatement) body.getBlock().getStatements().get(0);
ReturnStatement statement = (ReturnStatement) ((Block) ifStatement.getThenStatement()).getStatements().get(
0);
SimpleIdentifier variableName = (SimpleIdentifier) statement.getExpression();
assertSame(typeA, variableName.getPropagatedType());
}
public void test_assert() throws Exception {
Source source = addSource(createSource(//
"class A {}",
"A f(var p) {",
" assert (p is A);",
" return p;",
"}"));
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
ClassDeclaration classA = (ClassDeclaration) unit.getDeclarations().get(0);
InterfaceType typeA = classA.getElement().getType();
FunctionDeclaration function = (FunctionDeclaration) unit.getDeclarations().get(1);
BlockFunctionBody body = (BlockFunctionBody) function.getFunctionExpression().getBody();
ReturnStatement statement = (ReturnStatement) body.getBlock().getStatements().get(1);
SimpleIdentifier variableName = (SimpleIdentifier) statement.getExpression();
assertSame(typeA, variableName.getPropagatedType());
}
public void test_assignment() throws Exception {
Source source = addSource(createSource(//
"f() {",
" var v;",
" v = 0;",
" return v;",
"}"));
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
FunctionDeclaration function = (FunctionDeclaration) unit.getDeclarations().get(0);
BlockFunctionBody body = (BlockFunctionBody) function.getFunctionExpression().getBody();
ReturnStatement statement = (ReturnStatement) body.getBlock().getStatements().get(2);
SimpleIdentifier variableName = (SimpleIdentifier) statement.getExpression();
assertSame(getTypeProvider().getIntType(), variableName.getPropagatedType());
}
public void test_assignment_afterInitializer() throws Exception {
Source source = addSource(createSource(//
"f() {",
" var v = 0;",
" v = 1.0;",
" return v;",
"}"));
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
FunctionDeclaration function = (FunctionDeclaration) unit.getDeclarations().get(0);
BlockFunctionBody body = (BlockFunctionBody) function.getFunctionExpression().getBody();
ReturnStatement statement = (ReturnStatement) body.getBlock().getStatements().get(2);
SimpleIdentifier variableName = (SimpleIdentifier) statement.getExpression();
assertSame(getTypeProvider().getDoubleType(), variableName.getPropagatedType());
}
public void test_assignment_null() throws Exception {
String code = createSource(//
"main() {",
" int v; // declare",
" v = null;",
" return v; // return",
"}");
CompilationUnit unit;
{
Source source = addSource(code);
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
unit = resolveCompilationUnit(source, library);
}
{
SimpleIdentifier identifier = findNode(unit, code, "v; // declare", SimpleIdentifier.class);
assertSame(getTypeProvider().getIntType(), identifier.getStaticType());
assertSame(null, identifier.getPropagatedType());
}
{
SimpleIdentifier identifier = findNode(unit, code, "v = null;", SimpleIdentifier.class);
assertSame(getTypeProvider().getIntType(), identifier.getStaticType());
assertSame(null, identifier.getPropagatedType());
}
{
SimpleIdentifier identifier = findNode(unit, code, "v; // return", SimpleIdentifier.class);
assertSame(getTypeProvider().getIntType(), identifier.getStaticType());
assertSame(null, identifier.getPropagatedType());
}
}
public void test_CanvasElement_getContext() throws Exception {
String code = createSource(//
"import 'dart:html';",
"main(CanvasElement canvas) {",
" var context = canvas.getContext('2d');",
"}");
Source source = addSource(code);
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
SimpleIdentifier identifier = findNode(unit, code, "context", SimpleIdentifier.class);
assertEquals("CanvasRenderingContext2D", identifier.getPropagatedType().getName());
}
public void test_finalPropertyInducingVariable_classMember_instance() throws Exception {
addNamedSource("/lib.dart", createSource(//
"class A {",
" final v = 0;",
"}"));
String code = createSource(//
"import 'lib.dart';",
"f(A a) {",
" return a.v; // marker",
"}");
assertTypeOfMarkedExpression(
code,
getTypeProvider().getDynamicType(),
getTypeProvider().getIntType());
}
public void test_finalPropertyInducingVariable_classMember_instance_inherited() throws Exception {
addNamedSource("/lib.dart", createSource(//
"class A {",
" final v = 0;",
"}"));
String code = createSource(//
"import 'lib.dart';",
"class B extends A {",
" m() {",
" return v; // marker",
" }",
"}");
assertTypeOfMarkedExpression(
code,
getTypeProvider().getDynamicType(),
getTypeProvider().getIntType());
}
public void test_finalPropertyInducingVariable_classMember_instance_propagatedTarget()
throws Exception {
addNamedSource("/lib.dart", createSource(//
"class A {",
" final v = 0;",
"}"));
String code = createSource(//
"import 'lib.dart';",
"f(p) {",
" if (p is A) {",
" return p.v; // marker",
" }",
"}");
assertTypeOfMarkedExpression(
code,
getTypeProvider().getDynamicType(),
getTypeProvider().getIntType());
}
public void test_finalPropertyInducingVariable_classMember_static() throws Exception {
addNamedSource("/lib.dart", createSource(//
"class A {",
" static final V = 0;",
"}"));
String code = createSource(//
"import 'lib.dart';",
"f() {",
" return A.V; // marker",
"}");
assertTypeOfMarkedExpression(
code,
getTypeProvider().getDynamicType(),
getTypeProvider().getIntType());
}
public void test_finalPropertyInducingVariable_topLevelVaraible_prefixed() throws Exception {
addNamedSource("/lib.dart", "final V = 0;");
String code = createSource(//
"import 'lib.dart' as p;",
"f() {",
" var v2 = p.V; // marker prefixed",
"}");
assertTypeOfMarkedExpression(
code,
getTypeProvider().getDynamicType(),
getTypeProvider().getIntType());
}
public void test_finalPropertyInducingVariable_topLevelVaraible_simple() throws Exception {
addNamedSource("/lib.dart", "final V = 0;");
String code = createSource(//
"import 'lib.dart';",
"f() {",
" return V; // marker simple",
"}");
assertTypeOfMarkedExpression(
code,
getTypeProvider().getDynamicType(),
getTypeProvider().getIntType());
}
public void test_forEach() throws Exception {
String code = createSource(//
"main() {",
" var list = <String> [];",
" for (var e in list) {",
" e;",
" }",
"}");
Source source = addSource(code);
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
InterfaceType stringType = getTypeProvider().getStringType();
// in the declaration
{
SimpleIdentifier identifier = findNode(unit, code, "e in", SimpleIdentifier.class);
assertSame(stringType, identifier.getPropagatedType());
}
// in the loop body
{
SimpleIdentifier identifier = findNode(unit, code, "e;", SimpleIdentifier.class);
assertSame(stringType, identifier.getPropagatedType());
}
}
public void test_functionExpression_asInvocationArgument() throws Exception {
String code = createSource(//
"class MyMap<K, V> {",
" forEach(f(K key, V value)) {}",
"}",
"f(MyMap<int, String> m) {",
" m.forEach((k, v) {",
" k;",
" v;",
" });",
"}");
Source source = addSource(code);
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
// k
Type intType = getTypeProvider().getIntType();
FormalParameter kParameter = findNode(unit, code, "k, ", SimpleFormalParameter.class);
assertSame(intType, kParameter.getIdentifier().getPropagatedType());
SimpleIdentifier kIdentifier = findNode(unit, code, "k;", SimpleIdentifier.class);
assertSame(intType, kIdentifier.getPropagatedType());
assertSame(getTypeProvider().getDynamicType(), kIdentifier.getStaticType());
// v
Type stringType = getTypeProvider().getStringType();
FormalParameter vParameter = findNode(unit, code, "v)", SimpleFormalParameter.class);
assertSame(stringType, vParameter.getIdentifier().getPropagatedType());
SimpleIdentifier vIdentifier = findNode(unit, code, "v;", SimpleIdentifier.class);
assertSame(stringType, vIdentifier.getPropagatedType());
assertSame(getTypeProvider().getDynamicType(), vIdentifier.getStaticType());
}
public void test_functionExpression_asInvocationArgument_fromInferredInvocation()
throws Exception {
String code = createSource(//
"class MyMap<K, V> {",
" forEach(f(K key, V value)) {}",
"}",
"f(MyMap<int, String> m) {",
" var m2 = m;",
" m2.forEach((k, v) {});",
"}");
Source source = addSource(code);
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
// k
Type intType = getTypeProvider().getIntType();
FormalParameter kParameter = findNode(unit, code, "k, ", SimpleFormalParameter.class);
assertSame(intType, kParameter.getIdentifier().getPropagatedType());
// v
Type stringType = getTypeProvider().getStringType();
FormalParameter vParameter = findNode(unit, code, "v)", SimpleFormalParameter.class);
assertSame(stringType, vParameter.getIdentifier().getPropagatedType());
}
public void test_functionExpression_asInvocationArgument_functionExpressionInvocation()
throws Exception {
String code = createSource(//
"main() {",
" (f(String value)) {} ((v) {",
" v;",
" });",
"}");
Source source = addSource(code);
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
// v
Type dynamicType = getTypeProvider().getDynamicType();
Type stringType = getTypeProvider().getStringType();
FormalParameter vParameter = findNode(unit, code, "v)", FormalParameter.class);
assertSame(stringType, vParameter.getIdentifier().getPropagatedType());
assertSame(dynamicType, vParameter.getIdentifier().getStaticType());
SimpleIdentifier vIdentifier = findNode(unit, code, "v;", SimpleIdentifier.class);
assertSame(stringType, vIdentifier.getPropagatedType());
assertSame(dynamicType, vIdentifier.getStaticType());
}
public void test_functionExpression_asInvocationArgument_keepIfLessSpecific() throws Exception {
String code = createSource(//
"class MyList {",
" forEach(f(Object value)) {}",
"}",
"f(MyList list) {",
" list.forEach((int v) {",
" v;",
" });",
"}");
Source source = addSource(code);
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
// v
Type intType = getTypeProvider().getIntType();
FormalParameter vParameter = findNode(unit, code, "v)", SimpleFormalParameter.class);
assertSame(null, vParameter.getIdentifier().getPropagatedType());
assertSame(intType, vParameter.getIdentifier().getStaticType());
SimpleIdentifier vIdentifier = findNode(unit, code, "v;", SimpleIdentifier.class);
assertSame(intType, vIdentifier.getStaticType());
assertSame(null, vIdentifier.getPropagatedType());
}
public void test_functionExpression_asInvocationArgument_notSubtypeOfStaticType()
throws Exception {
String code = createSource(//
"class A {",
" m(void f(int i)) {}",
"}",
"x() {",
" A a = new A();",
" a.m(() => 0);",
"}");
Source source = addSource(code);
LibraryElement library = resolve(source);
assertErrors(source, StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
// () => 0
FunctionExpression functionExpression = findNode(
unit,
code,
"() => 0)",
FunctionExpression.class);
assertSame(0, ((FunctionType) functionExpression.getStaticType()).getParameters().length);
assertSame(null, functionExpression.getPropagatedType());
}
public void test_functionExpression_asInvocationArgument_replaceIfMoreSpecific() throws Exception {
String code = createSource(//
"class MyList<E> {",
" forEach(f(E value)) {}",
"}",
"f(MyList<String> list) {",
" list.forEach((Object v) {",
" v;",
" });",
"}");
Source source = addSource(code);
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
// v
Type stringType = getTypeProvider().getStringType();
FormalParameter vParameter = findNode(unit, code, "v)", SimpleFormalParameter.class);
assertSame(stringType, vParameter.getIdentifier().getPropagatedType());
assertSame(getTypeProvider().getObjectType(), vParameter.getIdentifier().getStaticType());
SimpleIdentifier vIdentifier = findNode(unit, code, "v;", SimpleIdentifier.class);
assertSame(stringType, vIdentifier.getPropagatedType());
}
public void test_Future_then() throws Exception {
String code = createSource(//
"import 'dart:async';",
"main(Future<int> firstFuture) {",
" firstFuture.then((p1) {",
" return 1.0;",
" }).then((p2) {",
" return new Future<String>.value('str');",
" }).then((p3) {",
" });",
"}");
Source source = addSource(code);
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
// p1
FormalParameter p1 = findNode(unit, code, "p1) {", SimpleFormalParameter.class);
assertSame(getTypeProvider().getIntType(), p1.getIdentifier().getPropagatedType());
// p2
FormalParameter p2 = findNode(unit, code, "p2) {", SimpleFormalParameter.class);
assertSame(getTypeProvider().getDoubleType(), p2.getIdentifier().getPropagatedType());
// p3
FormalParameter p3 = findNode(unit, code, "p3) {", SimpleFormalParameter.class);
assertSame(getTypeProvider().getStringType(), p3.getIdentifier().getPropagatedType());
}
public void test_initializer() throws Exception {
Source source = addSource(createSource(//
"f() {",
" var v = 0;",
" return v;",
"}"));
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
FunctionDeclaration function = (FunctionDeclaration) unit.getDeclarations().get(0);
BlockFunctionBody body = (BlockFunctionBody) function.getFunctionExpression().getBody();
NodeList<Statement> statements = body.getBlock().getStatements();
// Type of 'v' in declaration.
{
VariableDeclarationStatement statement = (VariableDeclarationStatement) statements.get(0);
SimpleIdentifier variableName = statement.getVariables().getVariables().get(0).getName();
assertSame(getTypeProvider().getDynamicType(), variableName.getStaticType());
assertSame(getTypeProvider().getIntType(), variableName.getPropagatedType());
}
// Type of 'v' in reference.
{
ReturnStatement statement = (ReturnStatement) statements.get(1);
SimpleIdentifier variableName = (SimpleIdentifier) statement.getExpression();
assertSame(getTypeProvider().getIntType(), variableName.getPropagatedType());
}
}
public void test_initializer_dereference() throws Exception {
Source source = addSource(createSource(//
"f() {",
" var v = 'String';",
" v.",
"}"));
LibraryElement library = resolve(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
FunctionDeclaration function = (FunctionDeclaration) unit.getDeclarations().get(0);
BlockFunctionBody body = (BlockFunctionBody) function.getFunctionExpression().getBody();
ExpressionStatement statement = (ExpressionStatement) body.getBlock().getStatements().get(1);
PrefixedIdentifier invocation = (PrefixedIdentifier) statement.getExpression();
SimpleIdentifier variableName = invocation.getPrefix();
assertSame(getTypeProvider().getStringType(), variableName.getPropagatedType());
}
public void test_initializer_null() throws Exception {
String code = createSource(//
"main() {",
" int v = null;",
" return v; // marker",
"}");
CompilationUnit unit;
{
Source source = addSource(code);
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
unit = resolveCompilationUnit(source, library);
}
{
SimpleIdentifier identifier = findNode(unit, code, "v = null;", SimpleIdentifier.class);
assertSame(getTypeProvider().getIntType(), identifier.getStaticType());
assertSame(null, identifier.getPropagatedType());
}
{
SimpleIdentifier identifier = findNode(unit, code, "v; // marker", SimpleIdentifier.class);
assertSame(getTypeProvider().getIntType(), identifier.getStaticType());
assertSame(null, identifier.getPropagatedType());
}
}
public void test_is_conditional() throws Exception {
Source source = addSource(createSource(//
"class A {}",
"A f(var p) {",
" return (p is A) ? p : null;",
"}"));
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
ClassDeclaration classA = (ClassDeclaration) unit.getDeclarations().get(0);
InterfaceType typeA = classA.getElement().getType();
FunctionDeclaration function = (FunctionDeclaration) unit.getDeclarations().get(1);
BlockFunctionBody body = (BlockFunctionBody) function.getFunctionExpression().getBody();
ReturnStatement statement = (ReturnStatement) body.getBlock().getStatements().get(0);
ConditionalExpression conditional = (ConditionalExpression) statement.getExpression();
SimpleIdentifier variableName = (SimpleIdentifier) conditional.getThenExpression();
assertSame(typeA, variableName.getPropagatedType());
}
public void test_is_if() throws Exception {
Source source = addSource(createSource(//
"class A {}",
"A f(var p) {",
" if (p is A) {",
" return p;",
" } else {",
" return null;",
" }",
"}"));
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
ClassDeclaration classA = (ClassDeclaration) unit.getDeclarations().get(0);
InterfaceType typeA = classA.getElement().getType();
FunctionDeclaration function = (FunctionDeclaration) unit.getDeclarations().get(1);
BlockFunctionBody body = (BlockFunctionBody) function.getFunctionExpression().getBody();
IfStatement ifStatement = (IfStatement) body.getBlock().getStatements().get(0);
ReturnStatement statement = (ReturnStatement) ((Block) ifStatement.getThenStatement()).getStatements().get(
0);
SimpleIdentifier variableName = (SimpleIdentifier) statement.getExpression();
assertSame(typeA, variableName.getPropagatedType());
}
public void test_is_if_lessSpecific() throws Exception {
Source source = addSource(createSource(//
"class A {}",
"A f(A p) {",
" if (p is String) {",
" return p;",
" } else {",
" return null;",
" }",
"}"));
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
// ClassDeclaration classA = (ClassDeclaration) unit.getDeclarations().get(0);
// InterfaceType typeA = classA.getElement().getType();
FunctionDeclaration function = (FunctionDeclaration) unit.getDeclarations().get(1);
BlockFunctionBody body = (BlockFunctionBody) function.getFunctionExpression().getBody();
IfStatement ifStatement = (IfStatement) body.getBlock().getStatements().get(0);
ReturnStatement statement = (ReturnStatement) ((Block) ifStatement.getThenStatement()).getStatements().get(
0);
SimpleIdentifier variableName = (SimpleIdentifier) statement.getExpression();
assertSame(null, variableName.getPropagatedType());
}
public void test_is_if_logicalAnd() throws Exception {
Source source = addSource(createSource(//
"class A {}",
"A f(var p) {",
" if (p is A && p != null) {",
" return p;",
" } else {",
" return null;",
" }",
"}"));
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
ClassDeclaration classA = (ClassDeclaration) unit.getDeclarations().get(0);
InterfaceType typeA = classA.getElement().getType();
FunctionDeclaration function = (FunctionDeclaration) unit.getDeclarations().get(1);
BlockFunctionBody body = (BlockFunctionBody) function.getFunctionExpression().getBody();
IfStatement ifStatement = (IfStatement) body.getBlock().getStatements().get(0);
ReturnStatement statement = (ReturnStatement) ((Block) ifStatement.getThenStatement()).getStatements().get(
0);
SimpleIdentifier variableName = (SimpleIdentifier) statement.getExpression();
assertSame(typeA, variableName.getPropagatedType());
}
public void test_is_postConditional() throws Exception {
Source source = addSource(createSource(//
"class A {}",
"A f(var p) {",
" A a = (p is A) ? p : throw null;",
" return p;",
"}"));
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
ClassDeclaration classA = (ClassDeclaration) unit.getDeclarations().get(0);
InterfaceType typeA = classA.getElement().getType();
FunctionDeclaration function = (FunctionDeclaration) unit.getDeclarations().get(1);
BlockFunctionBody body = (BlockFunctionBody) function.getFunctionExpression().getBody();
ReturnStatement statement = (ReturnStatement) body.getBlock().getStatements().get(1);
SimpleIdentifier variableName = (SimpleIdentifier) statement.getExpression();
assertSame(typeA, variableName.getPropagatedType());
}
public void test_is_postIf() throws Exception {
Source source = addSource(createSource(//
"class A {}",
"A f(var p) {",
" if (p is A) {",
" A a = p;",
" } else {",
" return null;",
" }",
" return p;",
"}"));
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
ClassDeclaration classA = (ClassDeclaration) unit.getDeclarations().get(0);
InterfaceType typeA = classA.getElement().getType();
FunctionDeclaration function = (FunctionDeclaration) unit.getDeclarations().get(1);
BlockFunctionBody body = (BlockFunctionBody) function.getFunctionExpression().getBody();
ReturnStatement statement = (ReturnStatement) body.getBlock().getStatements().get(1);
SimpleIdentifier variableName = (SimpleIdentifier) statement.getExpression();
assertSame(typeA, variableName.getPropagatedType());
}
public void test_is_subclass() throws Exception {
Source source = addSource(createSource(//
"class A {}",
"class B extends A {",
" B m() => this;",
"}",
"A f(A p) {",
" if (p is B) {",
" return p.m();",
" }",
" return p;",
"}"));
LibraryElement library = resolve(source);
assertNoErrors(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
FunctionDeclaration function = (FunctionDeclaration) unit.getDeclarations().get(2);
BlockFunctionBody body = (BlockFunctionBody) function.getFunctionExpression().getBody();
IfStatement ifStatement = (IfStatement) body.getBlock().getStatements().get(0);
ReturnStatement statement = (ReturnStatement) ((Block) ifStatement.getThenStatement()).getStatements().get(
0);
MethodInvocation invocation = (MethodInvocation) statement.getExpression();
assertNotNull(invocation.getMethodName().getPropagatedElement());
}
public void test_is_while() throws Exception {
Source source = addSource(createSource(//
"class A {}",
"A f(var p) {",
" while (p is A) {",
" return p;",
" }",
" return p;",
"}"));
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
ClassDeclaration classA = (ClassDeclaration) unit.getDeclarations().get(0);
InterfaceType typeA = classA.getElement().getType();
FunctionDeclaration function = (FunctionDeclaration) unit.getDeclarations().get(1);
BlockFunctionBody body = (BlockFunctionBody) function.getFunctionExpression().getBody();
WhileStatement whileStatement = (WhileStatement) body.getBlock().getStatements().get(0);
ReturnStatement statement = (ReturnStatement) ((Block) whileStatement.getBody()).getStatements().get(
0);
SimpleIdentifier variableName = (SimpleIdentifier) statement.getExpression();
assertSame(typeA, variableName.getPropagatedType());
}
public void test_isNot_conditional() throws Exception {
Source source = addSource(createSource(//
"class A {}",
"A f(var p) {",
" return (p is! A) ? null : p;",
"}"));
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
ClassDeclaration classA = (ClassDeclaration) unit.getDeclarations().get(0);
InterfaceType typeA = classA.getElement().getType();
FunctionDeclaration function = (FunctionDeclaration) unit.getDeclarations().get(1);
BlockFunctionBody body = (BlockFunctionBody) function.getFunctionExpression().getBody();
ReturnStatement statement = (ReturnStatement) body.getBlock().getStatements().get(0);
ConditionalExpression conditional = (ConditionalExpression) statement.getExpression();
SimpleIdentifier variableName = (SimpleIdentifier) conditional.getElseExpression();
assertSame(typeA, variableName.getPropagatedType());
}
public void test_isNot_if() throws Exception {
Source source = addSource(createSource(//
"class A {}",
"A f(var p) {",
" if (p is! A) {",
" return null;",
" } else {",
" return p;",
" }",
"}"));
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
ClassDeclaration classA = (ClassDeclaration) unit.getDeclarations().get(0);
InterfaceType typeA = classA.getElement().getType();
FunctionDeclaration function = (FunctionDeclaration) unit.getDeclarations().get(1);
BlockFunctionBody body = (BlockFunctionBody) function.getFunctionExpression().getBody();
IfStatement ifStatement = (IfStatement) body.getBlock().getStatements().get(0);
ReturnStatement statement = (ReturnStatement) ((Block) ifStatement.getElseStatement()).getStatements().get(
0);
SimpleIdentifier variableName = (SimpleIdentifier) statement.getExpression();
assertSame(typeA, variableName.getPropagatedType());
}
public void test_isNot_if_logicalOr() throws Exception {
Source source = addSource(createSource(//
"class A {}",
"A f(var p) {",
" if (p is! A || null == p) {",
" return null;",
" } else {",
" return p;",
" }",
"}"));
LibraryElement library = resolve(source);
assertNoErrors(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
ClassDeclaration classA = (ClassDeclaration) unit.getDeclarations().get(0);
InterfaceType typeA = classA.getElement().getType();
FunctionDeclaration function = (FunctionDeclaration) unit.getDeclarations().get(1);
BlockFunctionBody body = (BlockFunctionBody) function.getFunctionExpression().getBody();
IfStatement ifStatement = (IfStatement) body.getBlock().getStatements().get(0);
ReturnStatement statement = (ReturnStatement) ((Block) ifStatement.getElseStatement()).getStatements().get(
0);
SimpleIdentifier variableName = (SimpleIdentifier) statement.getExpression();
assertSame(typeA, variableName.getPropagatedType());
}
public void test_isNot_postConditional() throws Exception {
Source source = addSource(createSource(//
"class A {}",
"A f(var p) {",
" A a = (p is! A) ? throw null : p;",
" return p;",
"}"));
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
ClassDeclaration classA = (ClassDeclaration) unit.getDeclarations().get(0);
InterfaceType typeA = classA.getElement().getType();
FunctionDeclaration function = (FunctionDeclaration) unit.getDeclarations().get(1);
BlockFunctionBody body = (BlockFunctionBody) function.getFunctionExpression().getBody();
ReturnStatement statement = (ReturnStatement) body.getBlock().getStatements().get(1);
SimpleIdentifier variableName = (SimpleIdentifier) statement.getExpression();
assertSame(typeA, variableName.getPropagatedType());
}
public void test_isNot_postIf() throws Exception {
Source source = addSource(createSource(//
"class A {}",
"A f(var p) {",
" if (p is! A) {",
" return null;",
" }",
" return p;",
"}"));
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
ClassDeclaration classA = (ClassDeclaration) unit.getDeclarations().get(0);
InterfaceType typeA = classA.getElement().getType();
FunctionDeclaration function = (FunctionDeclaration) unit.getDeclarations().get(1);
BlockFunctionBody body = (BlockFunctionBody) function.getFunctionExpression().getBody();
ReturnStatement statement = (ReturnStatement) body.getBlock().getStatements().get(1);
SimpleIdentifier variableName = (SimpleIdentifier) statement.getExpression();
assertSame(typeA, variableName.getPropagatedType());
}
public void test_issue20904BuggyTypePromotionAtIfJoin_2() throws Exception {
// https://code.google.com/p/dart/issues/detail?id=20904
enableUnionTypes(false);
String code = createSource(//
"f(var message) {",
" if (message is Function) {",
" message = '';",
" }",
" message; // marker", // Here [message] could have any type.
"}");
Type t = findMarkedIdentifier(code, "; // marker").getPropagatedType();
assertFalse(getTypeProvider().getStringType().equals(t));
assertFalse(getTypeProvider().getFunctionType().equals(t));
}
public void test_issue20904BuggyTypePromotionAtIfJoin_5() throws Exception {
// https://code.google.com/p/dart/issues/detail?id=20904
//
// This is not an example of the 20904 bug, but rather,
// an example of something that one obvious fix changes inadvertently: we
// want to avoid using type information from is-checks when it
// loses precision. I can't see how to get a bad hint this way, since
// it seems the propagated type is not used to generate hints when a
// more precise type would cause no hint. For example, for code like the
// following, when the propagated type of [x] is [A] -- as happens for the
// fix these tests aim to warn against -- there is no warning for
// calling a method defined on [B] but not [A] (there aren't any, but pretend),
// but there is for calling a method not defined on either.
// By not overriding the propagated type via an is-check that loses
// precision, we get more precise completion under an is-check. However,
// I can only imagine strange code would make use of this feature.
//
// Here the is-check improves precision, so we use it.
String code = createSource(//
"class A {}",
"class B extends A {}",
"f() {",
" var a = new A();",
" var b = new B();",
" b; // B",
" if (a is B) {",
" return a; // marker",
" }",
"}");
Type tB = findMarkedIdentifier(code, "; // B").getPropagatedType();
assertTypeOfMarkedExpression(code, null, tB);
}
public void test_issue20904BuggyTypePromotionAtIfJoin_6() throws Exception {
// https://code.google.com/p/dart/issues/detail?id=20904
//
// The other half of the *_5() test.
//
// Here the is-check loses precision, so we don't use it.
String code = createSource(//
"class A {}",
"class B extends A {}",
"f() {",
" var b = new B();",
" b; // B",
" if (b is A) {",
" return b; // marker",
" }",
"}");
Type tB = findMarkedIdentifier(code, "; // B").getPropagatedType();
assertTypeOfMarkedExpression(code, null, tB);
}
public void test_listLiteral_different() throws Exception {
Source source = addSource(createSource(//
"f() {",
" var v = [0, '1', 2];",
" return v[2];",
"}"));
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
FunctionDeclaration function = (FunctionDeclaration) unit.getDeclarations().get(0);
BlockFunctionBody body = (BlockFunctionBody) function.getFunctionExpression().getBody();
ReturnStatement statement = (ReturnStatement) body.getBlock().getStatements().get(1);
IndexExpression indexExpression = (IndexExpression) statement.getExpression();
assertNull(indexExpression.getPropagatedType());
}
public void test_listLiteral_same() throws Exception {
Source source = addSource(createSource(//
"f() {",
" var v = [0, 1, 2];",
" return v[2];",
"}"));
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
FunctionDeclaration function = (FunctionDeclaration) unit.getDeclarations().get(0);
BlockFunctionBody body = (BlockFunctionBody) function.getFunctionExpression().getBody();
ReturnStatement statement = (ReturnStatement) body.getBlock().getStatements().get(1);
IndexExpression indexExpression = (IndexExpression) statement.getExpression();
assertNull(indexExpression.getPropagatedType());
Expression v = indexExpression.getTarget();
InterfaceType propagatedType = (InterfaceType) v.getPropagatedType();
assertSame(getTypeProvider().getListType().getElement(), propagatedType.getElement());
Type[] typeArguments = propagatedType.getTypeArguments();
assertLength(1, typeArguments);
assertSame(getTypeProvider().getDynamicType(), typeArguments[0]);
}
public void test_mapLiteral_different() throws Exception {
Source source = addSource(createSource(//
"f() {",
" var v = {'0' : 0, 1 : '1', '2' : 2};",
" return v;",
"}"));
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
FunctionDeclaration function = (FunctionDeclaration) unit.getDeclarations().get(0);
BlockFunctionBody body = (BlockFunctionBody) function.getFunctionExpression().getBody();
ReturnStatement statement = (ReturnStatement) body.getBlock().getStatements().get(1);
SimpleIdentifier identifier = (SimpleIdentifier) statement.getExpression();
InterfaceType propagatedType = (InterfaceType) identifier.getPropagatedType();
assertSame(getTypeProvider().getMapType().getElement(), propagatedType.getElement());
Type[] typeArguments = propagatedType.getTypeArguments();
assertLength(2, typeArguments);
assertSame(getTypeProvider().getDynamicType(), typeArguments[0]);
assertSame(getTypeProvider().getDynamicType(), typeArguments[1]);
}
public void test_mapLiteral_same() throws Exception {
Source source = addSource(createSource(//
"f() {",
" var v = {'a' : 0, 'b' : 1, 'c' : 2};",
" return v;",
"}"));
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
FunctionDeclaration function = (FunctionDeclaration) unit.getDeclarations().get(0);
BlockFunctionBody body = (BlockFunctionBody) function.getFunctionExpression().getBody();
ReturnStatement statement = (ReturnStatement) body.getBlock().getStatements().get(1);
SimpleIdentifier identifier = (SimpleIdentifier) statement.getExpression();
InterfaceType propagatedType = (InterfaceType) identifier.getPropagatedType();
assertSame(getTypeProvider().getMapType().getElement(), propagatedType.getElement());
Type[] typeArguments = propagatedType.getTypeArguments();
assertLength(2, typeArguments);
assertSame(getTypeProvider().getDynamicType(), typeArguments[0]);
assertSame(getTypeProvider().getDynamicType(), typeArguments[1]);
}
public void test_mergePropagatedTypesAtJoinPoint_4() throws Exception {
// https://code.google.com/p/dart/issues/detail?id=19929
assertTypeOfMarkedExpression(
createSource(
"f5(x) {",
" var y = [];",
" if (x) {",
" y = 0;",
" } else {",
" return y;",
" }",
" // Propagated type is [int] here: correct.",
" return y; // marker",
"}"),
// Don't care about the static type.
null,
getTypeProvider().getIntType());
}
public void test_mergePropagatedTypesAtJoinPoint_6() throws Exception {
// https://code.google.com/p/dart/issues/detail?id=19929
//
// Labeled [break]s are unsafe for the purposes of [isAbruptTerminationStatement].
//
// This is tricky: the [break] jumps back above the [if], making
// it into a loop of sorts. The [if] type-propagation code assumes
// that [break] does not introduce a loop.
enableUnionTypes(false);
String code = createSource(
"f() {",
" var x = 0;",
" var c = false;",
" L: ",
" if (c) {",
" } else {",
" x = '';",
" c = true;",
" break L;",
" }",
" x; // marker",
"}");
Type t = findMarkedIdentifier(code, "; // marker").getPropagatedType();
assertTrue(getTypeProvider().getIntType().isSubtypeOf(t));
assertTrue(getTypeProvider().getStringType().isSubtypeOf(t));
}
public void test_objectMethodOnDynamicExpression_doubleEquals() throws Exception {
// https://code.google.com/p/dart/issues/detail?id=20342
//
// This was not actually part of Issue 20342, since the spec specifies a
// static type of [bool] for [==] comparison and the implementation
// was already consistent with the spec there. But, it's another
// [Object] method, so it's included here.
assertTypeOfMarkedExpression(createSource(//
"f1(x) {",
" var v = (x == x);",
" return v; // marker",
"}"), null, getTypeProvider().getBoolType());
}
public void test_objectMethodOnDynamicExpression_hashCode() throws Exception {
// https://code.google.com/p/dart/issues/detail?id=20342
assertTypeOfMarkedExpression(createSource(//
"f1(x) {",
" var v = x.hashCode;",
" return v; // marker",
"}"), null, getTypeProvider().getIntType());
}
public void test_objectMethodOnDynamicExpression_runtimeType() throws Exception {
// https://code.google.com/p/dart/issues/detail?id=20342
assertTypeOfMarkedExpression(createSource(//
"f1(x) {",
" var v = x.runtimeType;",
" return v; // marker",
"}"), null, getTypeProvider().getTypeType());
}
public void test_objectMethodOnDynamicExpression_toString() throws Exception {
// https://code.google.com/p/dart/issues/detail?id=20342
assertTypeOfMarkedExpression(createSource(//
"f1(x) {",
" var v = x.toString();",
" return v; // marker",
"}"), null, getTypeProvider().getStringType());
}
public void test_propagatedReturnType_function_hasReturnType_returnsNull() throws Exception {
String code = createSource(//
"String f() => null;",
"main() {",
" var v = f();",
"}");
assertPropagatedReturnType(
code,
getTypeProvider().getDynamicType(),
getTypeProvider().getStringType());
}
public void test_propagatedReturnType_function_lessSpecificStaticReturnType() throws Exception {
String code = createSource(//
"Object f() => 42;",
"main() {",
" var v = f();",
"}");
assertPropagatedReturnType(
code,
getTypeProvider().getDynamicType(),
getTypeProvider().getIntType());
}
public void test_propagatedReturnType_function_moreSpecificStaticReturnType() throws Exception {
String code = createSource(//
"int f(v) => (v as num);",
"main() {",
" var v = f(3);",
"}");
assertPropagatedReturnType(
code,
getTypeProvider().getDynamicType(),
getTypeProvider().getIntType());
}
public void test_propagatedReturnType_function_noReturnTypeName_blockBody_multipleReturns()
throws Exception {
String code = createSource(//
"f() {",
" if (true) return 0;",
" return 1.0;",
"}",
"main() {",
" var v = f();",
"}");
assertPropagatedReturnType(
code,
getTypeProvider().getDynamicType(),
getTypeProvider().getNumType());
}
public void test_propagatedReturnType_function_noReturnTypeName_blockBody_oneReturn()
throws Exception {
String code = createSource(//
"f() {",
" var z = 42;",
" return z;",
"}",
"main() {",
" var v = f();",
"}");
assertPropagatedReturnType(
code,
getTypeProvider().getDynamicType(),
getTypeProvider().getIntType());
}
public void test_propagatedReturnType_function_noReturnTypeName_expressionBody() throws Exception {
String code = createSource(//
"f() => 42;",
"main() {",
" var v = f();",
"}");
assertPropagatedReturnType(
code,
getTypeProvider().getDynamicType(),
getTypeProvider().getIntType());
}
public void test_propagatedReturnType_localFunction() throws Exception {
String code = createSource(//
"main() {",
" f() => 42;",
" var v = f();",
"}");
assertPropagatedReturnType(
code,
getTypeProvider().getDynamicType(),
getTypeProvider().getIntType());
}
public void test_query() throws Exception {
Source source = addSource(createSource(//
"import 'dart:html';",
"",
"main() {",
" var v1 = query('a');",
" var v2 = query('A');",
" var v3 = query('body:active');",
" var v4 = query('button[foo=\"bar\"]');",
" var v5 = query('div.class');",
" var v6 = query('input#id');",
" var v7 = query('select#id');",
" // invocation of method",
" var m1 = document.query('div');",
" // unsupported currently",
" var b1 = query('noSuchTag');",
" var b2 = query('DART_EDITOR_NO_SUCH_TYPE');",
" var b3 = query('body div');",
" return [v1, v2, v3, v4, v5, v6, v7, m1, b1, b2, b3];",
"}"));
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
FunctionDeclaration main = (FunctionDeclaration) unit.getDeclarations().get(0);
BlockFunctionBody body = (BlockFunctionBody) main.getFunctionExpression().getBody();
ReturnStatement statement = (ReturnStatement) body.getBlock().getStatements().get(11);
NodeList<Expression> elements = ((ListLiteral) statement.getExpression()).getElements();
assertEquals("AnchorElement", elements.get(0).getPropagatedType().getName());
assertEquals("AnchorElement", elements.get(1).getPropagatedType().getName());
assertEquals("BodyElement", elements.get(2).getPropagatedType().getName());
assertEquals("ButtonElement", elements.get(3).getPropagatedType().getName());
assertEquals("DivElement", elements.get(4).getPropagatedType().getName());
assertEquals("InputElement", elements.get(5).getPropagatedType().getName());
assertEquals("SelectElement", elements.get(6).getPropagatedType().getName());
assertEquals("DivElement", elements.get(7).getPropagatedType().getName());
assertEquals("Element", elements.get(8).getPropagatedType().getName());
assertEquals("Element", elements.get(9).getPropagatedType().getName());
assertEquals("Element", elements.get(10).getPropagatedType().getName());
}
/**
* @param code the code that assigns the value to the variable "v", no matter how. We check that
* "v" has expected static and propagated type.
*/
private void assertPropagatedReturnType(String code, Type expectedStaticType,
Type expectedPropagatedType) throws Exception {
SimpleIdentifier identifier = findMarkedIdentifier(code, "v = ");
assertSame(expectedStaticType, identifier.getStaticType());
assertSame(expectedPropagatedType, identifier.getPropagatedType());
}
/**
* Check the static and propagated types of the expression marked with "; // marker" comment.
*
* @param code source code to analyze, with the expression to check marked with "// marker".
* @param expectedStaticType if non-null, check actual static type is equal to this.
* @param expectedPropagatedType if non-null, check actual static type is equal to this.
* @throws Exception
*/
private void assertTypeOfMarkedExpression(String code, Type expectedStaticType,
Type expectedPropagatedType) throws Exception {
SimpleIdentifier identifier = findMarkedIdentifier(code, "; // marker");
if (expectedStaticType != null) {
assertEquals(expectedStaticType, identifier.getStaticType());
}
if (expectedPropagatedType != null) {
assertEquals(expectedPropagatedType, identifier.getPropagatedType());
}
}
/**
* Return the {@code SimpleIdentifier} marked by {@code marker}. The source code must have no
* errors and be verifiable.
*
* @param code source code to analyze.
* @param marker marker identifying sought after expression in source code.
* @return expression marked by the marker.
* @throws Exception
*/
private SimpleIdentifier findMarkedIdentifier(String code, String marker) throws Exception {
try {
Source source = addSource(code);
LibraryElement library = resolve(source);
assertNoErrors(source);
verify(source);
CompilationUnit unit = resolveCompilationUnit(source, library);
// Could generalize this further by making [SimpleIdentifier.class] a parameter.
return findNode(unit, code, marker, SimpleIdentifier.class);
} catch (AssertionFailedError exception) {
// Is there a better exception to throw here? The point is that an assertion failure
// here should be a failure, in both "test_*" and "fail_*" tests.
// However, an assertion failure is success for the purpose of "fail_*" tests, so
// without catching them here "fail_*" tests can succeed by failing for the wrong reason.
throw new Exception("Unexexpected assertion failure: " + exception);
}
}
}