mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 18:16:04 +00:00
Issue 52146. Fix ConvertToIfCaseStatementChain for a case without statements.
Bug: https://github.com/dart-lang/sdk/issues/52146 Change-Id: I2947111a0e1a4c6e739bda851f1f91c9637a745a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/297420 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Phil Quitslund <pquitslund@google.com>
This commit is contained in:
parent
d3460e0855
commit
2cdfc05568
|
@ -5,6 +5,7 @@
|
|||
import 'package:analysis_server/src/services/correction/assist.dart';
|
||||
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
|
||||
import 'package:analyzer/dart/ast/ast.dart';
|
||||
import 'package:analyzer/src/dart/ast/ast.dart';
|
||||
import 'package:analyzer_plugin/utilities/assist/assist.dart';
|
||||
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
|
||||
import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
|
||||
|
@ -18,50 +19,43 @@ class ConvertToIfCaseStatementChain extends CorrectionProducer {
|
|||
@override
|
||||
Future<void> compute(ChangeBuilder builder) async {
|
||||
final switchStatement = node;
|
||||
if (switchStatement is! SwitchStatement) {
|
||||
if (switchStatement is! SwitchStatementImpl) {
|
||||
return;
|
||||
}
|
||||
|
||||
final groups = _groups(switchStatement);
|
||||
if (groups == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ifIndent = utils.getLinePrefix(switchStatement.offset);
|
||||
final expressionCode = utils.getNodeText(switchStatement.expression);
|
||||
|
||||
final switchPatternCases = <SwitchPatternCase>[];
|
||||
SwitchDefault? defaultCase;
|
||||
for (final member in switchStatement.members) {
|
||||
switch (member) {
|
||||
case SwitchPatternCase():
|
||||
switchPatternCases.add(member);
|
||||
case SwitchDefault():
|
||||
defaultCase = member;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await builder.addDartFileEdit(file, (builder) {
|
||||
builder.addReplacement(range.node(switchStatement), (builder) {
|
||||
var isFirst = true;
|
||||
for (final case_ in switchPatternCases) {
|
||||
for (final group in groups) {
|
||||
if (isFirst) {
|
||||
isFirst = false;
|
||||
} else {
|
||||
builder.write(' else ');
|
||||
}
|
||||
final patternCode = utils.getNodeText(case_.guardedPattern);
|
||||
builder.writeln('if ($expressionCode case $patternCode) {');
|
||||
switch (group) {
|
||||
case _SingleCaseGroup():
|
||||
final patternCode = utils.getNodeText(group.guardedPattern);
|
||||
builder.writeln('if ($expressionCode case $patternCode) {');
|
||||
case _JoinedCaseGroup():
|
||||
final patternCode = group.patterns
|
||||
.map((pattern) => utils.getNodeText(pattern))
|
||||
.join(' || ');
|
||||
builder.writeln('if ($expressionCode case $patternCode) {');
|
||||
case _DefaultGroup():
|
||||
builder.writeln('{');
|
||||
}
|
||||
_writeStatements(
|
||||
builder: builder,
|
||||
blockIndent: ifIndent,
|
||||
statements: case_.statements,
|
||||
);
|
||||
builder.write('$ifIndent}');
|
||||
}
|
||||
if (defaultCase case final defaultCase?) {
|
||||
builder.writeln(' else {');
|
||||
_writeStatements(
|
||||
builder: builder,
|
||||
blockIndent: ifIndent,
|
||||
statements: defaultCase.statements,
|
||||
statements: group.statements,
|
||||
);
|
||||
builder.write('$ifIndent}');
|
||||
}
|
||||
|
@ -69,14 +63,72 @@ class ConvertToIfCaseStatementChain extends CorrectionProducer {
|
|||
});
|
||||
}
|
||||
|
||||
List<_Group>? _groups(SwitchStatementImpl switchStatement) {
|
||||
final result = <_Group>[];
|
||||
for (final group in switchStatement.memberGroups) {
|
||||
final members = group.members;
|
||||
|
||||
// Support `default`, if alone.
|
||||
if (members.any((e) => e is SwitchDefault)) {
|
||||
if (members.length != 1) {
|
||||
return null;
|
||||
}
|
||||
result.add(
|
||||
_DefaultGroup(
|
||||
statements: group.statements,
|
||||
),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// We expect only `SwitchPatternCase`s.
|
||||
final guardedPatterns = members
|
||||
.whereType<SwitchPatternCase>()
|
||||
.map((e) => e.guardedPattern)
|
||||
.toList();
|
||||
if (guardedPatterns.length != members.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// For single `GuardedPattern` we allow `when`.
|
||||
final singleGuardedPattern = guardedPatterns.singleOrNull;
|
||||
if (singleGuardedPattern != null) {
|
||||
result.add(
|
||||
_SingleCaseGroup(
|
||||
guardedPattern: singleGuardedPattern,
|
||||
statements: group.statements,
|
||||
),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// For joined `GuardedPattern`s, we cannot support any `when`.
|
||||
if (guardedPatterns.hasWhen) {
|
||||
return null;
|
||||
}
|
||||
|
||||
result.add(
|
||||
_JoinedCaseGroup(
|
||||
patterns: guardedPatterns.map((e) => e.pattern).toList(),
|
||||
statements: group.statements,
|
||||
),
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void _writeStatements({
|
||||
required DartEditBuilder builder,
|
||||
required List<Statement> statements,
|
||||
required String blockIndent,
|
||||
}) {
|
||||
final range = utils.getLinesRangeStatements(statements);
|
||||
final first = statements.firstOrNull;
|
||||
if (first == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final firstIndent = utils.getLinePrefix(statements.first.offset);
|
||||
final range = utils.getLinesRangeStatements(statements);
|
||||
final firstIndent = utils.getLinePrefix(first.offset);
|
||||
final singleIndent = utils.getIndent(1);
|
||||
|
||||
final code = utils.replaceSourceRangeIndent(
|
||||
|
@ -87,3 +139,41 @@ class ConvertToIfCaseStatementChain extends CorrectionProducer {
|
|||
builder.write(code);
|
||||
}
|
||||
}
|
||||
|
||||
class _DefaultGroup extends _Group {
|
||||
_DefaultGroup({
|
||||
required super.statements,
|
||||
});
|
||||
}
|
||||
|
||||
sealed class _Group {
|
||||
final List<Statement> statements;
|
||||
|
||||
_Group({
|
||||
required this.statements,
|
||||
});
|
||||
}
|
||||
|
||||
/// Joined [Pattern]s, without `when`, before statements.
|
||||
class _JoinedCaseGroup extends _Group {
|
||||
final List<DartPattern> patterns;
|
||||
|
||||
_JoinedCaseGroup({
|
||||
required this.patterns,
|
||||
required super.statements,
|
||||
});
|
||||
}
|
||||
|
||||
/// A single [GuardedPattern] before statements.
|
||||
class _SingleCaseGroup extends _Group {
|
||||
final GuardedPattern guardedPattern;
|
||||
|
||||
_SingleCaseGroup({
|
||||
required this.guardedPattern,
|
||||
required super.statements,
|
||||
});
|
||||
}
|
||||
|
||||
extension on List<GuardedPattern> {
|
||||
bool get hasWhen => any((e) => e.whenClause != null);
|
||||
}
|
||||
|
|
|
@ -41,6 +41,80 @@ void f(Object? x) {
|
|||
''');
|
||||
}
|
||||
|
||||
Future<void> test_noDefault_hasWhen() async {
|
||||
await resolveTestCode('''
|
||||
void f(Object? x) {
|
||||
switch (x) {
|
||||
case int() when x > 0:
|
||||
0;
|
||||
case double():
|
||||
1;
|
||||
}
|
||||
}
|
||||
''');
|
||||
await assertHasAssistAt('switch', '''
|
||||
void f(Object? x) {
|
||||
if (x case int() when x > 0) {
|
||||
0;
|
||||
} else if (x case double()) {
|
||||
1;
|
||||
}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_noStatements() async {
|
||||
await resolveTestCode('''
|
||||
void f(Object? x) {
|
||||
switch (x) {
|
||||
case int():
|
||||
0;
|
||||
case double():
|
||||
}
|
||||
}
|
||||
''');
|
||||
await assertHasAssistAt('switch', '''
|
||||
void f(Object? x) {
|
||||
if (x case int()) {
|
||||
0;
|
||||
} else if (x case double()) {
|
||||
}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_sharedBody() async {
|
||||
await resolveTestCode('''
|
||||
void f(Object? x) {
|
||||
switch (x) {
|
||||
case int():
|
||||
case double():
|
||||
0;
|
||||
}
|
||||
}
|
||||
''');
|
||||
await assertHasAssistAt('switch', '''
|
||||
void f(Object? x) {
|
||||
if (x case int() || double()) {
|
||||
0;
|
||||
}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_sharedBody_hasWhen() async {
|
||||
await resolveTestCode('''
|
||||
void f(Object? x) {
|
||||
switch (x) {
|
||||
case int() when x > 0:
|
||||
case double():
|
||||
0;
|
||||
}
|
||||
}
|
||||
''');
|
||||
await assertNoAssistAt('switch');
|
||||
}
|
||||
|
||||
Future<void> test_withDefault() async {
|
||||
await resolveTestCode('''
|
||||
void f(Object? x) {
|
||||
|
@ -66,4 +140,19 @@ void f(Object? x) {
|
|||
}
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_withDefault_shared() async {
|
||||
await resolveTestCode('''
|
||||
void f(Object? x) {
|
||||
switch (x) {
|
||||
case int():
|
||||
0;
|
||||
case double():
|
||||
default:
|
||||
1;
|
||||
}
|
||||
}
|
||||
''');
|
||||
await assertNoAssistAt('switch');
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue