From ec6dfd4019461d14da0c44652cf01f84fbf7089c Mon Sep 17 00:00:00 2001 From: Honza Bittner Date: Mon, 21 Oct 2024 15:04:57 +0000 Subject: [PATCH] fix: joining if-cases Closes https://github.com/dart-lang/sdk/pull/56920 GitOrigin-RevId: 4e9075cacc6d4af73775aae1d42ee6fde4377b4e Change-Id: I8873082cc993de8b65191d02537f8199dd4fc68c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/390632 Commit-Queue: Phil Quitslund Commit-Queue: Brian Wilkerson Reviewed-by: Brian Wilkerson Reviewed-by: Phil Quitslund --- .../correction/dart/join_if_with_inner.dart | 29 ++++ .../correction/dart/join_if_with_outer.dart | 29 ++++ .../assist/join_if_with_inner_test.dart | 127 ++++++++++++++++++ .../assist/join_if_with_outer_test.dart | 127 ++++++++++++++++++ 4 files changed, 312 insertions(+) diff --git a/pkg/analysis_server/lib/src/services/correction/dart/join_if_with_inner.dart b/pkg/analysis_server/lib/src/services/correction/dart/join_if_with_inner.dart index 3318bc350b7..4adfcc2e492 100644 --- a/pkg/analysis_server/lib/src/services/correction/dart/join_if_with_inner.dart +++ b/pkg/analysis_server/lib/src/services/correction/dart/join_if_with_inner.dart @@ -42,6 +42,12 @@ class JoinIfWithInner extends ResolvedCorrectionProducer { if (innerIfStatement.elseStatement != null) { return; } + + // If inner is if-case, we cannot join them. + if (innerIfStatement.caseClause != null) { + return; + } + // prepare environment var prefix = utils.getNodePrefix(targetIfStatement); // merge conditions @@ -55,7 +61,30 @@ class JoinIfWithInner extends ResolvedCorrectionProducer { if (innerCondition.shouldWrapParenthesisBeforeAnd) { innerConditionSource = '($innerConditionSource)'; } + var condition = '$targetConditionSource && $innerConditionSource'; + + // If outer is if-case. + var outerCaseClause = targetIfStatement.caseClause; + if (outerCaseClause != null) { + var casePattern = outerCaseClause.guardedPattern.pattern; + var caseWhenExpression = + outerCaseClause.guardedPattern.whenClause?.expression; + + if (caseWhenExpression != null) { + var caseWhenSource = '$caseWhenExpression'; + if (caseWhenExpression.shouldWrapParenthesisBeforeAnd) { + caseWhenSource = '($caseWhenSource)'; + } + + condition = + '$targetConditionSource case $casePattern when $caseWhenSource && $innerConditionSource'; + } else { + condition = + '$targetConditionSource case $casePattern when $innerConditionSource'; + } + } + // replace target "if" statement var innerThenStatement = innerIfStatement.thenStatement; var innerThenStatements = getStatements(innerThenStatement); diff --git a/pkg/analysis_server/lib/src/services/correction/dart/join_if_with_outer.dart b/pkg/analysis_server/lib/src/services/correction/dart/join_if_with_outer.dart index c863811f6c6..59acee8ca9c 100644 --- a/pkg/analysis_server/lib/src/services/correction/dart/join_if_with_outer.dart +++ b/pkg/analysis_server/lib/src/services/correction/dart/join_if_with_outer.dart @@ -48,6 +48,12 @@ class JoinIfWithOuter extends ResolvedCorrectionProducer { if (outerIfStatement.elseStatement != null) { return; } + + // If target (inner) is if-case, we cannot join them. + if (targetIfStatement.caseClause != null) { + return; + } + // prepare environment var prefix = utils.getNodePrefix(outerIfStatement); // merge conditions @@ -61,7 +67,30 @@ class JoinIfWithOuter extends ResolvedCorrectionProducer { if (outerCondition.shouldWrapParenthesisBeforeAnd) { outerConditionSource = '($outerConditionSource)'; } + var condition = '$outerConditionSource && $targetConditionSource'; + + // If outer is if-case. + var outerCaseClause = outerIfStatement.caseClause; + if (outerCaseClause != null) { + var casePattern = outerCaseClause.guardedPattern.pattern; + var caseWhenExpression = + outerCaseClause.guardedPattern.whenClause?.expression; + + if (caseWhenExpression != null) { + var caseWhenSource = '$caseWhenExpression'; + if (caseWhenExpression.shouldWrapParenthesisBeforeAnd) { + caseWhenSource = '($caseWhenSource)'; + } + + condition = + '$outerConditionSource case $casePattern when $caseWhenSource && $targetConditionSource'; + } else { + condition = + '$outerConditionSource case $casePattern when $targetConditionSource'; + } + } + // replace outer "if" statement var targetThenStatement = targetIfStatement.thenStatement; var targetThenStatements = getStatements(targetThenStatement); diff --git a/pkg/analysis_server/test/src/services/correction/assist/join_if_with_inner_test.dart b/pkg/analysis_server/test/src/services/correction/assist/join_if_with_inner_test.dart index c24a5983081..60819034312 100644 --- a/pkg/analysis_server/test/src/services/correction/assist/join_if_with_inner_test.dart +++ b/pkg/analysis_server/test/src/services/correction/assist/join_if_with_inner_test.dart @@ -19,6 +19,19 @@ class JoinIfWithInnerTest extends AssistProcessorTest { @override AssistKind get kind => DartAssistKind.JOIN_IF_WITH_INNER; + Future test_bothOuterAndInnerAreIfCase() async { + await resolveTestCode(''' +void f(Object? p) { + if (p case final v?) { + if (v case final int x) { + print(0); + } + } +} +'''); + await assertNoAssistAt('if (p'); + } + Future test_conditionAndOr() async { await resolveTestCode(''' void f() { @@ -78,6 +91,120 @@ void f() { '''); } + Future test_ifCaseAddWhen() async { + await resolveTestCode(''' +void f(Object? p) { + if (p case final int v) { + if (v == 5) { + print(0); + } + } +} +'''); + await assertHasAssistAt('if (p', ''' +void f(Object? p) { + if (p case final int v when v == 5) { + print(0); + } +} +'''); + } + + Future test_ifCaseAddWhenUnrelated() async { + await resolveTestCode(''' +void f(Object? p, Object? q) { + if (p case final int v) { + if (q != null) { + print(0); + } + } +} +'''); + await assertHasAssistAt('if (p', ''' +void f(Object? p, Object? q) { + if (p case final int v when q != null) { + print(0); + } +} +'''); + } + + Future test_ifCaseAppendWhen() async { + await resolveTestCode(''' +void f(Object? p) { + if (p case final int v when v.isOdd) { + if (v == 5) { + print(0); + } + } +} +'''); + await assertHasAssistAt('if (p', ''' +void f(Object? p) { + if (p case final int v when v.isOdd && v == 5) { + print(0); + } +} +'''); + } + + Future test_ifCaseAppendWhenWithParenthesisBoth() async { + await resolveTestCode(''' +void f(Object? p) { + if (p case final int v when v.isOdd || v > 3) { + if (v == 5 || v != 6) { + print(0); + } + } +} +'''); + await assertHasAssistAt('if (p', ''' +void f(Object? p) { + if (p case final int v when (v.isOdd || v > 3) && (v == 5 || v != 6)) { + print(0); + } +} +'''); + } + + Future test_ifCaseAppendWhenWithParenthesisInner() async { + await resolveTestCode(''' +void f(Object? p) { + if (p case final int v when v.isOdd) { + if (v == 5 || v != 3) { + print(0); + } + } +} +'''); + await assertHasAssistAt('if (p', ''' +void f(Object? p) { + if (p case final int v when v.isOdd && (v == 5 || v != 3)) { + print(0); + } +} +'''); + } + + Future test_ifCaseAppendWhenWithParenthesisOuter() async { + await resolveTestCode(''' +void f(Object? p) { + if (p case final int v when v.isOdd || v != 3) { + if (v == 5) { + print(0); + } + } +} +'''); + await assertHasAssistAt('if (p', ''' +void f(Object? p) { + if (p case final int v when (v.isOdd || v != 3) && v == 5) { + print(0); + } +} +'''); + } + Future test_innerNotIf() async { await resolveTestCode(''' void f() { diff --git a/pkg/analysis_server/test/src/services/correction/assist/join_if_with_outer_test.dart b/pkg/analysis_server/test/src/services/correction/assist/join_if_with_outer_test.dart index 54860825957..824df47e83f 100644 --- a/pkg/analysis_server/test/src/services/correction/assist/join_if_with_outer_test.dart +++ b/pkg/analysis_server/test/src/services/correction/assist/join_if_with_outer_test.dart @@ -19,6 +19,19 @@ class JoinIfWithOuterTest extends AssistProcessorTest { @override AssistKind get kind => DartAssistKind.JOIN_IF_WITH_OUTER; + Future test_bothOuterAndInnerAreIfCase() async { + await resolveTestCode(''' +void f(Object? p) { + if (p case final v?) { + if (v case final int x) { + print(x); + } + } +} +'''); + await assertNoAssistAt('if (v'); + } + Future test_conditionAndOr() async { await resolveTestCode(''' void f() { @@ -78,6 +91,120 @@ void f() { '''); } + Future test_ifCaseAddWhen() async { + await resolveTestCode(''' +void f(Object? p) { + if (p case final int v) { + if (v == 5) { + print(0); + } + } +} +'''); + await assertHasAssistAt('if (v == 5', ''' +void f(Object? p) { + if (p case final int v when v == 5) { + print(0); + } +} +'''); + } + + Future test_ifCaseAddWhenUnrelated() async { + await resolveTestCode(''' +void f(Object? p, Object? q) { + if (p case final int v) { + if (q != null) { + print(0); + } + } +} +'''); + await assertHasAssistAt('if (q != null', ''' +void f(Object? p, Object? q) { + if (p case final int v when q != null) { + print(0); + } +} +'''); + } + + Future test_ifCaseAppendWhen() async { + await resolveTestCode(''' +void f(Object? p) { + if (p case final int v when v.isOdd) { + if (v == 5) { + print(0); + } + } +} +'''); + await assertHasAssistAt('if (v == 5', ''' +void f(Object? p) { + if (p case final int v when v.isOdd && v == 5) { + print(0); + } +} +'''); + } + + Future test_ifCaseAppendWhenWithParenthesisBoth() async { + await resolveTestCode(''' +void f(Object? p) { + if (p case final int v when v.isOdd || v > 3) { + if (v == 5 || v != 6) { + print(0); + } + } +} +'''); + await assertHasAssistAt('if (v', ''' +void f(Object? p) { + if (p case final int v when (v.isOdd || v > 3) && (v == 5 || v != 6)) { + print(0); + } +} +'''); + } + + Future test_ifCaseAppendWhenWithParenthesisInner() async { + await resolveTestCode(''' +void f(Object? p) { + if (p case final int v when v.isOdd) { + if (v == 5 || v != 3) { + print(0); + } + } +} +'''); + await assertHasAssistAt('if (v', ''' +void f(Object? p) { + if (p case final int v when v.isOdd && (v == 5 || v != 3)) { + print(0); + } +} +'''); + } + + Future test_ifCaseAppendWhenWithParenthesisOuter() async { + await resolveTestCode(''' +void f(Object? p) { + if (p case final int v when v.isOdd || v != 3) { + if (v == 5) { + print(0); + } + } +} +'''); + await assertHasAssistAt('if (v', ''' +void f(Object? p) { + if (p case final int v when (v.isOdd || v != 3) && v == 5) { + print(0); + } +} +'''); + } + Future test_onCondition() async { await resolveTestCode(''' void f() {