Skip to content

Commit 8eb28a4

Browse files
stereotype441commit-bot@chromium.org
authored andcommitted
Migration: add simple MethodInvocation support to FixBuilder.
Change-Id: Ice76583076a3f38d1cc0f9a3aacbac630a9a97c0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/121763 Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
1 parent 7d4bc6a commit 8eb28a4

File tree

2 files changed

+194
-0
lines changed

2 files changed

+194
-0
lines changed

pkg/nnbd_migration/lib/src/fix_builder.dart

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,20 @@ abstract class FixBuilder extends GeneralizingAstVisitor<DartType>
121121
_assignedVariables.capturedAnywhere);
122122
}
123123

124+
@override
125+
DartType visitArgumentList(ArgumentList node) {
126+
for (var argument in node.arguments) {
127+
Expression expression;
128+
if (argument is NamedExpression) {
129+
expression = argument.expression;
130+
} else {
131+
expression = argument;
132+
}
133+
visitSubexpression(expression, UnknownInferredType.instance);
134+
}
135+
return null;
136+
}
137+
124138
@override
125139
DartType visitAssignmentExpression(AssignmentExpression node) {
126140
var operatorType = node.operator.type;
@@ -378,6 +392,44 @@ abstract class FixBuilder extends GeneralizingAstVisitor<DartType>
378392
.withNullability(NullabilitySuffix.none);
379393
}
380394

395+
@override
396+
DartType visitMethodInvocation(MethodInvocation node) {
397+
var target = node.realTarget;
398+
var callee = node.methodName.staticElement;
399+
bool isNullAware = node.isNullAware;
400+
DartType targetType;
401+
if (target != null) {
402+
if (callee is ExecutableElement && callee.isStatic) {
403+
target.accept(this);
404+
} else {
405+
targetType = visitSubexpression(
406+
target,
407+
isNullAware || isDeclaredOnObject(node.methodName.name)
408+
? typeProvider.dynamicType
409+
: typeProvider.objectType);
410+
}
411+
}
412+
if (callee == null) {
413+
// Dynamic dispatch. The return type is `dynamic`.
414+
node.typeArguments?.accept(this);
415+
node.argumentList.accept(this);
416+
return typeProvider.dynamicType;
417+
}
418+
var calleeType = _computeMigratedType(callee, targetType: targetType);
419+
var expressionType = _handleInvocationArguments(
420+
node,
421+
node.argumentList.arguments,
422+
node.typeArguments,
423+
node.typeArgumentTypes,
424+
calleeType as FunctionType,
425+
null,
426+
invokeType: node.staticInvokeType);
427+
if (isNullAware) {
428+
expressionType = _typeSystem.makeNullable(expressionType as TypeImpl);
429+
}
430+
return expressionType;
431+
}
432+
381433
@override
382434
DartType visitNode(AstNode node) {
383435
// Every node type needs its own visit method.
@@ -665,6 +717,51 @@ abstract class FixBuilder extends GeneralizingAstVisitor<DartType>
665717
return combinedType;
666718
}
667719

720+
DartType _handleInvocationArguments(
721+
AstNode node,
722+
Iterable<AstNode> arguments,
723+
TypeArgumentList typeArguments,
724+
List<DartType> typeArgumentTypes,
725+
FunctionType calleeType,
726+
List<TypeParameterElement> constructorTypeParameters,
727+
{DartType invokeType}) {
728+
var typeFormals = constructorTypeParameters ?? calleeType.typeFormals;
729+
if (typeFormals.isNotEmpty) {
730+
throw UnimplementedError('TODO(paulberry): Invocation of generic method');
731+
}
732+
int i = 0;
733+
var namedParameterTypes = <String, DartType>{};
734+
var positionalParameterTypes = <DartType>[];
735+
for (var parameter in calleeType.parameters) {
736+
if (parameter.isNamed) {
737+
namedParameterTypes[parameter.name] = parameter.type;
738+
} else {
739+
positionalParameterTypes.add(parameter.type);
740+
}
741+
}
742+
for (var argument in arguments) {
743+
String name;
744+
Expression expression;
745+
if (argument is NamedExpression) {
746+
name = argument.name.label.name;
747+
expression = argument.expression;
748+
} else {
749+
expression = argument as Expression;
750+
}
751+
DartType parameterType;
752+
if (name != null) {
753+
parameterType = namedParameterTypes[name];
754+
assert(parameterType != null, 'Missing type for named parameter');
755+
} else {
756+
assert(i < positionalParameterTypes.length,
757+
'Missing positional parameter at $i');
758+
parameterType = positionalParameterTypes[i++];
759+
}
760+
visitSubexpression(expression, parameterType);
761+
}
762+
return calleeType.returnType;
763+
}
764+
668765
DartType _handlePropertyAccess(Expression node, Expression target,
669766
SimpleIdentifier propertyName, bool isNullAware) {
670767
var staticElement = propertyName.staticElement;

pkg/nnbd_migration/test/fix_builder_test.dart

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,6 +1074,103 @@ _f(int/*?*/ x) => <int/*!*/>[x];
10741074
changes: {findNode.simple('x]'): NullCheck()});
10751075
}
10761076

1077+
test_methodInvocation_dynamic() async {
1078+
await analyze('''
1079+
Object/*!*/ _f(dynamic d) => d.f();
1080+
''');
1081+
visitSubexpression(findNode.methodInvocation('d.f'), 'dynamic',
1082+
contextType: objectType);
1083+
}
1084+
1085+
test_methodInvocation_namedParameter() async {
1086+
await analyze('''
1087+
abstract class _C {
1088+
int f({int/*!*/ x});
1089+
}
1090+
_f(_C c, int/*?*/ y) => c.f(x: y);
1091+
''');
1092+
visitSubexpression(findNode.methodInvocation('c.f'), 'int',
1093+
changes: {findNode.simple('y);'): NullCheck()});
1094+
}
1095+
1096+
test_methodInvocation_ordinaryParameter() async {
1097+
await analyze('''
1098+
abstract class _C {
1099+
int f(int/*!*/ x);
1100+
}
1101+
_f(_C c, int/*?*/ y) => c.f(y);
1102+
''');
1103+
visitSubexpression(findNode.methodInvocation('c.f'), 'int',
1104+
changes: {findNode.simple('y);'): NullCheck()});
1105+
}
1106+
1107+
test_methodInvocation_return_nonNullable() async {
1108+
await analyze('''
1109+
abstract class _C {
1110+
int f();
1111+
}
1112+
_f(_C c) => c.f();
1113+
''');
1114+
visitSubexpression(findNode.methodInvocation('c.f'), 'int');
1115+
}
1116+
1117+
test_methodInvocation_return_nonNullable_check_target() async {
1118+
await analyze('''
1119+
abstract class _C {
1120+
int f();
1121+
}
1122+
_f(_C/*?*/ c) => c.f();
1123+
''');
1124+
visitSubexpression(findNode.methodInvocation('c.f'), 'int',
1125+
changes: {findNode.simple('c.f'): NullCheck()});
1126+
}
1127+
1128+
test_methodInvocation_return_nonNullable_nullAware() async {
1129+
await analyze('''
1130+
abstract class _C {
1131+
int f();
1132+
}
1133+
_f(_C/*?*/ c) => c?.f();
1134+
''');
1135+
visitSubexpression(findNode.methodInvocation('c?.f'), 'int?');
1136+
}
1137+
1138+
test_methodInvocation_return_nullable() async {
1139+
await analyze('''
1140+
abstract class _C {
1141+
int/*?*/ f();
1142+
}
1143+
_f(_C c) => c.f();
1144+
''');
1145+
visitSubexpression(findNode.methodInvocation('c.f'), 'int?');
1146+
}
1147+
1148+
test_methodInvocation_static() async {
1149+
await analyze('''
1150+
_f() => _C.g();
1151+
class _C {
1152+
static int g() => 1;
1153+
}
1154+
''');
1155+
visitSubexpression(findNode.methodInvocation('_C.g();'), 'int');
1156+
}
1157+
1158+
test_methodInvocation_topLevel() async {
1159+
await analyze('''
1160+
_f() => _g();
1161+
int _g() => 1;
1162+
''');
1163+
visitSubexpression(findNode.methodInvocation('_g();'), 'int');
1164+
}
1165+
1166+
test_methodInvocation_toString() async {
1167+
await analyze('''
1168+
abstract class _C {}
1169+
_f(_C/*?*/ c) => c.toString();
1170+
''');
1171+
visitSubexpression(findNode.methodInvocation('c.toString'), 'String');
1172+
}
1173+
10771174
test_nullAssertion_promotes() async {
10781175
await analyze('''
10791176
_f(bool/*?*/ x) => x && x;

0 commit comments

Comments
 (0)