@@ -16,9 +16,12 @@ import 'package:analyzer/src/generated/java_core.dart';
16
16
import 'package:analyzer/src/generated/source.dart' ;
17
17
import 'package:analyzer/src/lint/options_rule_validator.dart' ;
18
18
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart' ;
19
+ import 'package:analyzer_plugin/utilities/change_builder/change_builder_yaml.dart' ;
19
20
import 'package:analyzer_plugin/utilities/change_builder/change_workspace.dart' ;
20
21
import 'package:analyzer_plugin/utilities/fixes/fixes.dart' ;
22
+ import 'package:collection/collection.dart' ;
21
23
import 'package:yaml/yaml.dart' ;
24
+ import 'package:yaml_edit/yaml_edit.dart' ;
22
25
23
26
/// The generator used to generate fixes in analysis options files.
24
27
class AnalysisOptionsFixGenerator {
@@ -67,7 +70,26 @@ class AnalysisOptionsFixGenerator {
67
70
// AnalysisOptionsHintCode.STRONG_MODE_SETTING_DEPRECATED) {
68
71
// } else
69
72
70
- if (errorCode == DEPRECATED_LINT_HINT ) {
73
+ if (errorCode ==
74
+ AnalysisOptionsWarningCode
75
+ .ANALYSIS_OPTION_DEPRECATED_WITH_REPLACEMENT ) {
76
+ var analyzerMap = options['analyzer' ];
77
+ if (analyzerMap is ! YamlMap ) {
78
+ return fixes;
79
+ }
80
+ var strongModeMap = analyzerMap['strong-mode' ];
81
+
82
+ if (strongModeMap is ! YamlMap ) {
83
+ return fixes;
84
+ }
85
+ if (_isErrorAtMapKey (strongModeMap, 'implicit-casts' )) {
86
+ await _addFix_replaceWithStrictCasts (
87
+ coveringNodePath, analyzerMap, strongModeMap);
88
+ } else if (_isErrorAtMapKey (strongModeMap, 'implicit-dynamic' )) {
89
+ await _addFix_replaceWithStrictRawTypes (
90
+ coveringNodePath, analyzerMap, strongModeMap);
91
+ }
92
+ } else if (errorCode == DEPRECATED_LINT_HINT ) {
71
93
await _addFix_removeLint (coveringNodePath);
72
94
} else if (errorCode ==
73
95
AnalysisOptionsHintCode .SUPER_MIXINS_SETTING_DEPRECATED ) {
@@ -109,6 +131,52 @@ class AnalysisOptionsFixGenerator {
109
131
}
110
132
}
111
133
134
+ /// Replaces `analyzer: strong-mode: implicit-casts: false` with
135
+ /// `analyzer: language: strict-casts: true` .
136
+ Future <void > _addFix_replaceWithStrictCasts (List <YamlNode > coveringNodePath,
137
+ YamlMap analyzerMap, YamlMap strongModeMap) async {
138
+ var builder =
139
+ ChangeBuilder (workspace: _NonDartChangeWorkspace (resourceProvider));
140
+ await builder.addYamlFileEdit (file, (builder) {
141
+ _replaceStrongModeEntryWithLanguageEntry (
142
+ builder,
143
+ coveringNodePath,
144
+ analyzerMap,
145
+ strongModeMap,
146
+ strongModeKey: 'implicit-casts' ,
147
+ languageKey: 'strict-casts' ,
148
+ languageValue: true ,
149
+ );
150
+ });
151
+ _addFixFromBuilder (
152
+ builder, AnalysisOptionsFixKind .REPLACE_WITH_STRICT_CASTS ,
153
+ args: [coveringNodePath[0 ].toString ()]);
154
+ }
155
+
156
+ /// Replaces `analyzer: strong-mode: implicit-dynamic: false` with
157
+ /// `analyzer: language: strict-raw-types: true` .
158
+ Future <void > _addFix_replaceWithStrictRawTypes (
159
+ List <YamlNode > coveringNodePath,
160
+ YamlMap analyzerMap,
161
+ YamlMap strongModeMap) async {
162
+ var builder =
163
+ ChangeBuilder (workspace: _NonDartChangeWorkspace (resourceProvider));
164
+ await builder.addYamlFileEdit (file, (builder) {
165
+ _replaceStrongModeEntryWithLanguageEntry (
166
+ builder,
167
+ coveringNodePath,
168
+ analyzerMap,
169
+ strongModeMap,
170
+ strongModeKey: 'implicit-dynamic' ,
171
+ languageKey: 'strict-raw-types' ,
172
+ languageValue: true ,
173
+ );
174
+ });
175
+ _addFixFromBuilder (
176
+ builder, AnalysisOptionsFixKind .REPLACE_WITH_STRICT_RAW_TYPES ,
177
+ args: [coveringNodePath[0 ].toString ()]);
178
+ }
179
+
112
180
/// Add a fix whose edits were built by the [builder] that has the given
113
181
/// [kind] . If [args] are provided, they will be used to fill in the message
114
182
/// for the fix.
@@ -191,6 +259,20 @@ class AnalysisOptionsFixGenerator {
191
259
return offset;
192
260
}
193
261
262
+ /// Returns whether the error is located within [map] , covering the
263
+ /// [YamlScalar] node for [key] .
264
+ bool _isErrorAtMapKey (YamlMap map, String key) {
265
+ var keyNode = map.nodes.keys
266
+ .whereType <YamlScalar >()
267
+ .firstWhereOrNull ((k) => k.value == key);
268
+ if (keyNode == null ) {
269
+ return false ;
270
+ }
271
+ var keyOffset = keyNode.span.start.offset;
272
+ var keyLength = keyNode.span.end.offset - keyOffset;
273
+ return keyOffset == errorOffset && keyLength == errorLength;
274
+ }
275
+
194
276
SourceRange _lines (int start, int end) {
195
277
var startLocation = lineInfo.getLocation (start);
196
278
var startOffset = lineInfo.getOffsetOfLine (startLocation.lineNumber - 1 );
@@ -199,6 +281,53 @@ class AnalysisOptionsFixGenerator {
199
281
math.min (endLocation.lineNumber, lineInfo.lineCount - 1 ));
200
282
return SourceRange (startOffset, endOffset - startOffset);
201
283
}
284
+
285
+ /// Replaces a 'strong-mode' entry keyed to [strongModeKey] with a 'language'
286
+ /// entry with [languageKey] and [languageValue] .
287
+ ///
288
+ /// 'strong-mode' and 'language' are each maps which can be found under the
289
+ /// top-level 'analyzer' map. 'strong-mode' (given as [strongModeMap] ) must
290
+ /// already be present under the 'analyzer' map (given as [analyzerMap] ).
291
+ void _replaceStrongModeEntryWithLanguageEntry (
292
+ YamlFileEditBuilder builder,
293
+ List <YamlNode > coveringNodePath,
294
+ YamlMap analyzerMap,
295
+ YamlMap strongModeMap, {
296
+ required String strongModeKey,
297
+ required String languageKey,
298
+ required Object ? languageValue,
299
+ }) {
300
+ var yamlEditor = YamlEditor (content);
301
+ // If 'language' does not exist yet under 'analyzer', create it.
302
+ if (analyzerMap['language' ] == null ) {
303
+ yamlEditor.update (['analyzer' , 'language' ], {languageKey: languageValue});
304
+ } else {
305
+ yamlEditor.update (['analyzer' , 'language' , languageKey], languageValue);
306
+ }
307
+ var languageEdit = yamlEditor.edits.single;
308
+ builder.addSimpleReplacement (
309
+ SourceRange (languageEdit.offset, languageEdit.length),
310
+ languageEdit.replacement);
311
+
312
+ // If `strongModeKey` is the only entry under 'strong-mode', then remove
313
+ // the entire 'strong-mode' entry.
314
+ if (strongModeMap.length == 1 ) {
315
+ yamlEditor.remove (['analyzer' , 'strong-mode' ]);
316
+ } else {
317
+ yamlEditor.remove (['analyzer' , 'strong-mode' , strongModeKey]);
318
+ }
319
+ var strongModeEdit = yamlEditor.edits[1 ];
320
+ int strongModeEditOffset;
321
+ if (strongModeEdit.offset > languageEdit.offset) {
322
+ strongModeEditOffset = strongModeEdit.offset -
323
+ (languageEdit.replacement.length - languageEdit.length);
324
+ } else {
325
+ strongModeEditOffset = strongModeEdit.offset;
326
+ }
327
+ builder.addSimpleReplacement (
328
+ SourceRange (strongModeEditOffset, strongModeEdit.length),
329
+ strongModeEdit.replacement);
330
+ }
202
331
}
203
332
204
333
class _NonDartChangeWorkspace implements ChangeWorkspace {
0 commit comments