@@ -29,66 +29,13 @@ class AddExplicitCast extends ResolvedCorrectionProducer {
29
29
30
30
@override
31
31
Future <void > compute (ChangeBuilder builder) async {
32
- var target = coveringNode ;
33
- if (target is ! Expression ) {
32
+ var targetAndTypes = _computeTargetAndTypes () ;
33
+ if (targetAndTypes == null ) {
34
34
return ;
35
35
}
36
36
37
- var fromType = target.staticType;
38
- if (fromType == null ) {
39
- return ;
40
- }
37
+ var (: target, : fromType, : toType) = targetAndTypes;
41
38
42
- if (fromType == typeProvider.nullType) {
43
- // There would only be a diagnostic if the `toType` is not nullable, in
44
- // which case a cast won't fix the problem.
45
- return ;
46
- }
47
- DartType toType;
48
- var parent = target.parent;
49
- if (parent is CascadeExpression && target == parent.target) {
50
- target = parent;
51
- parent = target.parent;
52
- }
53
- if (parent is AssignmentExpression && target == parent.rightHandSide) {
54
- toType = parent.writeType! ;
55
- } else if (parent is VariableDeclaration && target == parent.initializer) {
56
- if (parent.declaredElement2 case var declaredElement? ) {
57
- toType = declaredElement.type;
58
- } else if (parent.declaredFragment case var declaredFragment? ) {
59
- toType = declaredFragment.element.type;
60
- } else {
61
- return ;
62
- }
63
- } else if (parent is ArgumentList ) {
64
- var staticType = target.correspondingParameter? .type;
65
- if (staticType == null ) return ;
66
- toType = staticType;
67
- } else {
68
- return ;
69
- }
70
- if (typeSystem.isAssignableTo (
71
- toType,
72
- typeSystem.promoteToNonNull (fromType),
73
- strictCasts: analysisOptions.strictCasts,
74
- )) {
75
- // The only reason that `fromType` can't be assigned to `toType` is
76
- // because it's nullable, in which case a cast won't fix the problem.
77
- return ;
78
- }
79
- if (target.isToListMethodInvocation || target.isToSetMethodInvocation) {
80
- var targetTarget = (target as MethodInvocation ).target;
81
- if (targetTarget != null ) {
82
- var targetTargetType = targetTarget.typeOrThrow;
83
- if (targetTargetType.isDartCoreIterable ||
84
- targetTargetType.isDartCoreList ||
85
- targetTargetType.isDartCoreMap ||
86
- targetTargetType.isDartCoreSet) {
87
- target = targetTarget;
88
- fromType = targetTargetType;
89
- }
90
- }
91
- }
92
39
if (target is AsExpression ) {
93
40
var type = target.type;
94
41
await builder.addDartFileEdit (file, (builder) {
@@ -99,72 +46,68 @@ class AddExplicitCast extends ResolvedCorrectionProducer {
99
46
return ;
100
47
}
101
48
102
- var target_final = target;
103
-
104
49
var needsParentheses = target.precedence < Precedence .postfix;
105
50
if (toType is InterfaceType &&
106
51
(fromType.isDartCoreIterable ||
107
52
fromType.isDartCoreList ||
108
53
fromType.isDartCoreSet) &&
109
54
(toType.isDartCoreList || toType.isDartCoreSet)) {
110
- var toType_final = toType;
111
- if (target.isCastMethodInvocation) {
112
- var typeArguments = (target as MethodInvocation ).typeArguments;
55
+ if (target is MethodInvocation && target.isCastMethodInvocation) {
56
+ var typeArguments = target.typeArguments;
113
57
if (typeArguments != null ) {
114
58
await builder.addDartFileEdit (file, (builder) {
115
- _replaceTypeArgument (builder, typeArguments, toType_final , 0 );
59
+ _replaceTypeArgument (builder, typeArguments, toType , 0 );
116
60
});
117
61
}
118
62
return ;
119
63
}
120
64
await builder.addDartFileEdit (file, (builder) {
121
65
if (needsParentheses) {
122
- builder.addSimpleInsertion (target_final .offset, '(' );
66
+ builder.addSimpleInsertion (target .offset, '(' );
123
67
}
124
- builder.addInsertion (target_final .end, (builder) {
68
+ builder.addInsertion (target .end, (builder) {
125
69
if (needsParentheses) {
126
70
builder.write (')' );
127
71
}
128
72
builder.write ('.cast<' );
129
- builder.writeType (toType_final .typeArguments[0 ]);
73
+ builder.writeType (toType .typeArguments[0 ]);
130
74
builder.write ('>()' );
131
75
});
132
76
});
133
77
} else if (fromType.isDartCoreMap &&
134
78
toType is InterfaceType &&
135
79
toType.isDartCoreMap) {
136
- var toType_final = toType;
137
- if (target.isCastMethodInvocation) {
138
- var typeArguments = (target as MethodInvocation ).typeArguments;
80
+ if (target is MethodInvocation && target.isCastMethodInvocation) {
81
+ var typeArguments = target.typeArguments;
139
82
if (typeArguments != null ) {
140
83
await builder.addDartFileEdit (file, (builder) {
141
- _replaceTypeArgument (builder, typeArguments, toType_final , 0 );
142
- _replaceTypeArgument (builder, typeArguments, toType_final , 1 );
84
+ _replaceTypeArgument (builder, typeArguments, toType , 0 );
85
+ _replaceTypeArgument (builder, typeArguments, toType , 1 );
143
86
});
144
87
}
145
88
return ;
146
89
}
147
90
await builder.addDartFileEdit (file, (builder) {
148
91
if (needsParentheses) {
149
- builder.addSimpleInsertion (target_final .offset, '(' );
92
+ builder.addSimpleInsertion (target .offset, '(' );
150
93
}
151
- builder.addInsertion (target_final .end, (builder) {
94
+ builder.addInsertion (target .end, (builder) {
152
95
if (needsParentheses) {
153
96
builder.write (')' );
154
97
}
155
98
builder.write ('.cast<' );
156
- builder.writeType (toType_final .typeArguments[0 ]);
99
+ builder.writeType (toType .typeArguments[0 ]);
157
100
builder.write (', ' );
158
- builder.writeType (toType_final .typeArguments[1 ]);
101
+ builder.writeType (toType .typeArguments[1 ]);
159
102
builder.write ('>()' );
160
103
});
161
104
});
162
105
} else {
163
106
await builder.addDartFileEdit (file, (builder) {
164
107
if (needsParentheses) {
165
- builder.addSimpleInsertion (target_final .offset, '(' );
108
+ builder.addSimpleInsertion (target .offset, '(' );
166
109
}
167
- builder.addInsertion (target_final .end, (builder) {
110
+ builder.addInsertion (target .end, (builder) {
168
111
if (needsParentheses) {
169
112
builder.write (')' );
170
113
}
@@ -175,6 +118,78 @@ class AddExplicitCast extends ResolvedCorrectionProducer {
175
118
}
176
119
}
177
120
121
+ /// Computes the target [Expression] , the "from" [DartType] , and the "to"
122
+ /// [DartType] for various types of casts.
123
+ ///
124
+ /// A `null` return value means these values cannot be computed, and a
125
+ /// correction cannot be made.
126
+ ({Expression target, DartType fromType, DartType toType})?
127
+ _computeTargetAndTypes () {
128
+ var target = coveringNode;
129
+ if (target is ! Expression ) {
130
+ return null ;
131
+ }
132
+
133
+ var fromType = target.staticType;
134
+ if (fromType == null ) {
135
+ return null ;
136
+ }
137
+
138
+ if (fromType == typeProvider.nullType) {
139
+ // There would only be a diagnostic if the `toType` is not nullable, in
140
+ // which case a cast won't fix the problem.
141
+ return null ;
142
+ }
143
+ DartType toType;
144
+ var parent = target.parent;
145
+ if (parent is CascadeExpression && target == parent.target) {
146
+ target = parent;
147
+ parent = target.parent;
148
+ }
149
+ if (parent is AssignmentExpression && target == parent.rightHandSide) {
150
+ toType = parent.writeType! ;
151
+ } else if (parent is VariableDeclaration && target == parent.initializer) {
152
+ if (parent.declaredElement2 case var declaredElement? ) {
153
+ toType = declaredElement.type;
154
+ } else if (parent.declaredFragment case var declaredFragment? ) {
155
+ toType = declaredFragment.element.type;
156
+ } else {
157
+ return null ;
158
+ }
159
+ } else if (parent is ArgumentList ) {
160
+ var staticType = target.correspondingParameter? .type;
161
+ if (staticType == null ) return null ;
162
+ toType = staticType;
163
+ } else {
164
+ return null ;
165
+ }
166
+ if (typeSystem.isAssignableTo (
167
+ toType,
168
+ typeSystem.promoteToNonNull (fromType),
169
+ strictCasts: analysisOptions.strictCasts,
170
+ )) {
171
+ // The only reason that `fromType` can't be assigned to `toType` is
172
+ // because it's nullable, in which case a cast won't fix the problem.
173
+ return null ;
174
+ }
175
+ if (target is MethodInvocation &&
176
+ (target.isToListMethodInvocation || target.isToSetMethodInvocation)) {
177
+ var targetTarget = target.target;
178
+ if (targetTarget != null ) {
179
+ var targetTargetType = targetTarget.typeOrThrow;
180
+ if (targetTargetType.isDartCoreIterable ||
181
+ targetTargetType.isDartCoreList ||
182
+ targetTargetType.isDartCoreMap ||
183
+ targetTargetType.isDartCoreSet) {
184
+ target = targetTarget;
185
+ fromType = targetTargetType;
186
+ }
187
+ }
188
+ }
189
+
190
+ return (target: target, fromType: fromType, toType: toType);
191
+ }
192
+
178
193
/// Replace the type argument of [typeArguments] at the specified [index]
179
194
/// with the corresponding type argument of [toType] .
180
195
void _replaceTypeArgument (
0 commit comments