@@ -29,66 +29,13 @@ class AddExplicitCast extends ResolvedCorrectionProducer {
2929
3030 @override
3131 Future <void > compute (ChangeBuilder builder) async {
32- var target = coveringNode ;
33- if (target is ! Expression ) {
32+ var targetAndTypes = _computeTargetAndTypes () ;
33+ if (targetAndTypes == null ) {
3434 return ;
3535 }
3636
37- var fromType = target.staticType;
38- if (fromType == null ) {
39- return ;
40- }
37+ var (: target, : fromType, : toType) = targetAndTypes;
4138
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- }
9239 if (target is AsExpression ) {
9340 var type = target.type;
9441 await builder.addDartFileEdit (file, (builder) {
@@ -99,72 +46,68 @@ class AddExplicitCast extends ResolvedCorrectionProducer {
9946 return ;
10047 }
10148
102- var target_final = target;
103-
10449 var needsParentheses = target.precedence < Precedence .postfix;
10550 if (toType is InterfaceType &&
10651 (fromType.isDartCoreIterable ||
10752 fromType.isDartCoreList ||
10853 fromType.isDartCoreSet) &&
10954 (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;
11357 if (typeArguments != null ) {
11458 await builder.addDartFileEdit (file, (builder) {
115- _replaceTypeArgument (builder, typeArguments, toType_final , 0 );
59+ _replaceTypeArgument (builder, typeArguments, toType , 0 );
11660 });
11761 }
11862 return ;
11963 }
12064 await builder.addDartFileEdit (file, (builder) {
12165 if (needsParentheses) {
122- builder.addSimpleInsertion (target_final .offset, '(' );
66+ builder.addSimpleInsertion (target .offset, '(' );
12367 }
124- builder.addInsertion (target_final .end, (builder) {
68+ builder.addInsertion (target .end, (builder) {
12569 if (needsParentheses) {
12670 builder.write (')' );
12771 }
12872 builder.write ('.cast<' );
129- builder.writeType (toType_final .typeArguments[0 ]);
73+ builder.writeType (toType .typeArguments[0 ]);
13074 builder.write ('>()' );
13175 });
13276 });
13377 } else if (fromType.isDartCoreMap &&
13478 toType is InterfaceType &&
13579 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;
13982 if (typeArguments != null ) {
14083 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 );
14386 });
14487 }
14588 return ;
14689 }
14790 await builder.addDartFileEdit (file, (builder) {
14891 if (needsParentheses) {
149- builder.addSimpleInsertion (target_final .offset, '(' );
92+ builder.addSimpleInsertion (target .offset, '(' );
15093 }
151- builder.addInsertion (target_final .end, (builder) {
94+ builder.addInsertion (target .end, (builder) {
15295 if (needsParentheses) {
15396 builder.write (')' );
15497 }
15598 builder.write ('.cast<' );
156- builder.writeType (toType_final .typeArguments[0 ]);
99+ builder.writeType (toType .typeArguments[0 ]);
157100 builder.write (', ' );
158- builder.writeType (toType_final .typeArguments[1 ]);
101+ builder.writeType (toType .typeArguments[1 ]);
159102 builder.write ('>()' );
160103 });
161104 });
162105 } else {
163106 await builder.addDartFileEdit (file, (builder) {
164107 if (needsParentheses) {
165- builder.addSimpleInsertion (target_final .offset, '(' );
108+ builder.addSimpleInsertion (target .offset, '(' );
166109 }
167- builder.addInsertion (target_final .end, (builder) {
110+ builder.addInsertion (target .end, (builder) {
168111 if (needsParentheses) {
169112 builder.write (')' );
170113 }
@@ -175,6 +118,78 @@ class AddExplicitCast extends ResolvedCorrectionProducer {
175118 }
176119 }
177120
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+
178193 /// Replace the type argument of [typeArguments] at the specified [index]
179194 /// with the corresponding type argument of [toType] .
180195 void _replaceTypeArgument (
0 commit comments