diff --git a/check_api/src/main/java/com/google/errorprone/util/ASTHelpers.java b/check_api/src/main/java/com/google/errorprone/util/ASTHelpers.java index 7ff84c44ac9..5de1c2b5ab1 100644 --- a/check_api/src/main/java/com/google/errorprone/util/ASTHelpers.java +++ b/check_api/src/main/java/com/google/errorprone/util/ASTHelpers.java @@ -1754,14 +1754,30 @@ public Type visitAnnotation(AnnotationTree tree, Void unused) { @Override public Type visitCase(CaseTree tree, Void unused) { - Tree t = parent.getParentPath().getLeaf(); - // JDK 12+, t can be SwitchExpressionTree - if (t instanceof SwitchTree) { - SwitchTree switchTree = (SwitchTree) t; - return getType(switchTree.getExpression()); - } - // TODO(b/176098078): When the ErrorProne project switches to JDK 12, we should check - // for SwitchExpressionTree. + Tree switchTree = parent.getParentPath().getLeaf(); + return getType(getSwitchExpression(switchTree)); + } + + @Nullable + private static ExpressionTree getSwitchExpression(Tree tree) { + if (tree instanceof SwitchTree) { + return ((SwitchTree) tree).getExpression(); + } + // Reflection is required for JDK < 12 + try { + Class switchExpression = Class.forName("com.sun.source.tree.SwitchExpressionTree"); + Class clazz = tree.getClass(); + if (switchExpression.isAssignableFrom(clazz)) { + try { + Method method = clazz.getMethod("getExpression"); + return (ExpressionTree) method.invoke(tree); + } catch (ReflectiveOperationException e) { + throw new LinkageError(e.getMessage(), e); + } + } + } catch (ClassNotFoundException e) { + // continue below + } return null; } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/threadsafety/ImmutableCheckerTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/threadsafety/ImmutableCheckerTest.java index 864524e5e8e..b51dd6501ce 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/threadsafety/ImmutableCheckerTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/threadsafety/ImmutableCheckerTest.java @@ -16,11 +16,14 @@ package com.google.errorprone.bugpatterns.threadsafety; +import static org.junit.Assume.assumeTrue; + import com.google.common.collect.ImmutableList; import com.google.errorprone.CompilationTestHelper; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.Immutable; import com.google.errorprone.annotations.concurrent.LazyInit; +import com.google.errorprone.util.RuntimeVersion; import java.util.Arrays; import org.junit.Ignore; import org.junit.Test; @@ -2969,4 +2972,27 @@ public void anonymousClass_canCallSuperMethodOnNonImmutableSuperClass() { "}") .doTest(); } + + @Test + public void switchExpressionsResultingInGenericTypes_doesNotThrow() { + assumeTrue(RuntimeVersion.isAtLeast14()); + compilationHelper + .addSourceLines( + "Kind.java", + "import com.google.errorprone.annotations.Immutable;", + "@Immutable enum Kind { A, B; }") + .addSourceLines( + "Test.java", + "import java.util.Optional;", + "import java.util.function.Supplier;", + "class Test {", + " Supplier> test(Kind kind) {", + " return switch (kind) {", + " case A -> Optional::empty;", + " case B -> () -> Optional.of(\"\");", + " };", + " }", + "}") + .doTest(); + } }