From 54b8c476d82798103d3473ba5249d5688d692d26 Mon Sep 17 00:00:00 2001 From: cpovirk Date: Fri, 27 Dec 2024 12:13:00 -0800 Subject: [PATCH] Standardize on `sneakyThrow` for "impossible" checked exceptions. This makes our code behave the same for sneaky checked exceptions that occur _when our implementations use reflection_ as for those that occur when our implementations use direct calls. This shouldn't matter for any of the code that I'm migrating to `sneakyThrow` in this CL, but there are other cases in which it could matter, and we're probably best off standardizing on one approach, just as we've done for _catching_ sneaky checked exceptions. Plus, pull each package's `sneakyThrow` out into its own top-level class for reuse. Also, sneak in a few other tiny cleanups: - We don't normally use `@GwtCompatible` in Truth, so remove it from `J2ktIncompatible`. - We can now use `Primitives.wrap` to produce a better error message for `isIntanceOf(primitiveType)`. RELNOTES=n/a PiperOrigin-RevId: 710111747 --- .../google/common/truth/J2ktIncompatible.java | 2 - .../com/google/common/truth/Platform.java | 4 +- .../com/google/common/truth/SneakyThrows.java | 41 +++++++++++++++++++ .../java/com/google/common/truth/Subject.java | 10 ++--- 4 files changed, 47 insertions(+), 10 deletions(-) create mode 100644 core/src/main/java/com/google/common/truth/SneakyThrows.java diff --git a/core/src/main/java/com/google/common/truth/J2ktIncompatible.java b/core/src/main/java/com/google/common/truth/J2ktIncompatible.java index 45e14be0c..3ac74695f 100644 --- a/core/src/main/java/com/google/common/truth/J2ktIncompatible.java +++ b/core/src/main/java/com/google/common/truth/J2ktIncompatible.java @@ -14,7 +14,6 @@ package com.google.common.truth; -import com.google.common.annotations.GwtCompatible; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -26,5 +25,4 @@ */ @Retention(RetentionPolicy.CLASS) @Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD}) -@GwtCompatible @interface J2ktIncompatible {} diff --git a/core/src/main/java/com/google/common/truth/Platform.java b/core/src/main/java/com/google/common/truth/Platform.java index 32b9461c6..fd589c75a 100644 --- a/core/src/main/java/com/google/common/truth/Platform.java +++ b/core/src/main/java/com/google/common/truth/Platform.java @@ -20,6 +20,7 @@ import static com.google.common.base.Throwables.throwIfUnchecked; import static com.google.common.truth.DiffUtils.generateUnifiedDiff; import static com.google.common.truth.Fact.fact; +import static com.google.common.truth.SneakyThrows.sneakyThrow; import com.google.common.base.Joiner; import com.google.common.base.Splitter; @@ -254,9 +255,8 @@ static AssertionError makeComparisonFailure( try { return constructor.newInstance(messages, facts, expected, actual, cause); } catch (InvocationTargetException e) { - throwIfUnchecked(e.getCause()); // That constructor has no `throws` clause. - throw newLinkageError(e); + throw sneakyThrow(e.getCause()); } catch (InstantiationException e) { // The class is a concrete class. throw newLinkageError(e); diff --git a/core/src/main/java/com/google/common/truth/SneakyThrows.java b/core/src/main/java/com/google/common/truth/SneakyThrows.java new file mode 100644 index 000000000..9e0673e89 --- /dev/null +++ b/core/src/main/java/com/google/common/truth/SneakyThrows.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015 Google, Inc. + * + * 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.common.truth; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; + +/** Static utility method for throwing an undeclared checked exception. */ +final class SneakyThrows { + /** + * Throws an undeclared checked exception. + * + * @return never; this method declares a return type of {@link Error} only so that callers can + * write {@code throw sneakyThrow(t);} to convince the compiler that the statement will always + * throw. + */ + @CanIgnoreReturnValue + static Error sneakyThrow(Throwable t) { + throw new SneakyThrows().throwIt(t); + } + + @SuppressWarnings("unchecked") // not really safe, but that's the point + private Error throwIt(Throwable t) throws T { + throw (T) t; + } + + private SneakyThrows() {} +} diff --git a/core/src/main/java/com/google/common/truth/Subject.java b/core/src/main/java/com/google/common/truth/Subject.java index 6c54def99..0cae3fc2b 100644 --- a/core/src/main/java/com/google/common/truth/Subject.java +++ b/core/src/main/java/com/google/common/truth/Subject.java @@ -44,6 +44,7 @@ import com.google.common.primitives.Chars; import com.google.common.primitives.Ints; import com.google.common.primitives.Longs; +import com.google.common.primitives.Primitives; import com.google.common.primitives.Shorts; import com.google.common.truth.FailureMetadata.OldAndNewValuesAreSimilar; import com.google.errorprone.annotations.DoNotCall; @@ -349,12 +350,9 @@ public void isNotInstanceOf(Class clazz) { private static boolean isInstanceOfType(Object instance, Class clazz) { checkArgument( !clazz.isPrimitive(), - "Cannot check instanceof for primitive type %s. Pass the wrapper class instead.", - clazz.getSimpleName()); - /* - * TODO(cpovirk): Make the message include `Primitives.wrap(clazz).getSimpleName()` once that - * method is available in a public guava-gwt release that we depend on. - */ + "Cannot check instanceof for primitive type %s. Pass the wrapper class %s instead.", + clazz.getSimpleName(), + Primitives.wrap(clazz).getSimpleName()); return Platform.isInstanceOfType(instance, clazz); }