Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[StatementSwitchToExpressionSwitch] for return switch pattern, if the switch has a default: clause and is otherwise exhaustive (even without said default: clause), then propose an alternative fix which removes the default: clause and its code. #4755

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ public final class StatementSwitchToExpressionSwitch extends BugChecker
AssignmentSwitchAnalysisResult.of(
/* canConvertToAssignmentSwitch= */ false,
/* canCombineWithPrecedingVariableDeclaration= */ false,
/* canRemoveDefault= */ false,
/* assignmentTargetOptional= */ Optional.empty(),
/* assignmentKindOptional= */ Optional.empty(),
/* assignmentSourceCodeOptional= */ Optional.empty());
Expand All @@ -121,11 +120,14 @@ public final class StatementSwitchToExpressionSwitch extends BugChecker
AnalysisResult.of(
/* canConvertDirectlyToExpressionSwitch= */ false,
/* canConvertToReturnSwitch= */ false,
/* canRemoveDefault= */ false,
DEFAULT_ASSIGNMENT_SWITCH_ANALYSIS_RESULT,
/* groupedWithNextCase= */ ImmutableList.of());
private static final String EQUALS_STRING = "=";
private static final Matcher<ExpressionTree> COMPILE_TIME_CONSTANT_MATCHER =
CompileTimeConstantExpressionMatcher.instance();
private static final String REMOVE_DEFAULT_CASE_SHORT_DESCRIPTION =
"Remove default case because all enum values handled";

// Tri-state to represent the fall-thru control flow of a particular case of a particular
// statement switch
Expand Down Expand Up @@ -171,14 +173,20 @@ public Description matchSwitch(SwitchTree switchTree, VisitorState state) {

List<SuggestedFix> suggestedFixes = new ArrayList<>();
if (enableReturnSwitchConversion && analysisResult.canConvertToReturnSwitch()) {
suggestedFixes.add(convertToReturnSwitch(switchTree, state, analysisResult));
suggestedFixes.add(
convertToReturnSwitch(switchTree, state, analysisResult, /* removeDefault= */ false));

if (analysisResult.canRemoveDefault()) {
suggestedFixes.add(
convertToReturnSwitch(switchTree, state, analysisResult, /* removeDefault= */ true));
}
}
if (enableAssignmentSwitchConversion
&& analysisResult.assignmentSwitchAnalysisResult().canConvertToAssignmentSwitch()) {
suggestedFixes.add(
convertToAssignmentSwitch(switchTree, state, analysisResult, /* removeDefault= */ false));

if (analysisResult.assignmentSwitchAnalysisResult().canRemoveDefault()) {
if (analysisResult.canRemoveDefault()) {
suggestedFixes.add(
convertToAssignmentSwitch(
switchTree, state, analysisResult, /* removeDefault= */ true));
Expand Down Expand Up @@ -344,10 +352,10 @@ && isSwitchExhaustiveWithoutDefault(
return AnalysisResult.of(
/* canConvertDirectlyToExpressionSwitch= */ allCasesHaveDefiniteControlFlow,
canConvertToReturnSwitch,
canRemoveDefault,
AssignmentSwitchAnalysisResult.of(
canConvertToAssignmentSwitch,
canCombineWithPrecedingVariableDeclaration,
canRemoveDefault,
assignmentSwitchAnalysisState.assignmentTargetOptional(),
assignmentSwitchAnalysisState.assignmentExpressionKindOptional(),
assignmentSwitchAnalysisState
Expand Down Expand Up @@ -759,7 +767,10 @@ private static SuggestedFix convertDirectlyToExpressionSwitch(
* conversion is possible.
*/
private static SuggestedFix convertToReturnSwitch(
SwitchTree switchTree, VisitorState state, AnalysisResult analysisResult) {
SwitchTree switchTree,
VisitorState state,
AnalysisResult analysisResult,
boolean removeDefault) {

List<StatementTree> statementsToDelete = new ArrayList<>();
List<? extends CaseTree> cases = switchTree.getCases();
Expand All @@ -778,6 +789,10 @@ private static SuggestedFix convertToReturnSwitch(
for (int caseIndex = 0; caseIndex < cases.size(); caseIndex++) {
CaseTree caseTree = cases.get(caseIndex);
boolean isDefaultCase = isSwitchDefault(caseTree);
if (removeDefault && isDefaultCase) {
// Skip default case
continue;
}

String transformedBlockSource =
transformReturnOrThrowBlock(caseTree, state, getStatements(caseTree));
Expand Down Expand Up @@ -849,8 +864,11 @@ private static SuggestedFix convertToReturnSwitch(
// removed.
statementsToDelete.addAll(followingStatementsInBlock(switchTree, state));

SuggestedFix.Builder suggestedFixBuilder =
SuggestedFix.builder().replace(switchTree, replacementCodeBuilder.toString());
SuggestedFix.Builder suggestedFixBuilder = SuggestedFix.builder();
if (removeDefault) {
suggestedFixBuilder.setShortDescription(REMOVE_DEFAULT_CASE_SHORT_DESCRIPTION);
}
suggestedFixBuilder.replace(switchTree, replacementCodeBuilder.toString());
// Delete trailing statements, leaving comments where feasible
statementsToDelete.forEach(deleteMe -> suggestedFixBuilder.replace(deleteMe, ""));
return suggestedFixBuilder.build();
Expand Down Expand Up @@ -1128,8 +1146,7 @@ private static SuggestedFix convertToAssignmentSwitch(

SuggestedFix.Builder suggestedFixBuilder = SuggestedFix.builder();
if (removeDefault) {
suggestedFixBuilder.setShortDescription(
"Remove default case because all enum values handled");
suggestedFixBuilder.setShortDescription(REMOVE_DEFAULT_CASE_SHORT_DESCRIPTION);
}
suggestedFixBuilder.replace(switchTree, replacementCodeBuilder.toString());
statementsToDelete.forEach(deleteMe -> suggestedFixBuilder.replace(deleteMe, ""));
Expand Down Expand Up @@ -1473,6 +1490,12 @@ abstract static class AnalysisResult {
// Whether the statement switch can be converted to a return switch
abstract boolean canConvertToReturnSwitch();

/**
* Whether the assignment switch is exhaustive even in the absence of the default case that
* exists in the original switch statement
*/
abstract boolean canRemoveDefault();

// Results of the analysis for conversion to an assignment switch
abstract AssignmentSwitchAnalysisResult assignmentSwitchAnalysisResult();

Expand All @@ -1482,11 +1505,13 @@ abstract static class AnalysisResult {
static AnalysisResult of(
boolean canConvertDirectlyToExpressionSwitch,
boolean canConvertToReturnSwitch,
boolean canRemoveDefault,
AssignmentSwitchAnalysisResult assignmentSwitchAnalysisResult,
ImmutableList<Boolean> groupedWithNextCase) {
return new AutoValue_StatementSwitchToExpressionSwitch_AnalysisResult(
canConvertDirectlyToExpressionSwitch,
canConvertToReturnSwitch,
canRemoveDefault,
assignmentSwitchAnalysisResult,
groupedWithNextCase);
}
Expand All @@ -1501,10 +1526,6 @@ abstract static class AssignmentSwitchAnalysisResult {
// declaration
abstract boolean canCombineWithPrecedingVariableDeclaration();

// Whether the assignment switch is exhaustive even in the absence of the default case that
// exists in the original switch statement
abstract boolean canRemoveDefault();

// Target of the assignment switch, if any
abstract Optional<ExpressionTree> assignmentTargetOptional();

Expand All @@ -1517,14 +1538,12 @@ abstract static class AssignmentSwitchAnalysisResult {
static AssignmentSwitchAnalysisResult of(
boolean canConvertToAssignmentSwitch,
boolean canCombineWithPrecedingVariableDeclaration,
boolean canRemoveDefault,
Optional<ExpressionTree> assignmentTargetOptional,
Optional<Tree.Kind> assignmentKindOptional,
Optional<String> assignmentSourceCodeOptional) {
return new AutoValue_StatementSwitchToExpressionSwitch_AssignmentSwitchAnalysisResult(
canConvertToAssignmentSwitch,
canCombineWithPrecedingVariableDeclaration,
canRemoveDefault,
assignmentTargetOptional,
assignmentKindOptional,
assignmentSourceCodeOptional);
Expand Down
Loading
Loading