mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 10:18:13 +00:00
Migration: Split up migration_visitor_test.dart.
This will make it easier to re-use the test infrastructure for some other tests I plan to introduce in a follow-up CL. Change-Id: I0a243f00f342674fe38274eb46e7c1e943817785 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/106442 Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
This commit is contained in:
parent
9ac3a733d2
commit
d622fa010b
|
@ -3,25 +3,18 @@
|
|||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:analyzer/dart/ast/ast.dart';
|
||||
import 'package:analyzer/src/generated/resolver.dart';
|
||||
import 'package:analyzer/src/generated/source.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:nnbd_migration/src/conditional_discard.dart';
|
||||
import 'package:nnbd_migration/src/decorated_type.dart';
|
||||
import 'package:nnbd_migration/src/expression_checks.dart';
|
||||
import 'package:nnbd_migration/src/graph_builder.dart';
|
||||
import 'package:nnbd_migration/src/node_builder.dart';
|
||||
import 'package:nnbd_migration/src/nullability_node.dart';
|
||||
import 'package:nnbd_migration/src/variables.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import 'abstract_single_unit.dart';
|
||||
import 'migration_visitor_test_base.dart';
|
||||
|
||||
main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(GraphBuilderTest);
|
||||
defineReflectiveTests(NodeBuilderTest);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -32,8 +25,7 @@ class GraphBuilderTest extends MigrationVisitorTestBase {
|
|||
@override
|
||||
Future<CompilationUnit> analyze(String code) async {
|
||||
var unit = await super.analyze(code);
|
||||
unit.accept(
|
||||
GraphBuilder(typeProvider, _variables, graph, testSource, null));
|
||||
unit.accept(GraphBuilder(typeProvider, variables, graph, testSource, null));
|
||||
return unit;
|
||||
}
|
||||
|
||||
|
@ -69,14 +61,14 @@ class GraphBuilderTest extends MigrationVisitorTestBase {
|
|||
/// representation is [text], or `null` if the expression has no
|
||||
/// [ExpressionChecks] associated with it.
|
||||
ExpressionChecks checkExpression(String text) {
|
||||
return _variables.checkExpression(findNode.expression(text));
|
||||
return variables.checkExpression(findNode.expression(text));
|
||||
}
|
||||
|
||||
/// Gets the [DecoratedType] associated with the expression whose text
|
||||
/// representation is [text], or `null` if the expression has no
|
||||
/// [DecoratedType] associated with it.
|
||||
DecoratedType decoratedExpressionType(String text) {
|
||||
return _variables.decoratedExpressionType(findNode.expression(text));
|
||||
return variables.decoratedExpressionType(findNode.expression(text));
|
||||
}
|
||||
|
||||
test_assert_demonstrates_non_null_intent() async {
|
||||
|
@ -1552,492 +1544,3 @@ void f(int i) {
|
|||
hard: true);
|
||||
}
|
||||
}
|
||||
|
||||
class MigrationVisitorTestBase extends AbstractSingleUnitTest {
|
||||
final _Variables _variables;
|
||||
|
||||
final NullabilityGraphForTesting graph;
|
||||
|
||||
MigrationVisitorTestBase() : this._(NullabilityGraphForTesting());
|
||||
|
||||
MigrationVisitorTestBase._(this.graph) : _variables = _Variables(graph);
|
||||
|
||||
NullabilityNode get always => graph.always;
|
||||
|
||||
NullabilityNode get never => graph.never;
|
||||
|
||||
TypeProvider get typeProvider => testAnalysisResult.typeProvider;
|
||||
|
||||
Future<CompilationUnit> analyze(String code) async {
|
||||
await resolveTestUnit(code);
|
||||
testUnit
|
||||
.accept(NodeBuilder(_variables, testSource, null, graph, typeProvider));
|
||||
return testUnit;
|
||||
}
|
||||
|
||||
NullabilityEdge assertEdge(
|
||||
NullabilityNode source, NullabilityNode destination,
|
||||
{@required bool hard, List<NullabilityNode> guards = const []}) {
|
||||
var edges = getEdges(source, destination);
|
||||
if (edges.length == 0) {
|
||||
fail('Expected edge $source -> $destination, found none');
|
||||
} else if (edges.length != 1) {
|
||||
fail('Found multiple edges $source -> $destination');
|
||||
} else {
|
||||
var edge = edges[0];
|
||||
expect(edge.hard, hard);
|
||||
expect(edge.guards, unorderedEquals(guards));
|
||||
return edge;
|
||||
}
|
||||
}
|
||||
|
||||
void assertNoEdge(NullabilityNode source, NullabilityNode destination) {
|
||||
var edges = getEdges(source, destination);
|
||||
if (edges.isNotEmpty) {
|
||||
fail('Expected no edge $source -> $destination, found ${edges.length}');
|
||||
}
|
||||
}
|
||||
|
||||
void assertUnion(NullabilityNode x, NullabilityNode y) {
|
||||
var edges = getEdges(x, y);
|
||||
for (var edge in edges) {
|
||||
if (edge.isUnion) {
|
||||
expect(edge.sources, hasLength(1));
|
||||
return;
|
||||
}
|
||||
}
|
||||
fail('Expected union between $x and $y, not found');
|
||||
}
|
||||
|
||||
/// Gets the [DecoratedType] associated with the generic function type
|
||||
/// annotation whose text is [text].
|
||||
DecoratedType decoratedGenericFunctionTypeAnnotation(String text) {
|
||||
return _variables.decoratedTypeAnnotation(
|
||||
testSource, findNode.genericFunctionType(text));
|
||||
}
|
||||
|
||||
/// Gets the [DecoratedType] associated with the type annotation whose text
|
||||
/// is [text].
|
||||
DecoratedType decoratedTypeAnnotation(String text) {
|
||||
return _variables.decoratedTypeAnnotation(
|
||||
testSource, findNode.typeAnnotation(text));
|
||||
}
|
||||
|
||||
List<NullabilityEdge> getEdges(
|
||||
NullabilityNode source, NullabilityNode destination) =>
|
||||
graph
|
||||
.getUpstreamEdges(destination)
|
||||
.where((e) => e.primarySource == source)
|
||||
.toList();
|
||||
|
||||
NullabilityNode possiblyOptionalParameter(String text) {
|
||||
return _variables
|
||||
.possiblyOptionalParameter(findNode.defaultParameter(text));
|
||||
}
|
||||
|
||||
/// Gets the [ConditionalDiscard] information associated with the statement
|
||||
/// whose text is [text].
|
||||
ConditionalDiscard statementDiscard(String text) {
|
||||
return _variables.conditionalDiscard(findNode.statement(text));
|
||||
}
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class NodeBuilderTest extends MigrationVisitorTestBase {
|
||||
/// Gets the [DecoratedType] associated with the constructor declaration whose
|
||||
/// name matches [search].
|
||||
DecoratedType decoratedConstructorDeclaration(String search) => _variables
|
||||
.decoratedElementType(findNode.constructor(search).declaredElement);
|
||||
|
||||
/// Gets the [DecoratedType] associated with the function declaration whose
|
||||
/// name matches [search].
|
||||
DecoratedType decoratedFunctionType(String search) =>
|
||||
_variables.decoratedElementType(
|
||||
findNode.functionDeclaration(search).declaredElement);
|
||||
|
||||
DecoratedType decoratedTypeParameterBound(String search) => _variables
|
||||
.decoratedElementType(findNode.typeParameter(search).declaredElement);
|
||||
|
||||
test_constructor_returnType_implicit_dynamic() async {
|
||||
await analyze('''
|
||||
class C {
|
||||
C();
|
||||
}
|
||||
''');
|
||||
var decoratedType = decoratedConstructorDeclaration('C(').returnType;
|
||||
expect(decoratedType.node, same(never));
|
||||
}
|
||||
|
||||
test_dynamic_type() async {
|
||||
await analyze('''
|
||||
dynamic f() {}
|
||||
''');
|
||||
var decoratedType = decoratedTypeAnnotation('dynamic');
|
||||
expect(decoratedFunctionType('f').returnType, same(decoratedType));
|
||||
assertEdge(always, decoratedType.node, hard: false);
|
||||
}
|
||||
|
||||
test_field_type_simple() async {
|
||||
await analyze('''
|
||||
class C {
|
||||
int f = 0;
|
||||
}
|
||||
''');
|
||||
var decoratedType = decoratedTypeAnnotation('int');
|
||||
expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(
|
||||
_variables.decoratedElementType(
|
||||
findNode.fieldDeclaration('f').fields.variables[0].declaredElement),
|
||||
same(decoratedType));
|
||||
}
|
||||
|
||||
test_genericFunctionType_namedParameterType() async {
|
||||
await analyze('''
|
||||
void f(void Function({int y}) x) {}
|
||||
''');
|
||||
var decoratedType =
|
||||
decoratedGenericFunctionTypeAnnotation('void Function({int y})');
|
||||
expect(decoratedFunctionType('f').positionalParameters[0],
|
||||
same(decoratedType));
|
||||
expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
var decoratedIntType = decoratedTypeAnnotation('int');
|
||||
expect(decoratedType.namedParameters['y'], same(decoratedIntType));
|
||||
expect(decoratedIntType.node, isNotNull);
|
||||
expect(decoratedIntType.node, isNot(never));
|
||||
}
|
||||
|
||||
test_genericFunctionType_returnType() async {
|
||||
await analyze('''
|
||||
void f(int Function() x) {}
|
||||
''');
|
||||
var decoratedType =
|
||||
decoratedGenericFunctionTypeAnnotation('int Function()');
|
||||
expect(decoratedFunctionType('f').positionalParameters[0],
|
||||
same(decoratedType));
|
||||
expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
var decoratedIntType = decoratedTypeAnnotation('int');
|
||||
expect(decoratedType.returnType, same(decoratedIntType));
|
||||
expect(decoratedIntType.node, isNotNull);
|
||||
expect(decoratedIntType.node, isNot(never));
|
||||
}
|
||||
|
||||
test_genericFunctionType_unnamedParameterType() async {
|
||||
await analyze('''
|
||||
void f(void Function(int) x) {}
|
||||
''');
|
||||
var decoratedType =
|
||||
decoratedGenericFunctionTypeAnnotation('void Function(int)');
|
||||
expect(decoratedFunctionType('f').positionalParameters[0],
|
||||
same(decoratedType));
|
||||
expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
var decoratedIntType = decoratedTypeAnnotation('int');
|
||||
expect(decoratedType.positionalParameters[0], same(decoratedIntType));
|
||||
expect(decoratedIntType.node, isNotNull);
|
||||
expect(decoratedIntType.node, isNot(never));
|
||||
}
|
||||
|
||||
test_interfaceType_generic_instantiate_to_dynamic() async {
|
||||
await analyze('''
|
||||
void f(List x) {}
|
||||
''');
|
||||
var decoratedListType = decoratedTypeAnnotation('List');
|
||||
expect(decoratedFunctionType('f').positionalParameters[0],
|
||||
same(decoratedListType));
|
||||
expect(decoratedListType.node, isNotNull);
|
||||
expect(decoratedListType.node, isNot(never));
|
||||
var decoratedArgType = decoratedListType.typeArguments[0];
|
||||
expect(decoratedArgType.node, same(always));
|
||||
}
|
||||
|
||||
test_interfaceType_generic_instantiate_to_generic_type() async {
|
||||
await analyze('''
|
||||
class C<T> {}
|
||||
class D<T extends C<int>> {}
|
||||
void f(D x) {}
|
||||
''');
|
||||
var decoratedListType = decoratedTypeAnnotation('D x');
|
||||
expect(decoratedFunctionType('f').positionalParameters[0],
|
||||
same(decoratedListType));
|
||||
expect(decoratedListType.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(decoratedListType.typeArguments, hasLength(1));
|
||||
var decoratedArgType = decoratedListType.typeArguments[0];
|
||||
expect(decoratedArgType.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(decoratedArgType.typeArguments, hasLength(1));
|
||||
var decoratedArgArgType = decoratedArgType.typeArguments[0];
|
||||
expect(decoratedArgArgType.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(decoratedArgArgType.typeArguments, isEmpty);
|
||||
}
|
||||
|
||||
test_interfaceType_generic_instantiate_to_generic_type_2() async {
|
||||
await analyze('''
|
||||
class C<T, U> {}
|
||||
class D<T extends C<int, String>, U extends C<num, double>> {}
|
||||
void f(D x) {}
|
||||
''');
|
||||
var decoratedDType = decoratedTypeAnnotation('D x');
|
||||
expect(decoratedFunctionType('f').positionalParameters[0],
|
||||
same(decoratedDType));
|
||||
expect(decoratedDType.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(decoratedDType.typeArguments, hasLength(2));
|
||||
var decoratedArg0Type = decoratedDType.typeArguments[0];
|
||||
expect(decoratedArg0Type.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(decoratedArg0Type.typeArguments, hasLength(2));
|
||||
var decoratedArg0Arg0Type = decoratedArg0Type.typeArguments[0];
|
||||
expect(decoratedArg0Arg0Type.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(decoratedArg0Arg0Type.typeArguments, isEmpty);
|
||||
var decoratedArg0Arg1Type = decoratedArg0Type.typeArguments[1];
|
||||
expect(decoratedArg0Arg1Type.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(decoratedArg0Arg1Type.typeArguments, isEmpty);
|
||||
var decoratedArg1Type = decoratedDType.typeArguments[1];
|
||||
expect(decoratedArg1Type.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(decoratedArg1Type.typeArguments, hasLength(2));
|
||||
var decoratedArg1Arg0Type = decoratedArg1Type.typeArguments[0];
|
||||
expect(decoratedArg1Arg0Type.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(decoratedArg1Arg0Type.typeArguments, isEmpty);
|
||||
var decoratedArg1Arg1Type = decoratedArg1Type.typeArguments[1];
|
||||
expect(decoratedArg1Arg1Type.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(decoratedArg1Arg1Type.typeArguments, isEmpty);
|
||||
}
|
||||
|
||||
test_interfaceType_generic_instantiate_to_object() async {
|
||||
await analyze('''
|
||||
class C<T extends Object> {}
|
||||
void f(C x) {}
|
||||
''');
|
||||
var decoratedListType = decoratedTypeAnnotation('C x');
|
||||
expect(decoratedFunctionType('f').positionalParameters[0],
|
||||
same(decoratedListType));
|
||||
expect(decoratedListType.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(decoratedListType.typeArguments, hasLength(1));
|
||||
var decoratedArgType = decoratedListType.typeArguments[0];
|
||||
expect(decoratedArgType.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(decoratedArgType.typeArguments, isEmpty);
|
||||
}
|
||||
|
||||
test_interfaceType_typeParameter() async {
|
||||
await analyze('''
|
||||
void f(List<int> x) {}
|
||||
''');
|
||||
var decoratedListType = decoratedTypeAnnotation('List<int>');
|
||||
expect(decoratedFunctionType('f').positionalParameters[0],
|
||||
same(decoratedListType));
|
||||
expect(decoratedListType.node, isNotNull);
|
||||
expect(decoratedListType.node, isNot(never));
|
||||
var decoratedIntType = decoratedTypeAnnotation('int');
|
||||
expect(decoratedListType.typeArguments[0], same(decoratedIntType));
|
||||
expect(decoratedIntType.node, isNotNull);
|
||||
expect(decoratedIntType.node, isNot(never));
|
||||
}
|
||||
|
||||
test_topLevelFunction_parameterType_implicit_dynamic() async {
|
||||
await analyze('''
|
||||
void f(x) {}
|
||||
''');
|
||||
var decoratedType =
|
||||
_variables.decoratedElementType(findNode.simple('x').staticElement);
|
||||
expect(decoratedFunctionType('f').positionalParameters[0],
|
||||
same(decoratedType));
|
||||
expect(decoratedType.type.isDynamic, isTrue);
|
||||
assertUnion(always, decoratedType.node);
|
||||
}
|
||||
|
||||
test_topLevelFunction_parameterType_named_no_default() async {
|
||||
await analyze('''
|
||||
void f({String s}) {}
|
||||
''');
|
||||
var decoratedType = decoratedTypeAnnotation('String');
|
||||
var functionType = decoratedFunctionType('f');
|
||||
expect(functionType.namedParameters['s'], same(decoratedType));
|
||||
expect(decoratedType.node, isNotNull);
|
||||
expect(decoratedType.node, isNot(never));
|
||||
expect(decoratedType.node, isNot(always));
|
||||
expect(functionType.namedParameters['s'].node.isPossiblyOptional, true);
|
||||
}
|
||||
|
||||
test_topLevelFunction_parameterType_named_no_default_required() async {
|
||||
addMetaPackage();
|
||||
await analyze('''
|
||||
import 'package:meta/meta.dart';
|
||||
void f({@required String s}) {}
|
||||
''');
|
||||
var decoratedType = decoratedTypeAnnotation('String');
|
||||
var functionType = decoratedFunctionType('f');
|
||||
expect(functionType.namedParameters['s'], same(decoratedType));
|
||||
expect(decoratedType.node, isNotNull);
|
||||
expect(decoratedType.node, isNot(never));
|
||||
expect(decoratedType.node, isNot(always));
|
||||
expect(functionType.namedParameters['s'].node.isPossiblyOptional, false);
|
||||
}
|
||||
|
||||
test_topLevelFunction_parameterType_named_with_default() async {
|
||||
await analyze('''
|
||||
void f({String s: 'x'}) {}
|
||||
''');
|
||||
var decoratedType = decoratedTypeAnnotation('String');
|
||||
var functionType = decoratedFunctionType('f');
|
||||
expect(functionType.namedParameters['s'], same(decoratedType));
|
||||
expect(decoratedType.node, isNotNull);
|
||||
expect(decoratedType.node, isNot(never));
|
||||
expect(functionType.namedParameters['s'].node.isPossiblyOptional, false);
|
||||
}
|
||||
|
||||
test_topLevelFunction_parameterType_positionalOptional() async {
|
||||
await analyze('''
|
||||
void f([int i]) {}
|
||||
''');
|
||||
var decoratedType = decoratedTypeAnnotation('int');
|
||||
expect(decoratedFunctionType('f').positionalParameters[0],
|
||||
same(decoratedType));
|
||||
expect(decoratedType.node, isNotNull);
|
||||
expect(decoratedType.node, isNot(never));
|
||||
}
|
||||
|
||||
test_topLevelFunction_parameterType_simple() async {
|
||||
await analyze('''
|
||||
void f(int i) {}
|
||||
''');
|
||||
var decoratedType = decoratedTypeAnnotation('int');
|
||||
expect(decoratedFunctionType('f').positionalParameters[0],
|
||||
same(decoratedType));
|
||||
expect(decoratedType.node, isNotNull);
|
||||
expect(decoratedType.node, isNot(never));
|
||||
}
|
||||
|
||||
test_topLevelFunction_returnType_implicit_dynamic() async {
|
||||
await analyze('''
|
||||
f() {}
|
||||
''');
|
||||
var decoratedType = decoratedFunctionType('f').returnType;
|
||||
expect(decoratedType.type.isDynamic, isTrue);
|
||||
assertUnion(always, decoratedType.node);
|
||||
}
|
||||
|
||||
test_topLevelFunction_returnType_simple() async {
|
||||
await analyze('''
|
||||
int f() => 0;
|
||||
''');
|
||||
var decoratedType = decoratedTypeAnnotation('int');
|
||||
expect(decoratedFunctionType('f').returnType, same(decoratedType));
|
||||
expect(decoratedType.node, isNotNull);
|
||||
expect(decoratedType.node, isNot(never));
|
||||
}
|
||||
|
||||
test_type_comment_bang() async {
|
||||
await analyze('''
|
||||
void f(int/*!*/ i) {}
|
||||
''');
|
||||
assertEdge(decoratedTypeAnnotation('int').node, never, hard: true);
|
||||
}
|
||||
|
||||
test_type_comment_question() async {
|
||||
await analyze('''
|
||||
void f(int/*?*/ i) {}
|
||||
''');
|
||||
assertEdge(always, decoratedTypeAnnotation('int').node, hard: false);
|
||||
}
|
||||
|
||||
test_type_parameter_explicit_bound() async {
|
||||
await analyze('''
|
||||
class C<T extends Object> {}
|
||||
''');
|
||||
var bound = decoratedTypeParameterBound('T');
|
||||
expect(decoratedTypeAnnotation('Object'), same(bound));
|
||||
expect(bound.node, isNot(always));
|
||||
expect(bound.type, typeProvider.objectType);
|
||||
}
|
||||
|
||||
test_type_parameter_implicit_bound() async {
|
||||
// The implicit bound of `T` is automatically `Object?`. TODO(paulberry):
|
||||
// consider making it possible for type inference to infer an explicit bound
|
||||
// of `Object`.
|
||||
await analyze('''
|
||||
class C<T> {}
|
||||
''');
|
||||
var bound = decoratedTypeParameterBound('T');
|
||||
assertUnion(always, bound.node);
|
||||
expect(bound.type, same(typeProvider.objectType));
|
||||
}
|
||||
|
||||
test_variableDeclaration_type_simple() async {
|
||||
await analyze('''
|
||||
main() {
|
||||
int i;
|
||||
}
|
||||
''');
|
||||
var decoratedType = decoratedTypeAnnotation('int');
|
||||
expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
}
|
||||
|
||||
test_void_type() async {
|
||||
await analyze('''
|
||||
void f() {}
|
||||
''');
|
||||
var decoratedType = decoratedTypeAnnotation('void');
|
||||
expect(decoratedFunctionType('f').returnType, same(decoratedType));
|
||||
assertEdge(always, decoratedType.node, hard: false);
|
||||
}
|
||||
}
|
||||
|
||||
/// Mock representation of constraint variables.
|
||||
class _Variables extends Variables {
|
||||
final _conditionalDiscard = <AstNode, ConditionalDiscard>{};
|
||||
|
||||
final _decoratedExpressionTypes = <Expression, DecoratedType>{};
|
||||
|
||||
final _expressionChecks = <Expression, ExpressionChecks>{};
|
||||
|
||||
final _possiblyOptional = <DefaultFormalParameter, NullabilityNode>{};
|
||||
|
||||
_Variables(NullabilityGraph graph) : super(graph);
|
||||
|
||||
/// Gets the [ExpressionChecks] associated with the given [expression].
|
||||
ExpressionChecks checkExpression(Expression expression) =>
|
||||
_expressionChecks[_normalizeExpression(expression)];
|
||||
|
||||
/// Gets the [conditionalDiscard] associated with the given [expression].
|
||||
ConditionalDiscard conditionalDiscard(AstNode node) =>
|
||||
_conditionalDiscard[node];
|
||||
|
||||
/// Gets the [DecoratedType] associated with the given [expression].
|
||||
DecoratedType decoratedExpressionType(Expression expression) =>
|
||||
_decoratedExpressionTypes[_normalizeExpression(expression)];
|
||||
|
||||
/// Gets the [NullabilityNode] associated with the possibility that
|
||||
/// [parameter] may be optional.
|
||||
NullabilityNode possiblyOptionalParameter(DefaultFormalParameter parameter) =>
|
||||
_possiblyOptional[parameter];
|
||||
|
||||
@override
|
||||
void recordConditionalDiscard(
|
||||
Source source, AstNode node, ConditionalDiscard conditionalDiscard) {
|
||||
_conditionalDiscard[node] = conditionalDiscard;
|
||||
super.recordConditionalDiscard(source, node, conditionalDiscard);
|
||||
}
|
||||
|
||||
void recordDecoratedExpressionType(Expression node, DecoratedType type) {
|
||||
super.recordDecoratedExpressionType(node, type);
|
||||
_decoratedExpressionTypes[_normalizeExpression(node)] = type;
|
||||
}
|
||||
|
||||
@override
|
||||
void recordExpressionChecks(
|
||||
Source source, Expression expression, ExpressionChecks checks) {
|
||||
super.recordExpressionChecks(source, expression, checks);
|
||||
_expressionChecks[_normalizeExpression(expression)] = checks;
|
||||
}
|
||||
|
||||
@override
|
||||
void recordPossiblyOptional(
|
||||
Source source, DefaultFormalParameter parameter, NullabilityNode node) {
|
||||
_possiblyOptional[parameter] = node;
|
||||
super.recordPossiblyOptional(source, parameter, node);
|
||||
}
|
||||
|
||||
/// Unwraps any parentheses surrounding [expression].
|
||||
Expression _normalizeExpression(Expression expression) {
|
||||
while (expression is ParenthesizedExpression) {
|
||||
expression = (expression as ParenthesizedExpression).expression;
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
}
|
170
pkg/nnbd_migration/test/migration_visitor_test_base.dart
Normal file
170
pkg/nnbd_migration/test/migration_visitor_test_base.dart
Normal file
|
@ -0,0 +1,170 @@
|
|||
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:analyzer/dart/ast/ast.dart';
|
||||
import 'package:analyzer/src/generated/resolver.dart';
|
||||
import 'package:analyzer/src/generated/source.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:nnbd_migration/src/conditional_discard.dart';
|
||||
import 'package:nnbd_migration/src/decorated_type.dart';
|
||||
import 'package:nnbd_migration/src/expression_checks.dart';
|
||||
import 'package:nnbd_migration/src/node_builder.dart';
|
||||
import 'package:nnbd_migration/src/nullability_node.dart';
|
||||
import 'package:nnbd_migration/src/variables.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'abstract_single_unit.dart';
|
||||
|
||||
/// Mock representation of constraint variables.
|
||||
class InstrumentedVariables extends Variables {
|
||||
final _conditionalDiscard = <AstNode, ConditionalDiscard>{};
|
||||
|
||||
final _decoratedExpressionTypes = <Expression, DecoratedType>{};
|
||||
|
||||
final _expressionChecks = <Expression, ExpressionChecks>{};
|
||||
|
||||
final _possiblyOptional = <DefaultFormalParameter, NullabilityNode>{};
|
||||
|
||||
InstrumentedVariables(NullabilityGraph graph) : super(graph);
|
||||
|
||||
/// Gets the [ExpressionChecks] associated with the given [expression].
|
||||
ExpressionChecks checkExpression(Expression expression) =>
|
||||
_expressionChecks[_normalizeExpression(expression)];
|
||||
|
||||
/// Gets the [conditionalDiscard] associated with the given [expression].
|
||||
ConditionalDiscard conditionalDiscard(AstNode node) =>
|
||||
_conditionalDiscard[node];
|
||||
|
||||
/// Gets the [DecoratedType] associated with the given [expression].
|
||||
DecoratedType decoratedExpressionType(Expression expression) =>
|
||||
_decoratedExpressionTypes[_normalizeExpression(expression)];
|
||||
|
||||
/// Gets the [NullabilityNode] associated with the possibility that
|
||||
/// [parameter] may be optional.
|
||||
NullabilityNode possiblyOptionalParameter(DefaultFormalParameter parameter) =>
|
||||
_possiblyOptional[parameter];
|
||||
|
||||
@override
|
||||
void recordConditionalDiscard(
|
||||
Source source, AstNode node, ConditionalDiscard conditionalDiscard) {
|
||||
_conditionalDiscard[node] = conditionalDiscard;
|
||||
super.recordConditionalDiscard(source, node, conditionalDiscard);
|
||||
}
|
||||
|
||||
void recordDecoratedExpressionType(Expression node, DecoratedType type) {
|
||||
super.recordDecoratedExpressionType(node, type);
|
||||
_decoratedExpressionTypes[_normalizeExpression(node)] = type;
|
||||
}
|
||||
|
||||
@override
|
||||
void recordExpressionChecks(
|
||||
Source source, Expression expression, ExpressionChecks checks) {
|
||||
super.recordExpressionChecks(source, expression, checks);
|
||||
_expressionChecks[_normalizeExpression(expression)] = checks;
|
||||
}
|
||||
|
||||
@override
|
||||
void recordPossiblyOptional(
|
||||
Source source, DefaultFormalParameter parameter, NullabilityNode node) {
|
||||
_possiblyOptional[parameter] = node;
|
||||
super.recordPossiblyOptional(source, parameter, node);
|
||||
}
|
||||
|
||||
/// Unwraps any parentheses surrounding [expression].
|
||||
Expression _normalizeExpression(Expression expression) {
|
||||
while (expression is ParenthesizedExpression) {
|
||||
expression = (expression as ParenthesizedExpression).expression;
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
|
||||
class MigrationVisitorTestBase extends AbstractSingleUnitTest {
|
||||
final InstrumentedVariables variables;
|
||||
|
||||
final NullabilityGraphForTesting graph;
|
||||
|
||||
MigrationVisitorTestBase() : this._(NullabilityGraphForTesting());
|
||||
|
||||
MigrationVisitorTestBase._(this.graph)
|
||||
: variables = InstrumentedVariables(graph);
|
||||
|
||||
NullabilityNode get always => graph.always;
|
||||
|
||||
NullabilityNode get never => graph.never;
|
||||
|
||||
TypeProvider get typeProvider => testAnalysisResult.typeProvider;
|
||||
|
||||
Future<CompilationUnit> analyze(String code) async {
|
||||
await resolveTestUnit(code);
|
||||
testUnit
|
||||
.accept(NodeBuilder(variables, testSource, null, graph, typeProvider));
|
||||
return testUnit;
|
||||
}
|
||||
|
||||
NullabilityEdge assertEdge(
|
||||
NullabilityNode source, NullabilityNode destination,
|
||||
{@required bool hard, List<NullabilityNode> guards = const []}) {
|
||||
var edges = getEdges(source, destination);
|
||||
if (edges.length == 0) {
|
||||
fail('Expected edge $source -> $destination, found none');
|
||||
} else if (edges.length != 1) {
|
||||
fail('Found multiple edges $source -> $destination');
|
||||
} else {
|
||||
var edge = edges[0];
|
||||
expect(edge.hard, hard);
|
||||
expect(edge.guards, unorderedEquals(guards));
|
||||
return edge;
|
||||
}
|
||||
}
|
||||
|
||||
void assertNoEdge(NullabilityNode source, NullabilityNode destination) {
|
||||
var edges = getEdges(source, destination);
|
||||
if (edges.isNotEmpty) {
|
||||
fail('Expected no edge $source -> $destination, found ${edges.length}');
|
||||
}
|
||||
}
|
||||
|
||||
void assertUnion(NullabilityNode x, NullabilityNode y) {
|
||||
var edges = getEdges(x, y);
|
||||
for (var edge in edges) {
|
||||
if (edge.isUnion) {
|
||||
expect(edge.sources, hasLength(1));
|
||||
return;
|
||||
}
|
||||
}
|
||||
fail('Expected union between $x and $y, not found');
|
||||
}
|
||||
|
||||
/// Gets the [DecoratedType] associated with the generic function type
|
||||
/// annotation whose text is [text].
|
||||
DecoratedType decoratedGenericFunctionTypeAnnotation(String text) {
|
||||
return variables.decoratedTypeAnnotation(
|
||||
testSource, findNode.genericFunctionType(text));
|
||||
}
|
||||
|
||||
/// Gets the [DecoratedType] associated with the type annotation whose text
|
||||
/// is [text].
|
||||
DecoratedType decoratedTypeAnnotation(String text) {
|
||||
return variables.decoratedTypeAnnotation(
|
||||
testSource, findNode.typeAnnotation(text));
|
||||
}
|
||||
|
||||
List<NullabilityEdge> getEdges(
|
||||
NullabilityNode source, NullabilityNode destination) =>
|
||||
graph
|
||||
.getUpstreamEdges(destination)
|
||||
.where((e) => e.primarySource == source)
|
||||
.toList();
|
||||
|
||||
NullabilityNode possiblyOptionalParameter(String text) {
|
||||
return variables.possiblyOptionalParameter(findNode.defaultParameter(text));
|
||||
}
|
||||
|
||||
/// Gets the [ConditionalDiscard] information associated with the statement
|
||||
/// whose text is [text].
|
||||
ConditionalDiscard statementDiscard(String text) {
|
||||
return variables.conditionalDiscard(findNode.statement(text));
|
||||
}
|
||||
}
|
352
pkg/nnbd_migration/test/node_builder_test.dart
Normal file
352
pkg/nnbd_migration/test/node_builder_test.dart
Normal file
|
@ -0,0 +1,352 @@
|
|||
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:nnbd_migration/src/decorated_type.dart';
|
||||
import 'package:nnbd_migration/src/nullability_node.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import 'migration_visitor_test_base.dart';
|
||||
|
||||
main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(NodeBuilderTest);
|
||||
});
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class NodeBuilderTest extends MigrationVisitorTestBase {
|
||||
/// Gets the [DecoratedType] associated with the constructor declaration whose
|
||||
/// name matches [search].
|
||||
DecoratedType decoratedConstructorDeclaration(String search) => variables
|
||||
.decoratedElementType(findNode.constructor(search).declaredElement);
|
||||
|
||||
/// Gets the [DecoratedType] associated with the function declaration whose
|
||||
/// name matches [search].
|
||||
DecoratedType decoratedFunctionType(String search) =>
|
||||
variables.decoratedElementType(
|
||||
findNode.functionDeclaration(search).declaredElement);
|
||||
|
||||
DecoratedType decoratedTypeParameterBound(String search) => variables
|
||||
.decoratedElementType(findNode.typeParameter(search).declaredElement);
|
||||
|
||||
test_constructor_returnType_implicit_dynamic() async {
|
||||
await analyze('''
|
||||
class C {
|
||||
C();
|
||||
}
|
||||
''');
|
||||
var decoratedType = decoratedConstructorDeclaration('C(').returnType;
|
||||
expect(decoratedType.node, same(never));
|
||||
}
|
||||
|
||||
test_dynamic_type() async {
|
||||
await analyze('''
|
||||
dynamic f() {}
|
||||
''');
|
||||
var decoratedType = decoratedTypeAnnotation('dynamic');
|
||||
expect(decoratedFunctionType('f').returnType, same(decoratedType));
|
||||
assertEdge(always, decoratedType.node, hard: false);
|
||||
}
|
||||
|
||||
test_field_type_simple() async {
|
||||
await analyze('''
|
||||
class C {
|
||||
int f = 0;
|
||||
}
|
||||
''');
|
||||
var decoratedType = decoratedTypeAnnotation('int');
|
||||
expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(
|
||||
variables.decoratedElementType(
|
||||
findNode.fieldDeclaration('f').fields.variables[0].declaredElement),
|
||||
same(decoratedType));
|
||||
}
|
||||
|
||||
test_genericFunctionType_namedParameterType() async {
|
||||
await analyze('''
|
||||
void f(void Function({int y}) x) {}
|
||||
''');
|
||||
var decoratedType =
|
||||
decoratedGenericFunctionTypeAnnotation('void Function({int y})');
|
||||
expect(decoratedFunctionType('f').positionalParameters[0],
|
||||
same(decoratedType));
|
||||
expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
var decoratedIntType = decoratedTypeAnnotation('int');
|
||||
expect(decoratedType.namedParameters['y'], same(decoratedIntType));
|
||||
expect(decoratedIntType.node, isNotNull);
|
||||
expect(decoratedIntType.node, isNot(never));
|
||||
}
|
||||
|
||||
test_genericFunctionType_returnType() async {
|
||||
await analyze('''
|
||||
void f(int Function() x) {}
|
||||
''');
|
||||
var decoratedType =
|
||||
decoratedGenericFunctionTypeAnnotation('int Function()');
|
||||
expect(decoratedFunctionType('f').positionalParameters[0],
|
||||
same(decoratedType));
|
||||
expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
var decoratedIntType = decoratedTypeAnnotation('int');
|
||||
expect(decoratedType.returnType, same(decoratedIntType));
|
||||
expect(decoratedIntType.node, isNotNull);
|
||||
expect(decoratedIntType.node, isNot(never));
|
||||
}
|
||||
|
||||
test_genericFunctionType_unnamedParameterType() async {
|
||||
await analyze('''
|
||||
void f(void Function(int) x) {}
|
||||
''');
|
||||
var decoratedType =
|
||||
decoratedGenericFunctionTypeAnnotation('void Function(int)');
|
||||
expect(decoratedFunctionType('f').positionalParameters[0],
|
||||
same(decoratedType));
|
||||
expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
var decoratedIntType = decoratedTypeAnnotation('int');
|
||||
expect(decoratedType.positionalParameters[0], same(decoratedIntType));
|
||||
expect(decoratedIntType.node, isNotNull);
|
||||
expect(decoratedIntType.node, isNot(never));
|
||||
}
|
||||
|
||||
test_interfaceType_generic_instantiate_to_dynamic() async {
|
||||
await analyze('''
|
||||
void f(List x) {}
|
||||
''');
|
||||
var decoratedListType = decoratedTypeAnnotation('List');
|
||||
expect(decoratedFunctionType('f').positionalParameters[0],
|
||||
same(decoratedListType));
|
||||
expect(decoratedListType.node, isNotNull);
|
||||
expect(decoratedListType.node, isNot(never));
|
||||
var decoratedArgType = decoratedListType.typeArguments[0];
|
||||
expect(decoratedArgType.node, same(always));
|
||||
}
|
||||
|
||||
test_interfaceType_generic_instantiate_to_generic_type() async {
|
||||
await analyze('''
|
||||
class C<T> {}
|
||||
class D<T extends C<int>> {}
|
||||
void f(D x) {}
|
||||
''');
|
||||
var decoratedListType = decoratedTypeAnnotation('D x');
|
||||
expect(decoratedFunctionType('f').positionalParameters[0],
|
||||
same(decoratedListType));
|
||||
expect(decoratedListType.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(decoratedListType.typeArguments, hasLength(1));
|
||||
var decoratedArgType = decoratedListType.typeArguments[0];
|
||||
expect(decoratedArgType.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(decoratedArgType.typeArguments, hasLength(1));
|
||||
var decoratedArgArgType = decoratedArgType.typeArguments[0];
|
||||
expect(decoratedArgArgType.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(decoratedArgArgType.typeArguments, isEmpty);
|
||||
}
|
||||
|
||||
test_interfaceType_generic_instantiate_to_generic_type_2() async {
|
||||
await analyze('''
|
||||
class C<T, U> {}
|
||||
class D<T extends C<int, String>, U extends C<num, double>> {}
|
||||
void f(D x) {}
|
||||
''');
|
||||
var decoratedDType = decoratedTypeAnnotation('D x');
|
||||
expect(decoratedFunctionType('f').positionalParameters[0],
|
||||
same(decoratedDType));
|
||||
expect(decoratedDType.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(decoratedDType.typeArguments, hasLength(2));
|
||||
var decoratedArg0Type = decoratedDType.typeArguments[0];
|
||||
expect(decoratedArg0Type.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(decoratedArg0Type.typeArguments, hasLength(2));
|
||||
var decoratedArg0Arg0Type = decoratedArg0Type.typeArguments[0];
|
||||
expect(decoratedArg0Arg0Type.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(decoratedArg0Arg0Type.typeArguments, isEmpty);
|
||||
var decoratedArg0Arg1Type = decoratedArg0Type.typeArguments[1];
|
||||
expect(decoratedArg0Arg1Type.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(decoratedArg0Arg1Type.typeArguments, isEmpty);
|
||||
var decoratedArg1Type = decoratedDType.typeArguments[1];
|
||||
expect(decoratedArg1Type.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(decoratedArg1Type.typeArguments, hasLength(2));
|
||||
var decoratedArg1Arg0Type = decoratedArg1Type.typeArguments[0];
|
||||
expect(decoratedArg1Arg0Type.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(decoratedArg1Arg0Type.typeArguments, isEmpty);
|
||||
var decoratedArg1Arg1Type = decoratedArg1Type.typeArguments[1];
|
||||
expect(decoratedArg1Arg1Type.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(decoratedArg1Arg1Type.typeArguments, isEmpty);
|
||||
}
|
||||
|
||||
test_interfaceType_generic_instantiate_to_object() async {
|
||||
await analyze('''
|
||||
class C<T extends Object> {}
|
||||
void f(C x) {}
|
||||
''');
|
||||
var decoratedListType = decoratedTypeAnnotation('C x');
|
||||
expect(decoratedFunctionType('f').positionalParameters[0],
|
||||
same(decoratedListType));
|
||||
expect(decoratedListType.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(decoratedListType.typeArguments, hasLength(1));
|
||||
var decoratedArgType = decoratedListType.typeArguments[0];
|
||||
expect(decoratedArgType.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
expect(decoratedArgType.typeArguments, isEmpty);
|
||||
}
|
||||
|
||||
test_interfaceType_typeParameter() async {
|
||||
await analyze('''
|
||||
void f(List<int> x) {}
|
||||
''');
|
||||
var decoratedListType = decoratedTypeAnnotation('List<int>');
|
||||
expect(decoratedFunctionType('f').positionalParameters[0],
|
||||
same(decoratedListType));
|
||||
expect(decoratedListType.node, isNotNull);
|
||||
expect(decoratedListType.node, isNot(never));
|
||||
var decoratedIntType = decoratedTypeAnnotation('int');
|
||||
expect(decoratedListType.typeArguments[0], same(decoratedIntType));
|
||||
expect(decoratedIntType.node, isNotNull);
|
||||
expect(decoratedIntType.node, isNot(never));
|
||||
}
|
||||
|
||||
test_topLevelFunction_parameterType_implicit_dynamic() async {
|
||||
await analyze('''
|
||||
void f(x) {}
|
||||
''');
|
||||
var decoratedType =
|
||||
variables.decoratedElementType(findNode.simple('x').staticElement);
|
||||
expect(decoratedFunctionType('f').positionalParameters[0],
|
||||
same(decoratedType));
|
||||
expect(decoratedType.type.isDynamic, isTrue);
|
||||
assertUnion(always, decoratedType.node);
|
||||
}
|
||||
|
||||
test_topLevelFunction_parameterType_named_no_default() async {
|
||||
await analyze('''
|
||||
void f({String s}) {}
|
||||
''');
|
||||
var decoratedType = decoratedTypeAnnotation('String');
|
||||
var functionType = decoratedFunctionType('f');
|
||||
expect(functionType.namedParameters['s'], same(decoratedType));
|
||||
expect(decoratedType.node, isNotNull);
|
||||
expect(decoratedType.node, isNot(never));
|
||||
expect(decoratedType.node, isNot(always));
|
||||
expect(functionType.namedParameters['s'].node.isPossiblyOptional, true);
|
||||
}
|
||||
|
||||
test_topLevelFunction_parameterType_named_no_default_required() async {
|
||||
addMetaPackage();
|
||||
await analyze('''
|
||||
import 'package:meta/meta.dart';
|
||||
void f({@required String s}) {}
|
||||
''');
|
||||
var decoratedType = decoratedTypeAnnotation('String');
|
||||
var functionType = decoratedFunctionType('f');
|
||||
expect(functionType.namedParameters['s'], same(decoratedType));
|
||||
expect(decoratedType.node, isNotNull);
|
||||
expect(decoratedType.node, isNot(never));
|
||||
expect(decoratedType.node, isNot(always));
|
||||
expect(functionType.namedParameters['s'].node.isPossiblyOptional, false);
|
||||
}
|
||||
|
||||
test_topLevelFunction_parameterType_named_with_default() async {
|
||||
await analyze('''
|
||||
void f({String s: 'x'}) {}
|
||||
''');
|
||||
var decoratedType = decoratedTypeAnnotation('String');
|
||||
var functionType = decoratedFunctionType('f');
|
||||
expect(functionType.namedParameters['s'], same(decoratedType));
|
||||
expect(decoratedType.node, isNotNull);
|
||||
expect(decoratedType.node, isNot(never));
|
||||
expect(functionType.namedParameters['s'].node.isPossiblyOptional, false);
|
||||
}
|
||||
|
||||
test_topLevelFunction_parameterType_positionalOptional() async {
|
||||
await analyze('''
|
||||
void f([int i]) {}
|
||||
''');
|
||||
var decoratedType = decoratedTypeAnnotation('int');
|
||||
expect(decoratedFunctionType('f').positionalParameters[0],
|
||||
same(decoratedType));
|
||||
expect(decoratedType.node, isNotNull);
|
||||
expect(decoratedType.node, isNot(never));
|
||||
}
|
||||
|
||||
test_topLevelFunction_parameterType_simple() async {
|
||||
await analyze('''
|
||||
void f(int i) {}
|
||||
''');
|
||||
var decoratedType = decoratedTypeAnnotation('int');
|
||||
expect(decoratedFunctionType('f').positionalParameters[0],
|
||||
same(decoratedType));
|
||||
expect(decoratedType.node, isNotNull);
|
||||
expect(decoratedType.node, isNot(never));
|
||||
}
|
||||
|
||||
test_topLevelFunction_returnType_implicit_dynamic() async {
|
||||
await analyze('''
|
||||
f() {}
|
||||
''');
|
||||
var decoratedType = decoratedFunctionType('f').returnType;
|
||||
expect(decoratedType.type.isDynamic, isTrue);
|
||||
assertUnion(always, decoratedType.node);
|
||||
}
|
||||
|
||||
test_topLevelFunction_returnType_simple() async {
|
||||
await analyze('''
|
||||
int f() => 0;
|
||||
''');
|
||||
var decoratedType = decoratedTypeAnnotation('int');
|
||||
expect(decoratedFunctionType('f').returnType, same(decoratedType));
|
||||
expect(decoratedType.node, isNotNull);
|
||||
expect(decoratedType.node, isNot(never));
|
||||
}
|
||||
|
||||
test_type_comment_bang() async {
|
||||
await analyze('''
|
||||
void f(int/*!*/ i) {}
|
||||
''');
|
||||
assertEdge(decoratedTypeAnnotation('int').node, never, hard: true);
|
||||
}
|
||||
|
||||
test_type_comment_question() async {
|
||||
await analyze('''
|
||||
void f(int/*?*/ i) {}
|
||||
''');
|
||||
assertEdge(always, decoratedTypeAnnotation('int').node, hard: false);
|
||||
}
|
||||
|
||||
test_type_parameter_explicit_bound() async {
|
||||
await analyze('''
|
||||
class C<T extends Object> {}
|
||||
''');
|
||||
var bound = decoratedTypeParameterBound('T');
|
||||
expect(decoratedTypeAnnotation('Object'), same(bound));
|
||||
expect(bound.node, isNot(always));
|
||||
expect(bound.type, typeProvider.objectType);
|
||||
}
|
||||
|
||||
test_type_parameter_implicit_bound() async {
|
||||
// The implicit bound of `T` is automatically `Object?`. TODO(paulberry):
|
||||
// consider making it possible for type inference to infer an explicit bound
|
||||
// of `Object`.
|
||||
await analyze('''
|
||||
class C<T> {}
|
||||
''');
|
||||
var bound = decoratedTypeParameterBound('T');
|
||||
assertUnion(always, bound.node);
|
||||
expect(bound.type, same(typeProvider.objectType));
|
||||
}
|
||||
|
||||
test_variableDeclaration_type_simple() async {
|
||||
await analyze('''
|
||||
main() {
|
||||
int i;
|
||||
}
|
||||
''');
|
||||
var decoratedType = decoratedTypeAnnotation('int');
|
||||
expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
|
||||
}
|
||||
|
||||
test_void_type() async {
|
||||
await analyze('''
|
||||
void f() {}
|
||||
''');
|
||||
var decoratedType = decoratedTypeAnnotation('void');
|
||||
expect(decoratedFunctionType('f').returnType, same(decoratedType));
|
||||
assertEdge(always, decoratedType.node, hard: false);
|
||||
}
|
||||
}
|
|
@ -5,13 +5,15 @@
|
|||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import 'api_test.dart' as api_test;
|
||||
import 'migration_visitor_test.dart' as migration_visitor_test;
|
||||
import 'graph_builder_test.dart' as graph_builder_test;
|
||||
import 'node_builder_test.dart' as node_builder_test;
|
||||
import 'nullability_node_test.dart' as nullability_node_test;
|
||||
|
||||
main() {
|
||||
defineReflectiveSuite(() {
|
||||
api_test.main();
|
||||
migration_visitor_test.main();
|
||||
graph_builder_test.main();
|
||||
node_builder_test.main();
|
||||
nullability_node_test.main();
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue