mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 02:17:14 +00:00
Migration: fix handling of unresolved field formal parameters.
Change-Id: I67d3472974657618afa88d7feafae1eaf8250e43 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/207040 Reviewed-by: Samuel Rawlins <srawlins@google.com>
This commit is contained in:
parent
06a35b8c2e
commit
e98091010e
|
@ -895,18 +895,20 @@ class EdgeBuilder extends GeneralizingAstVisitor<DecoratedType>
|
|||
_dispatch(node.parameters);
|
||||
var parameterElement = node.declaredElement as FieldFormalParameterElement;
|
||||
var parameterType = _variables!.decoratedElementType(parameterElement);
|
||||
var field = parameterElement.field!;
|
||||
_fieldsNotInitializedByConstructor!.remove(field);
|
||||
var fieldType = _variables!.decoratedElementType(field);
|
||||
var origin = FieldFormalParameterOrigin(source, node);
|
||||
if (node.type == null) {
|
||||
_linkDecoratedTypes(parameterType, fieldType, origin, isUnion: false);
|
||||
_checkAssignment(origin, FixReasonTarget.root,
|
||||
source: fieldType, destination: parameterType, hard: false);
|
||||
} else {
|
||||
_dispatch(node.type);
|
||||
_checkAssignment(origin, FixReasonTarget.root,
|
||||
source: parameterType, destination: fieldType, hard: true);
|
||||
var field = parameterElement.field;
|
||||
if (field != null) {
|
||||
_fieldsNotInitializedByConstructor!.remove(field);
|
||||
var fieldType = _variables!.decoratedElementType(field);
|
||||
var origin = FieldFormalParameterOrigin(source, node);
|
||||
if (node.type == null) {
|
||||
_linkDecoratedTypes(parameterType, fieldType, origin, isUnion: false);
|
||||
_checkAssignment(origin, FixReasonTarget.root,
|
||||
source: fieldType, destination: parameterType, hard: false);
|
||||
} else {
|
||||
_dispatch(node.type);
|
||||
_checkAssignment(origin, FixReasonTarget.root,
|
||||
source: parameterType, destination: fieldType, hard: true);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -2083,7 +2085,10 @@ class EdgeBuilder extends GeneralizingAstVisitor<DecoratedType>
|
|||
var result = <PropertyAccessorElement, FieldFormalParameterElement>{};
|
||||
for (var parameter in constructorElement.parameters) {
|
||||
if (parameter is FieldFormalParameterElement) {
|
||||
result[parameter.field!.getter!] = parameter;
|
||||
var getter = parameter.field?.getter;
|
||||
if (getter != null) {
|
||||
result[getter] = parameter;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
|
|
@ -1147,15 +1147,18 @@ class _FixBuilderPreVisitor extends GeneralizingAstVisitor<void>
|
|||
// Potentially add an explicit type to a field formal parameter.
|
||||
var decl = node.declaredElement as FieldFormalParameterElement;
|
||||
var decoratedType = _fixBuilder._variables!.decoratedElementType(decl);
|
||||
var decoratedFieldType =
|
||||
_fixBuilder._variables!.decoratedElementType(decl.field!);
|
||||
var typeToAdd = _fixBuilder._variables!.toFinalType(decoratedType);
|
||||
var fieldFinalType =
|
||||
_fixBuilder._variables!.toFinalType(decoratedFieldType);
|
||||
if (typeToAdd is InterfaceType &&
|
||||
!_fixBuilder._typeSystem.isSubtypeOf(fieldFinalType, typeToAdd)) {
|
||||
(_fixBuilder._getChange(node) as NodeChangeForFieldFormalParameter)
|
||||
.addExplicitType = typeToAdd;
|
||||
var field = decl.field;
|
||||
if (field != null) {
|
||||
var decoratedFieldType =
|
||||
_fixBuilder._variables!.decoratedElementType(field);
|
||||
var typeToAdd = _fixBuilder._variables!.toFinalType(decoratedType);
|
||||
var fieldFinalType =
|
||||
_fixBuilder._variables!.toFinalType(decoratedFieldType);
|
||||
if (typeToAdd is InterfaceType &&
|
||||
!_fixBuilder._typeSystem.isSubtypeOf(fieldFinalType, typeToAdd)) {
|
||||
(_fixBuilder._getChange(node) as NodeChangeForFieldFormalParameter)
|
||||
.addExplicitType = typeToAdd;
|
||||
}
|
||||
}
|
||||
} else if (node.parameters != null) {
|
||||
// Handle function-typed field formal parameters.
|
||||
|
|
|
@ -446,9 +446,10 @@ class NodeBuilder extends GeneralizingAstVisitor<DecoratedType>
|
|||
|
||||
@override
|
||||
DecoratedType? visitMethodDeclaration(MethodDeclaration node) {
|
||||
_handleExecutableDeclaration(
|
||||
var declaredElement = node.declaredElement;
|
||||
var decoratedType = _handleExecutableDeclaration(
|
||||
node,
|
||||
node.declaredElement!,
|
||||
declaredElement!,
|
||||
node.metadata,
|
||||
node.returnType,
|
||||
node.typeParameters,
|
||||
|
@ -456,6 +457,19 @@ class NodeBuilder extends GeneralizingAstVisitor<DecoratedType>
|
|||
null,
|
||||
node.body,
|
||||
null);
|
||||
if (declaredElement is PropertyAccessorElement) {
|
||||
// Store a decorated type for the synthetic field so that in case we try
|
||||
// to access it later we won't crash (this could happen due to errors in
|
||||
// the source code).
|
||||
if (declaredElement.isGetter) {
|
||||
_variables!.recordDecoratedElementType(
|
||||
declaredElement.variable, decoratedType.returnType);
|
||||
} else {
|
||||
_variables!.recordDecoratedElementType(
|
||||
declaredElement.variable, decoratedType.positionalParameters![0],
|
||||
soft: true);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -675,7 +689,7 @@ class NodeBuilder extends GeneralizingAstVisitor<DecoratedType>
|
|||
}
|
||||
|
||||
/// Common handling of function and method declarations.
|
||||
void _handleExecutableDeclaration(
|
||||
DecoratedType _handleExecutableDeclaration(
|
||||
AstNode node,
|
||||
ExecutableElement declaredElement,
|
||||
NodeList<Annotation>? metadata,
|
||||
|
@ -726,6 +740,7 @@ class NodeBuilder extends GeneralizingAstVisitor<DecoratedType>
|
|||
}
|
||||
_variables!
|
||||
.recordDecoratedElementType(declaredElement, decoratedFunctionType);
|
||||
return decoratedFunctionType;
|
||||
}
|
||||
|
||||
DecoratedType? _handleFormalParameter(
|
||||
|
|
|
@ -214,7 +214,8 @@ class Variables {
|
|||
}
|
||||
|
||||
/// Associates decorated type information with the given [element].
|
||||
void recordDecoratedElementType(Element? element, DecoratedType? type) {
|
||||
void recordDecoratedElementType(Element? element, DecoratedType? type,
|
||||
{bool soft = false}) {
|
||||
assert(() {
|
||||
assert(element is! TypeParameterElement,
|
||||
'Use recordDecoratedTypeParameterBound instead');
|
||||
|
@ -227,6 +228,9 @@ class Variables {
|
|||
}
|
||||
return true;
|
||||
}());
|
||||
if (soft && _decoratedElementTypes.containsKey(element)) {
|
||||
return;
|
||||
}
|
||||
_decoratedElementTypes[element] = type;
|
||||
}
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ abstract class _ProvisionalApiTestBase extends AbstractContextTest {
|
|||
///
|
||||
/// Optional parameter [removeViaComments] indicates whether dead code should
|
||||
/// be removed in its entirety (the default) or removed by commenting it out.
|
||||
Future<void> _checkSingleFileChanges(String content, String expected,
|
||||
Future<void> _checkSingleFileChanges(String content, dynamic expected,
|
||||
{Map<String, String> migratedInput = const {},
|
||||
bool removeViaComments = false,
|
||||
bool warnOnWeakCode = false,
|
||||
|
@ -1164,6 +1164,41 @@ void main() {
|
|||
await _checkSingleFileChanges(content, expected);
|
||||
}
|
||||
|
||||
Future<void> test_constructor_field_formal_resolves_to_getter() async {
|
||||
var content = '''
|
||||
class C {
|
||||
int get i => 0;
|
||||
C(this.i);
|
||||
}
|
||||
''';
|
||||
// It doesn't matter what the migration produces; we just want to make sure
|
||||
// there isn't a crash.
|
||||
await _checkSingleFileChanges(content, anything, allowErrors: true);
|
||||
}
|
||||
|
||||
Future<void> test_constructor_field_formal_resolves_to_setter() async {
|
||||
var content = '''
|
||||
class C {
|
||||
set i(int value) {}
|
||||
C(this.i);
|
||||
}
|
||||
''';
|
||||
// It doesn't matter what the migration produces; we just want to make sure
|
||||
// there isn't a crash.
|
||||
await _checkSingleFileChanges(content, anything, allowErrors: true);
|
||||
}
|
||||
|
||||
Future<void> test_constructor_field_formal_unresolved() async {
|
||||
var content = '''
|
||||
class C {
|
||||
C(this.i);
|
||||
}
|
||||
''';
|
||||
// It doesn't matter what the migration produces; we just want to make sure
|
||||
// there isn't a crash.
|
||||
await _checkSingleFileChanges(content, anything, allowErrors: true);
|
||||
}
|
||||
|
||||
Future<void> test_constructor_optional_param_factory() async {
|
||||
var content = '''
|
||||
class C {
|
||||
|
|
Loading…
Reference in a new issue