Skip to content

Commit 385e43a

Browse files
cushonError Prone Team
authored and
Error Prone Team
committed
Disallow using traditional :-style switches as switch expressions
PiperOrigin-RevId: 653064183
1 parent 2656f48 commit 385e43a

File tree

4 files changed

+170
-0
lines changed

4 files changed

+170
-0
lines changed

check_api/src/main/java/com/google/errorprone/util/ASTHelpers.java

+25
Original file line numberDiff line numberDiff line change
@@ -2808,6 +2808,31 @@ private static Method getCaseTreeGetExpressionsMethod() {
28082808
}
28092809
}
28102810

2811+
/**
2812+
* Returns true if the given {@link CaseTree} is in the form: {@code case <expression> ->
2813+
* <expression>}.
2814+
*/
2815+
public static boolean isRuleKind(CaseTree caseTree) {
2816+
Enum<?> kind;
2817+
try {
2818+
kind = (Enum<?>) GET_CASE_KIND_METHOD.invoke(caseTree);
2819+
} catch (ReflectiveOperationException e) {
2820+
return false;
2821+
}
2822+
return kind.name().equals("RULE");
2823+
}
2824+
2825+
private static final Method GET_CASE_KIND_METHOD = getGetCaseKindMethod();
2826+
2827+
@Nullable
2828+
private static Method getGetCaseKindMethod() {
2829+
try {
2830+
return CaseTree.class.getMethod("getCaseKind");
2831+
} catch (NoSuchMethodException e) {
2832+
return null;
2833+
}
2834+
}
2835+
28112836
/**
28122837
* Retrieves a stream containing all case expressions, in order, for a given {@code CaseTree}.
28132838
* This method acts as a facade to the {@code CaseTree.getExpressions()} API, falling back to
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2024 The Error Prone Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.errorprone.bugpatterns;
18+
19+
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
20+
import static com.google.errorprone.matchers.Description.NO_MATCH;
21+
import static com.google.errorprone.util.ASTHelpers.isRuleKind;
22+
23+
import com.google.errorprone.BugPattern;
24+
import com.google.errorprone.VisitorState;
25+
import com.google.errorprone.matchers.Description;
26+
import com.sun.source.tree.CaseTree;
27+
import com.sun.source.tree.Tree;
28+
29+
/** A {@link BugChecker}; see the associated {@link BugPattern} annotation for details. */
30+
@BugPattern(summary = "Prefer -> switches for switch expressions", severity = WARNING)
31+
public class TraditionalSwitchExpression extends BugChecker implements BugChecker.CaseTreeMatcher {
32+
33+
@Override
34+
public Description matchCase(CaseTree tree, VisitorState state) {
35+
if (isRuleKind(tree)) {
36+
return NO_MATCH;
37+
}
38+
Tree parent = state.getPath().getParentPath().getLeaf();
39+
if (!parent.getKind().name().equals("SWITCH_EXPRESSION")) {
40+
return NO_MATCH;
41+
}
42+
return describeMatch(parent);
43+
}
44+
}

core/src/main/java/com/google/errorprone/scanner/BuiltInCheckerSuppliers.java

+2
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@
379379
import com.google.errorprone.bugpatterns.ThrowsUncheckedException;
380380
import com.google.errorprone.bugpatterns.ToStringReturnsNull;
381381
import com.google.errorprone.bugpatterns.TooManyParameters;
382+
import com.google.errorprone.bugpatterns.TraditionalSwitchExpression;
382383
import com.google.errorprone.bugpatterns.TransientMisuse;
383384
import com.google.errorprone.bugpatterns.TreeToString;
384385
import com.google.errorprone.bugpatterns.TruthAssertExpected;
@@ -1075,6 +1076,7 @@ public static ScannerSupplier warningChecks() {
10751076
ThreeLetterTimeZoneID.class,
10761077
TimeUnitConversionChecker.class,
10771078
ToStringReturnsNull.class,
1079+
TraditionalSwitchExpression.class,
10781080
TruthAssertExpected.class,
10791081
TruthConstantAsserts.class,
10801082
TruthGetOrDefault.class,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Copyright 2024 The Error Prone Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.errorprone.bugpatterns;
18+
19+
import static org.junit.Assume.assumeTrue;
20+
21+
import com.google.errorprone.CompilationTestHelper;
22+
import com.google.errorprone.util.RuntimeVersion;
23+
import org.junit.Test;
24+
import org.junit.runner.RunWith;
25+
import org.junit.runners.JUnit4;
26+
27+
@RunWith(JUnit4.class)
28+
public class TraditionalSwitchExpressionTest {
29+
30+
private final CompilationTestHelper testHelper =
31+
CompilationTestHelper.newInstance(TraditionalSwitchExpression.class, getClass());
32+
33+
@Test
34+
public void positive() {
35+
assumeTrue(RuntimeVersion.isAtLeast14());
36+
testHelper
37+
.addSourceLines(
38+
"Test.java",
39+
"class Test {",
40+
" int f(int i) {",
41+
" // BUG: Diagnostic contains: Prefer -> switches for switch expressions",
42+
" return switch (i) {",
43+
" default:",
44+
" yield -1;",
45+
" };",
46+
" }",
47+
"}")
48+
.doTest();
49+
}
50+
51+
@Test
52+
public void negativeStatement() {
53+
assumeTrue(RuntimeVersion.isAtLeast14());
54+
testHelper
55+
.addSourceLines(
56+
"Test.java",
57+
"class Test {",
58+
" void f(int i) {",
59+
" switch (i) {",
60+
" default:",
61+
" return;",
62+
" }",
63+
" }",
64+
"}")
65+
.doTest();
66+
}
67+
68+
@Test
69+
public void negativeArrowStatement() {
70+
assumeTrue(RuntimeVersion.isAtLeast14());
71+
testHelper
72+
.addSourceLines(
73+
"Test.java",
74+
"class Test {",
75+
" void f(int i) {",
76+
" switch (i) {",
77+
" default -> System.err.println();",
78+
" }",
79+
" }",
80+
"}")
81+
.doTest();
82+
}
83+
84+
@Test
85+
public void negativeArrow() {
86+
assumeTrue(RuntimeVersion.isAtLeast14());
87+
testHelper
88+
.addSourceLines(
89+
"Test.java",
90+
"class Test {",
91+
" int f(int i) {",
92+
" return switch (i) {",
93+
" default -> -1;",
94+
" };",
95+
" }",
96+
"}")
97+
.doTest();
98+
}
99+
}

0 commit comments

Comments
 (0)