diff --git a/check_api/src/main/java/com/google/errorprone/util/RuntimeVersion.java b/check_api/src/main/java/com/google/errorprone/util/RuntimeVersion.java index f965d3f625c..14ae3dd37fc 100644 --- a/check_api/src/main/java/com/google/errorprone/util/RuntimeVersion.java +++ b/check_api/src/main/java/com/google/errorprone/util/RuntimeVersion.java @@ -16,7 +16,15 @@ package com.google.errorprone.util; -/** JDK version string utilities. */ +/** + * JDK runtime version utilities. + * + *
These methods are generally used when deciding which method to call reflectively. Bug checkers + * that rely on support for specific source code constructs should consult {@link SourceVersion} + * instead. + * + * @see SourceVersion + */ public final class RuntimeVersion { private static final int FEATURE = Runtime.version().feature(); diff --git a/check_api/src/main/java/com/google/errorprone/util/SourceVersion.java b/check_api/src/main/java/com/google/errorprone/util/SourceVersion.java new file mode 100644 index 00000000000..23de9c6402a --- /dev/null +++ b/check_api/src/main/java/com/google/errorprone/util/SourceVersion.java @@ -0,0 +1,44 @@ +/* + * Copyright 2023 The Error Prone Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.errorprone.util; + +import com.sun.tools.javac.code.Source; +import com.sun.tools.javac.util.Context; + +/** + * JDK source version utilities. + * + * @see RuntimeVersion + */ +public final class SourceVersion { + /** Returns true if the compiler source version level supports switch expressions. */ + public static boolean supportsSwitchExpressions(Context context) { + return sourceIsAtLeast(context, "14"); + } + + /** Returns true if the compiler source version level supports text blocks. */ + public static boolean supportsTextBlocks(Context context) { + return sourceIsAtLeast(context, "15"); + } + + private static boolean sourceIsAtLeast(Context context, String versionString) { + Source lowerBound = Source.lookup(versionString); + return lowerBound != null && Source.instance(context).compareTo(lowerBound) >= 0; + } + + private SourceVersion() {} +} diff --git a/check_api/src/test/java/com/google/errorprone/util/SourceVersionTest.java b/check_api/src/test/java/com/google/errorprone/util/SourceVersionTest.java new file mode 100644 index 00000000000..c7da4fb92b9 --- /dev/null +++ b/check_api/src/test/java/com/google/errorprone/util/SourceVersionTest.java @@ -0,0 +1,66 @@ +/* + * Copyright 2023 The Error Prone Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.errorprone.util; + +import static com.google.common.truth.Truth.assertThat; + +import com.sun.tools.javac.main.Option; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Options; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class SourceVersionTest { + @Test + public void supportsSwitchExpressions_notSupported() { + Context context = contextWithSourceVersion("13"); + + assertThat(SourceVersion.supportsSwitchExpressions(context)).isFalse(); + } + + @Test + public void supportsSwitchExpressions_conditionallySupported() { + Context context = contextWithSourceVersion("14"); + + assertThat(SourceVersion.supportsSwitchExpressions(context)) + .isEqualTo(RuntimeVersion.isAtLeast14()); + } + + @Test + public void supportsTextBlocks_notSupported() { + Context context = contextWithSourceVersion("14"); + + assertThat(SourceVersion.supportsTextBlocks(context)).isFalse(); + } + + @Test + public void supportsTextBlocks_conditionallySupported() { + Context context = contextWithSourceVersion("15"); + + assertThat(SourceVersion.supportsTextBlocks(context)).isEqualTo(RuntimeVersion.isAtLeast15()); + } + + private static Context contextWithSourceVersion(String versionString) { + Context context = new Context(); + + Options options = Options.instance(context); + options.put(Option.SOURCE, versionString); + + return context; + } +} diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/StatementSwitchToExpressionSwitch.java b/core/src/main/java/com/google/errorprone/bugpatterns/StatementSwitchToExpressionSwitch.java index 8d53a085ae7..b9181a5091f 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/StatementSwitchToExpressionSwitch.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/StatementSwitchToExpressionSwitch.java @@ -39,6 +39,7 @@ import com.google.errorprone.matchers.Description; import com.google.errorprone.util.Reachability; import com.google.errorprone.util.RuntimeVersion; +import com.google.errorprone.util.SourceVersion; import com.sun.source.tree.BreakTree; import com.sun.source.tree.CaseTree; import com.sun.source.tree.ExpressionTree; @@ -85,8 +86,7 @@ public StatementSwitchToExpressionSwitch(ErrorProneFlags flags) { @Override public Description matchSwitch(SwitchTree switchTree, VisitorState state) { - // Expression switches finalized in Java 14 - if (!RuntimeVersion.isAtLeast14()) { + if (!SourceVersion.supportsSwitchExpressions(state.context)) { return NO_MATCH; }