Skip to content

Commit 79f276e

Browse files
stereotype441commit-bot@chromium.org
authored andcommitted
Migration: handle field formal parameters.
Change-Id: I15fb64a2cb7ed9bc56593fc8b27170aaa34af8a5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/107743 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
1 parent c8c3572 commit 79f276e

File tree

7 files changed

+190
-32
lines changed

7 files changed

+190
-32
lines changed

pkg/nnbd_migration/lib/src/edge_builder.dart

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ class EdgeBuilder extends GeneralizingAstVisitor<DecoratedType> {
345345

346346
@override
347347
DecoratedType visitDefaultFormalParameter(DefaultFormalParameter node) {
348+
node.parameter.accept(this);
348349
var defaultValue = node.defaultValue;
349350
if (defaultValue == null) {
350351
if (node.declaredElement.hasRequired) {
@@ -382,6 +383,21 @@ class EdgeBuilder extends GeneralizingAstVisitor<DecoratedType> {
382383
return null;
383384
}
384385

386+
@override
387+
DecoratedType visitFieldFormalParameter(FieldFormalParameter node) {
388+
var parameterElement = node.declaredElement as FieldFormalParameterElement;
389+
var parameterType = _variables.decoratedElementType(parameterElement);
390+
var fieldType = _variables.decoratedElementType(parameterElement.field);
391+
var origin = FieldFormalParameterOrigin(_source, node.offset);
392+
if (node.type == null) {
393+
_unionDecoratedTypes(parameterType, fieldType, origin);
394+
} else {
395+
_checkAssignment(origin,
396+
source: parameterType, destination: fieldType, hard: true);
397+
}
398+
return null;
399+
}
400+
385401
@override
386402
DecoratedType visitFunctionDeclaration(FunctionDeclaration node) {
387403
node.functionExpression.parameters?.accept(this);

pkg/nnbd_migration/lib/src/edge_origin.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ abstract class EdgeOriginWithLocation extends EdgeOrigin {
3434
EdgeOriginWithLocation(this.source, this.offset);
3535
}
3636

37+
/// Edge origin resulting from the relationship between a field formal parameter
38+
/// and the corresponding field.
39+
class FieldFormalParameterOrigin extends EdgeOriginWithLocation {
40+
FieldFormalParameterOrigin(Source source, int offset) : super(source, offset);
41+
}
42+
3743
/// Edge origin resulting from the presence of a `??` operator.
3844
class IfNullOrigin extends EdgeOriginWithLocation {
3945
IfNullOrigin(Source source, int offset) : super(source, offset);

pkg/nnbd_migration/lib/src/node_builder.dart

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -134,20 +134,8 @@ class NodeBuilder extends GeneralizingAstVisitor<DecoratedType> {
134134

135135
@override
136136
DecoratedType visitFieldFormalParameter(FieldFormalParameter node) {
137-
// TODO(brianwilkerson)
138-
_unimplemented(node, 'FieldFormalParameter');
139-
}
140-
141-
@override
142-
DecoratedType visitFormalParameter(FormalParameter node) {
143-
// Do not visit children
144-
// TODO(paulberry): handle all types of formal parameters
145-
// - NormalFormalParameter
146-
// - SimpleFormalParameter
147-
// - FieldFormalParameter
148-
// - FunctionTypedFormalParameter
149-
// - DefaultFormalParameter
150-
return null;
137+
return _handleFormalParameter(node.declaredElement, node.metadata,
138+
node.type, node.typeParameters, node.parameters);
151139
}
152140

153141
@override
@@ -171,8 +159,8 @@ class NodeBuilder extends GeneralizingAstVisitor<DecoratedType> {
171159
@override
172160
DecoratedType visitFunctionTypedFormalParameter(
173161
FunctionTypedFormalParameter node) {
174-
// TODO(brianwilkerson)
175-
_unimplemented(node, 'FunctionTypedFormalParameter');
162+
return _handleFormalParameter(node.declaredElement, node.metadata,
163+
node.returnType, node.typeParameters, node.parameters);
176164
}
177165

178166
@override
@@ -212,17 +200,8 @@ $stackTrace''');
212200

213201
@override
214202
DecoratedType visitSimpleFormalParameter(SimpleFormalParameter node) {
215-
var declaredElement = node.declaredElement;
216-
var type = node.type != null
217-
? node.type.accept(this)
218-
: DecoratedType.forImplicitType(declaredElement.type, _graph);
219-
_variables.recordDecoratedElementType(declaredElement, type);
220-
if (declaredElement.isNamed) {
221-
_namedParameters[declaredElement.name] = type;
222-
} else {
223-
_positionalParameters.add(type);
224-
}
225-
return type;
203+
return _handleFormalParameter(
204+
node.declaredElement, node.metadata, node.type, null, null);
226205
}
227206

228207
@override
@@ -410,6 +389,28 @@ $stackTrace''');
410389
declaredElement, decoratedFunctionType);
411390
}
412391

392+
DecoratedType _handleFormalParameter(
393+
ParameterElement declaredElement,
394+
NodeList<Annotation> metadata,
395+
TypeAnnotation type,
396+
TypeParameterList typeParameters,
397+
FormalParameterList parameters) {
398+
if (typeParameters != null || parameters != null) {
399+
_unimplemented(parameters, 'FunctionTypedFormalParameter');
400+
}
401+
metadata?.accept(this);
402+
var decoratedType = type != null
403+
? type.accept(this)
404+
: DecoratedType.forImplicitType(declaredElement.type, _graph);
405+
_variables.recordDecoratedElementType(declaredElement, decoratedType);
406+
if (declaredElement.isNamed) {
407+
_namedParameters[declaredElement.name] = decoratedType;
408+
} else {
409+
_positionalParameters.add(decoratedType);
410+
}
411+
return decoratedType;
412+
}
413+
413414
void _handleSupertypeClauses(
414415
ClassElement declaredElement,
415416
TypeName superclass,

pkg/nnbd_migration/test/api_test.dart

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,82 @@ int f(int i) {
813813
await _checkSingleFileChanges(content, expected);
814814
}
815815

816+
test_field_formal_param_typed() async {
817+
var content = '''
818+
class C {
819+
int i;
820+
C(int this.i);
821+
}
822+
main() {
823+
C(null);
824+
}
825+
''';
826+
var expected = '''
827+
class C {
828+
int? i;
829+
C(int? this.i);
830+
}
831+
main() {
832+
C(null);
833+
}
834+
''';
835+
await _checkSingleFileChanges(content, expected);
836+
}
837+
838+
test_field_formal_param_typed_non_nullable() async {
839+
var content = '''
840+
class C {
841+
int/*!*/ i;
842+
C(int this.i);
843+
}
844+
void f(int i, bool b) {
845+
if (b) {
846+
C(i);
847+
}
848+
}
849+
main() {
850+
f(null, false);
851+
}
852+
''';
853+
var expected = '''
854+
class C {
855+
int/*!*/ i;
856+
C(int this.i);
857+
}
858+
void f(int? i, bool b) {
859+
if (b) {
860+
C(i!);
861+
}
862+
}
863+
main() {
864+
f(null, false);
865+
}
866+
''';
867+
await _checkSingleFileChanges(content, expected);
868+
}
869+
870+
test_field_formal_param_untyped() async {
871+
var content = '''
872+
class C {
873+
int i;
874+
C(this.i);
875+
}
876+
main() {
877+
C(null);
878+
}
879+
''';
880+
var expected = '''
881+
class C {
882+
int? i;
883+
C(this.i);
884+
}
885+
main() {
886+
C(null);
887+
}
888+
''';
889+
await _checkSingleFileChanges(content, expected);
890+
}
891+
816892
test_field_type_inferred() async {
817893
var content = '''
818894
int f() => null;

pkg/nnbd_migration/test/edge_builder_test.dart

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,31 @@ class C {
811811
assertUnion(xType.node, decoratedTypeAnnotation('int').node);
812812
}
813813

814+
test_fieldFormalParameter_typed() async {
815+
await analyze('''
816+
class C {
817+
int i;
818+
C(int this.i);
819+
}
820+
''');
821+
assertEdge(decoratedTypeAnnotation('int this').node,
822+
decoratedTypeAnnotation('int i').node,
823+
hard: true);
824+
}
825+
826+
test_fieldFormalParameter_untyped() async {
827+
await analyze('''
828+
class C {
829+
int i;
830+
C.named(this.i);
831+
}
832+
''');
833+
var decoratedConstructorParamType =
834+
decoratedConstructorDeclaration('named').positionalParameters[0];
835+
assertUnion(decoratedConstructorParamType.node,
836+
decoratedTypeAnnotation('int i').node);
837+
}
838+
814839
test_functionDeclaration_expression_body() async {
815840
await analyze('''
816841
int/*1*/ f(int/*2*/ i) => i/*3*/;

pkg/nnbd_migration/test/migration_visitor_test_base.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,11 @@ class MigrationVisitorTestBase extends AbstractSingleUnitTest {
140140
fail('Expected union between $x and $y, not found');
141141
}
142142

143+
/// Gets the [DecoratedType] associated with the constructor declaration whose
144+
/// name matches [search].
145+
DecoratedType decoratedConstructorDeclaration(String search) => variables
146+
.decoratedElementType(findNode.constructor(search).declaredElement);
147+
143148
Map<ClassElement, DecoratedType> decoratedDirectSupertypes(String name) {
144149
return variables.decoratedDirectSupertypes(findElement.classOrMixin(name));
145150
}

pkg/nnbd_migration/test/node_builder_test.dart

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,6 @@ main() {
1717

1818
@reflectiveTest
1919
class NodeBuilderTest extends MigrationVisitorTestBase {
20-
/// Gets the [DecoratedType] associated with the constructor declaration whose
21-
/// name matches [search].
22-
DecoratedType decoratedConstructorDeclaration(String search) => variables
23-
.decoratedElementType(findNode.constructor(search).declaredElement);
24-
2520
/// Gets the [DecoratedType] associated with the function declaration whose
2621
/// name matches [search].
2722
DecoratedType decoratedFunctionType(String search) =>
@@ -415,6 +410,40 @@ class C {
415410
same(decoratedType));
416411
}
417412

413+
test_fieldFormalParameter_typed() async {
414+
await analyze('''
415+
class C {
416+
int i;
417+
C.named(int this.i);
418+
}
419+
''');
420+
var decoratedConstructorParamType =
421+
decoratedConstructorDeclaration('named').positionalParameters[0];
422+
expect(decoratedTypeAnnotation('int this'),
423+
same(decoratedConstructorParamType));
424+
expect(decoratedConstructorParamType.type.toString(), 'int');
425+
expect(decoratedConstructorParamType.node,
426+
TypeMatcher<NullabilityNodeMutable>());
427+
// Note: the edge builder will connect this node to the node for the type of
428+
// the field.
429+
}
430+
431+
test_fieldFormalParameter_untyped() async {
432+
await analyze('''
433+
class C {
434+
int i;
435+
C.named(this.i);
436+
}
437+
''');
438+
var decoratedConstructorParamType =
439+
decoratedConstructorDeclaration('named').positionalParameters[0];
440+
expect(decoratedConstructorParamType.type.toString(), 'int');
441+
expect(decoratedConstructorParamType.node,
442+
TypeMatcher<NullabilityNodeMutable>());
443+
// Note: the edge builder will unify this implicit type with the type of the
444+
// field.
445+
}
446+
418447
test_generic_function_type_syntax_inferred_dynamic_return() async {
419448
await analyze('''
420449
abstract class C {

0 commit comments

Comments
 (0)