Migration: Add IndexExpression support to FixBuilder.

Change-Id: I870047d12304c70cfe89e64d4864cc1809b7e4ac
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/121408
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Mike Fairhurst <mfairhurst@google.com>
This commit is contained in:
Paul Berry 2019-10-12 03:11:03 +00:00 committed by commit-bot@chromium.org
parent 5594981c2a
commit 1e3cbd4344
2 changed files with 273 additions and 0 deletions

View file

@ -179,6 +179,34 @@ abstract class FixBuilder extends GeneralizingAstVisitor<DartType> {
? writeType
: _computeMigratedType(auxiliaryElements.staticElement);
return AssignmentTargetInfo(isCompound ? readType : null, writeType);
} else if (node is IndexExpression) {
var targetType =
visitSubexpression(node.target, _typeProvider.objectType);
var writeElement = node.staticElement;
DartType indexContext;
DartType writeType;
DartType readType;
if (writeElement == null) {
indexContext = UnknownInferredType.instance;
writeType = _typeProvider.dynamicType;
readType = isCompound ? _typeProvider.dynamicType : null;
} else {
var writerType =
_computeMigratedType(writeElement, targetType: targetType)
as FunctionType;
writeType = writerType.parameters[1].type;
if (isCompound) {
var readerType = _computeMigratedType(
node.auxiliaryElements.staticElement,
targetType: targetType) as FunctionType;
readType = readerType.returnType;
indexContext = readerType.parameters[0].type;
} else {
indexContext = writerType.parameters[0].type;
}
}
visitSubexpression(node.index, indexContext);
return AssignmentTargetInfo(readType, writeType);
} else {
throw UnimplementedError('TODO(paulberry)');
}
@ -276,6 +304,28 @@ abstract class FixBuilder extends GeneralizingAstVisitor<DartType> {
return null;
}
@override
DartType visitIndexExpression(IndexExpression node) {
var target = node.target;
var staticElement = node.staticElement;
var index = node.index;
var targetType = visitSubexpression(target, _typeProvider.objectType);
DartType contextType;
DartType returnType;
if (staticElement == null) {
contextType = _typeProvider.dynamicType;
returnType = _typeProvider.dynamicType;
} else {
var methodType =
_computeMigratedType(staticElement, targetType: targetType)
as FunctionType;
contextType = methodType.parameters[0].type;
returnType = methodType.returnType;
}
visitSubexpression(index, contextType);
return returnType;
}
@override
DartType visitListLiteral(ListLiteral node) {
DartType contextType;

View file

@ -236,6 +236,158 @@ _f(bool/*?*/ x, bool/*?*/ y) => x != null && (x = y) != null;
visitSubexpression(findNode.binary('&&'), 'bool');
}
test_assignmentTarget_indexExpression_compound_dynamic() async {
await analyze('''
_f(dynamic d, int/*?*/ i) => d[i] += 0;
''');
visitAssignmentTarget(findNode.index('d[i]'), 'dynamic', 'dynamic');
}
test_assignmentTarget_indexExpression_compound_simple() async {
await analyze('''
class _C {
int operator[](String s) => 1;
void operator[]=(String s, num n) {}
}
_f(_C c) => c['foo'] += 0;
''');
visitAssignmentTarget(findNode.index('c['), 'int', 'num');
}
test_assignmentTarget_indexExpression_compound_simple_check_lhs() async {
await analyze('''
class _C {
int operator[](String s) => 1;
void operator[]=(String s, num n) {}
}
_f(_C/*?*/ c) => c['foo'] += 0;
''');
visitAssignmentTarget(findNode.index('c['), 'int', 'num',
nullChecked: {findNode.simple('c[')});
}
test_assignmentTarget_indexExpression_compound_simple_check_rhs() async {
await analyze('''
class _C {
int operator[](String/*!*/ s) => 1;
void operator[]=(String/*?*/ s, num n) {}
}
_f(_C c, String/*?*/ s) => c[s] += 0;
''');
visitAssignmentTarget(findNode.index('c['), 'int', 'num',
nullChecked: {findNode.simple('s]')});
}
test_assignmentTarget_indexExpression_compound_substituted() async {
await analyze('''
class _C<T, U> {
T operator[](U u) => throw 'foo';
void operator[]=(U u, T t) {}
}
_f(_C<int, String> c) => c['foo'] += 1;
''');
visitAssignmentTarget(findNode.index('c['), 'int', 'int');
}
test_assignmentTarget_indexExpression_compound_substituted_check_rhs() async {
await analyze('''
class _C<T, U> {
T operator[](U u) => throw 'foo';
void operator[]=(U/*?*/ u, T t) {}
}
_f(_C<int, String/*!*/> c, String/*?*/ s) => c[s] += 1;
''');
visitAssignmentTarget(findNode.index('c['), 'int', 'int',
nullChecked: {findNode.simple('s]')});
}
test_assignmentTarget_indexExpression_compound_substituted_no_check_rhs() async {
await analyze('''
class _C<T, U> {
T operator[](U u) => throw 'foo';
void operator[]=(U u, T t) {}
}
_f(_C<int, String/*?*/> c, String/*?*/ s) => c[s] += 0;
''');
visitAssignmentTarget(findNode.index('c['), 'int', 'int');
}
test_assignmentTarget_indexExpression_dynamic() async {
await analyze('''
_f(dynamic d, int/*?*/ i) => d[i] = 0;
''');
visitAssignmentTarget(findNode.index('d[i]'), null, 'dynamic');
}
test_assignmentTarget_indexExpression_simple() async {
await analyze('''
class _C {
int operator[](String s) => 1;
void operator[]=(String s, num n) {}
}
_f(_C c) => c['foo'] = 0;
''');
visitAssignmentTarget(findNode.index('c['), null, 'num');
}
test_assignmentTarget_indexExpression_simple_check_lhs() async {
await analyze('''
class _C {
int operator[](String s) => 1;
void operator[]=(String s, num n) {}
}
_f(_C/*?*/ c) => c['foo'] = 0;
''');
visitAssignmentTarget(findNode.index('c['), null, 'num',
nullChecked: {findNode.simple('c[')});
}
test_assignmentTarget_indexExpression_simple_check_rhs() async {
await analyze('''
class _C {
int operator[](String/*?*/ s) => 1;
void operator[]=(String/*!*/ s, num n) {}
}
_f(_C c, String/*?*/ s) => c[s] = 0;
''');
visitAssignmentTarget(findNode.index('c['), null, 'num',
nullChecked: {findNode.simple('s]')});
}
test_assignmentTarget_indexExpression_substituted() async {
await analyze('''
class _C<T, U> {
T operator[](U u) => throw 'foo';
void operator[]=(U u, T t) {}
}
_f(_C<int, String> c) => c['foo'] = 1;
''');
visitAssignmentTarget(findNode.index('c['), null, 'int');
}
test_assignmentTarget_indexExpression_substituted_check_rhs() async {
await analyze('''
class _C<T, U> {
T operator[](U u) => throw 'foo';
void operator[]=(U/*?*/ u, T t) {}
}
_f(_C<int, String/*!*/> c, String/*?*/ s) => c[s] = 1;
''');
visitAssignmentTarget(findNode.index('c['), null, 'int',
nullChecked: {findNode.simple('s]')});
}
test_assignmentTarget_indexExpression_substituted_no_check_rhs() async {
await analyze('''
class _C<T, U> {
T operator[](U u) => throw 'foo';
void operator[]=(U u, T t) {}
}
_f(_C<int, String/*?*/> c, String/*?*/ s) => c[s] = 0;
''');
visitAssignmentTarget(findNode.index('c['), null, 'int');
}
test_assignmentTarget_simpleIdentifier_field_generic() async {
await analyze('''
abstract class _C<T> {
@ -645,6 +797,77 @@ _f(int/*?*/ x) {
visitStatement(findNode.statement('if'));
}
test_indexExpression_dynamic() async {
await analyze('''
Object/*!*/ _f(dynamic d, int/*?*/ i) => d[i];
''');
visitSubexpression(findNode.index('d[i]'), 'dynamic',
contextType: objectType);
}
test_indexExpression_simple() async {
await analyze('''
class _C {
int operator[](String s) => 1;
}
_f(_C c) => c['foo'];
''');
visitSubexpression(findNode.index('c['), 'int');
}
test_indexExpression_simple_check_lhs() async {
await analyze('''
class _C {
int operator[](String s) => 1;
}
_f(_C/*?*/ c) => c['foo'];
''');
visitSubexpression(findNode.index('c['), 'int',
nullChecked: {findNode.simple('c[')});
}
test_indexExpression_simple_check_rhs() async {
await analyze('''
class _C {
int operator[](String/*!*/ s) => 1;
}
_f(_C c, String/*?*/ s) => c[s];
''');
visitSubexpression(findNode.index('c['), 'int',
nullChecked: {findNode.simple('s]')});
}
test_indexExpression_substituted() async {
await analyze('''
class _C<T, U> {
T operator[](U u) => throw 'foo';
}
_f(_C<int, String> c) => c['foo'];
''');
visitSubexpression(findNode.index('c['), 'int');
}
test_indexExpression_substituted_check_rhs() async {
await analyze('''
class _C<T, U> {
T operator[](U u) => throw 'foo';
}
_f(_C<int, String/*!*/> c, String/*?*/ s) => c[s];
''');
visitSubexpression(findNode.index('c['), 'int',
nullChecked: {findNode.simple('s]')});
}
test_indexExpression_substituted_no_check_rhs() async {
await analyze('''
class _C<T, U> {
T operator[](U u) => throw 'foo';
}
_f(_C<int, String/*?*/> c, String/*?*/ s) => c[s];
''');
visitSubexpression(findNode.index('c['), 'int');
}
test_integerLiteral() async {
await analyze('''
f() => 1;