Skip to content

Commit 166c54b

Browse files
srawlinsCommit Queue
authored and
Commit Queue
committed
analyzer: Mark implicit-casts and implicit-dynamic as deprecated
Also add a fix which replaces 'implicit-casts' with 'strict-casts' and a fix which replaces 'implicit-dynamic' with 'strict-raw-types'. Fixes #47902 This reverts 5050f31 Change-Id: Icd156b0dda78a50ed28272ddef7460018f511cc2 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/276766 Commit-Queue: Samuel Rawlins <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]>
1 parent 778e8d1 commit 166c54b

File tree

17 files changed

+636
-58
lines changed

17 files changed

+636
-58
lines changed

pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ AnalysisOptionsErrorCode.PARSE_ERROR:
4343
AnalysisOptionsHintCode.STRONG_MODE_SETTING_DEPRECATED:
4444
status: needsFix
4545
notes: Fixed.
46+
AnalysisOptionsWarningCode.ANALYSIS_OPTION_DEPRECATED:
47+
status: needsEvaluation
48+
AnalysisOptionsWarningCode.ANALYSIS_OPTION_DEPRECATED_WITH_REPLACEMENT:
49+
status: needsEvaluation
4650
AnalysisOptionsWarningCode.INCLUDE_FILE_NOT_FOUND:
4751
status: noFix
4852
notes: |-

pkg/analysis_server/lib/src/services/correction/fix.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ class AnalysisOptionsFixKind {
4040
50,
4141
"Remove '{0}'",
4242
);
43+
static const REPLACE_WITH_STRICT_CASTS = FixKind(
44+
'analysisOptions.fix.replaceWithStrictCasts',
45+
50,
46+
'Replace with the strict-casts analysis mode',
47+
);
48+
static const REPLACE_WITH_STRICT_RAW_TYPES = FixKind(
49+
'analysisOptions.fix.replaceWithStrictRawTypes',
50+
50,
51+
'Replace with the strict-raw-types analysis mode',
52+
);
4353
}
4454

4555
/// The implementation of [DartFixContext].

pkg/analysis_server/lib/src/services/correction/fix/analysis_options/fix_generator.dart

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@ import 'package:analyzer/src/generated/java_core.dart';
1616
import 'package:analyzer/src/generated/source.dart';
1717
import 'package:analyzer/src/lint/options_rule_validator.dart';
1818
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
19+
import 'package:analyzer_plugin/utilities/change_builder/change_builder_yaml.dart';
1920
import 'package:analyzer_plugin/utilities/change_builder/change_workspace.dart';
2021
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
22+
import 'package:collection/collection.dart';
2123
import 'package:yaml/yaml.dart';
24+
import 'package:yaml_edit/yaml_edit.dart';
2225

2326
/// The generator used to generate fixes in analysis options files.
2427
class AnalysisOptionsFixGenerator {
@@ -64,6 +67,25 @@ class AnalysisOptionsFixGenerator {
6467
// } else
6568
if (errorCode == AnalysisOptionsHintCode.STRONG_MODE_SETTING_DEPRECATED) {
6669
await _addFix_removeSetting(coveringNodePath);
70+
} else if (errorCode ==
71+
AnalysisOptionsWarningCode
72+
.ANALYSIS_OPTION_DEPRECATED_WITH_REPLACEMENT) {
73+
var analyzerMap = options['analyzer'];
74+
if (analyzerMap is! YamlMap) {
75+
return fixes;
76+
}
77+
var strongModeMap = analyzerMap['strong-mode'];
78+
79+
if (strongModeMap is! YamlMap) {
80+
return fixes;
81+
}
82+
if (_isErrorAtMapKey(strongModeMap, 'implicit-casts')) {
83+
await _addFix_replaceWithStrictCasts(
84+
coveringNodePath, analyzerMap, strongModeMap);
85+
} else if (_isErrorAtMapKey(strongModeMap, 'implicit-dynamic')) {
86+
await _addFix_replaceWithStrictRawTypes(
87+
coveringNodePath, analyzerMap, strongModeMap);
88+
}
6789
} else if (errorCode == DEPRECATED_LINT_HINT) {
6890
await _addFix_removeLint(coveringNodePath);
6991
// } else if (errorCode == AnalysisOptionsWarningCode.INCLUDED_FILE_WARNING) {
@@ -101,6 +123,52 @@ class AnalysisOptionsFixGenerator {
101123
}
102124
}
103125

126+
/// Replaces `analyzer: strong-mode: implicit-casts: false` with
127+
/// `analyzer: language: strict-casts: true`.
128+
Future<void> _addFix_replaceWithStrictCasts(List<YamlNode> coveringNodePath,
129+
YamlMap analyzerMap, YamlMap strongModeMap) async {
130+
var builder =
131+
ChangeBuilder(workspace: _NonDartChangeWorkspace(resourceProvider));
132+
await builder.addYamlFileEdit(file, (builder) {
133+
_replaceStrongModeEntryWithLanguageEntry(
134+
builder,
135+
coveringNodePath,
136+
analyzerMap,
137+
strongModeMap,
138+
strongModeKey: 'implicit-casts',
139+
languageKey: 'strict-casts',
140+
languageValue: true,
141+
);
142+
});
143+
_addFixFromBuilder(
144+
builder, AnalysisOptionsFixKind.REPLACE_WITH_STRICT_CASTS,
145+
args: [coveringNodePath[0].toString()]);
146+
}
147+
148+
/// Replaces `analyzer: strong-mode: implicit-dynamic: false` with
149+
/// `analyzer: language: strict-raw-types: true`.
150+
Future<void> _addFix_replaceWithStrictRawTypes(
151+
List<YamlNode> coveringNodePath,
152+
YamlMap analyzerMap,
153+
YamlMap strongModeMap) async {
154+
var builder =
155+
ChangeBuilder(workspace: _NonDartChangeWorkspace(resourceProvider));
156+
await builder.addYamlFileEdit(file, (builder) {
157+
_replaceStrongModeEntryWithLanguageEntry(
158+
builder,
159+
coveringNodePath,
160+
analyzerMap,
161+
strongModeMap,
162+
strongModeKey: 'implicit-dynamic',
163+
languageKey: 'strict-raw-types',
164+
languageValue: true,
165+
);
166+
});
167+
_addFixFromBuilder(
168+
builder, AnalysisOptionsFixKind.REPLACE_WITH_STRICT_RAW_TYPES,
169+
args: [coveringNodePath[0].toString()]);
170+
}
171+
104172
/// Add a fix whose edits were built by the [builder] that has the given
105173
/// [kind]. If [args] are provided, they will be used to fill in the message
106174
/// for the fix.
@@ -184,6 +252,20 @@ class AnalysisOptionsFixGenerator {
184252
return offset;
185253
}
186254

255+
/// Returns whether the error is located within [map], covering the
256+
/// [YamlScalar] node for [key].
257+
bool _isErrorAtMapKey(YamlMap map, String key) {
258+
var keyNode = map.nodes.keys
259+
.whereType<YamlScalar>()
260+
.firstWhereOrNull((k) => k.value == key);
261+
if (keyNode == null) {
262+
return false;
263+
}
264+
var keyOffset = keyNode.span.start.offset;
265+
var keyLength = keyNode.span.end.offset - keyOffset;
266+
return keyOffset == errorOffset && keyLength == errorLength;
267+
}
268+
187269
SourceRange _lines(int start, int end) {
188270
var startLocation = lineInfo.getLocation(start);
189271
var startOffset = lineInfo.getOffsetOfLine(startLocation.lineNumber - 1);
@@ -192,6 +274,53 @@ class AnalysisOptionsFixGenerator {
192274
math.min(endLocation.lineNumber, lineInfo.lineCount - 1));
193275
return SourceRange(startOffset, endOffset - startOffset);
194276
}
277+
278+
/// Replaces a 'strong-mode' entry keyed to [strongModeKey] with a 'language'
279+
/// entry with [languageKey] and [languageValue].
280+
///
281+
/// 'strong-mode' and 'language' are each maps which can be found under the
282+
/// top-level 'analyzer' map. 'strong-mode' (given as [strongModeMap]) must
283+
/// already be present under the 'analyzer' map (given as [analyzerMap]).
284+
void _replaceStrongModeEntryWithLanguageEntry(
285+
YamlFileEditBuilder builder,
286+
List<YamlNode> coveringNodePath,
287+
YamlMap analyzerMap,
288+
YamlMap strongModeMap, {
289+
required String strongModeKey,
290+
required String languageKey,
291+
required Object? languageValue,
292+
}) {
293+
var yamlEditor = YamlEditor(content);
294+
// If 'language' does not exist yet under 'analyzer', create it.
295+
if (analyzerMap['language'] == null) {
296+
yamlEditor.update(['analyzer', 'language'], {languageKey: languageValue});
297+
} else {
298+
yamlEditor.update(['analyzer', 'language', languageKey], languageValue);
299+
}
300+
var languageEdit = yamlEditor.edits.single;
301+
builder.addSimpleReplacement(
302+
SourceRange(languageEdit.offset, languageEdit.length),
303+
languageEdit.replacement);
304+
305+
// If `strongModeKey` is the only entry under 'strong-mode', then remove
306+
// the entire 'strong-mode' entry.
307+
if (strongModeMap.length == 1) {
308+
yamlEditor.remove(['analyzer', 'strong-mode']);
309+
} else {
310+
yamlEditor.remove(['analyzer', 'strong-mode', strongModeKey]);
311+
}
312+
var strongModeEdit = yamlEditor.edits[1];
313+
int strongModeEditOffset;
314+
if (strongModeEdit.offset > languageEdit.offset) {
315+
strongModeEditOffset = strongModeEdit.offset -
316+
(languageEdit.replacement.length - languageEdit.length);
317+
} else {
318+
strongModeEditOffset = strongModeEdit.offset;
319+
}
320+
builder.addSimpleReplacement(
321+
SourceRange(strongModeEditOffset, strongModeEdit.length),
322+
strongModeEdit.replacement);
323+
}
195324
}
196325

197326
class _NonDartChangeWorkspace implements ChangeWorkspace {

pkg/analysis_server/pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ dependencies:
2424
test: any
2525
watcher: any
2626
yaml: any
27+
yaml_edit: any
2728

2829
# Use 'any' constraints here; we get our versions from the DEPS file.
2930
dev_dependencies:

pkg/analysis_server/test/abstract_context.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ class AbstractContextTest with ResourceProviderMixin {
6565

6666
Future<AnalysisSession> get session => sessionFor(testPackageRootPath);
6767

68+
/// The path for `analysis_options.yaml` in [testPackageRootPath].
69+
String get testAnalysisOptionsPath =>
70+
convertPath('$testPackageRootPath/analysis_options.yaml');
71+
6872
String? get testPackageLanguageVersion => latestLanguageVersion;
6973

7074
String get testPackageLibPath => '$testPackageRootPath/lib';

pkg/analysis_server/test/analysis_server_base.dart

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,15 @@ class AnalysisOptionsFileConfig {
5858
buffer.writeln(' strict-casts: $strictCasts');
5959
buffer.writeln(' strict-inference: $strictInference');
6060
buffer.writeln(' strict-raw-types: $strictRawTypes');
61-
buffer.writeln(' strong-mode:');
62-
buffer.writeln(' implicit-casts: $implicitCasts');
63-
buffer.writeln(' implicit-dynamic: $implicitDynamic');
61+
if (!implicitCasts || !implicitDynamic) {
62+
buffer.writeln(' strong-mode:');
63+
if (!implicitCasts) {
64+
buffer.writeln(' implicit-casts: $implicitCasts');
65+
}
66+
if (!implicitDynamic) {
67+
buffer.writeln(' implicit-dynamic: $implicitDynamic');
68+
}
69+
}
6470

6571
buffer.writeln('linter:');
6672
buffer.writeln(' rules:');

pkg/analysis_server/test/client/completion_driver_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ class BasicCompletionTest2 extends AbstractCompletionDriverTest
271271
}
272272

273273
mixin BasicCompletionTestCases on AbstractCompletionDriverTest {
274-
/// Duplicates (and potentially replaces DeprecatedMemberRelevanceTest).
274+
/// Duplicates (and potentially replaces) [DeprecatedMemberRelevanceTest].
275275
Future<void> test_deprecated_member_relevance() async {
276276
await addTestFile('''
277277
class A {

0 commit comments

Comments
 (0)