Skip to content

Commit

Permalink
In an AutoValueJava8Test test method, accept any @Nullable annotation.
Browse files Browse the repository at this point in the history
This test has a local `@Nullable` that is nested in the test class itself, and applied to the type of a property method in an AutoValue class being tested. Previously we expected that that annotation would also be copied onto the parameter type of `equals(Object)`. But if `java.lang.Object` already has a `@Nullable` on its `equals` parameter, we'll copy that instead. So the test now accepts either.

RELNOTES=n/a
PiperOrigin-RevId: 587710520
  • Loading branch information
eamonnmcmanus authored and Google Java Core Libraries committed Dec 4, 2023
1 parent 92d881e commit cd07d0d
Showing 1 changed file with 44 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,18 @@
package com.google.auto.value;

import static com.google.common.base.StandardSystemProperty.JAVA_SPECIFICATION_VERSION;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static com.google.common.truth.Truth8.assertThat;
import static com.google.common.truth.TruthJUnit.assume;
import static com.google.testing.compile.CompilationSubject.assertThat;
import static java.util.Arrays.stream;
import static org.junit.Assert.assertThrows;
import static org.junit.Assume.assumeTrue;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.testing.EqualsTester;
import com.google.testing.compile.Compilation;
Expand All @@ -48,6 +51,7 @@
import java.util.OptionalDouble;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Stream;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
Expand All @@ -72,6 +76,7 @@
*/
@RunWith(JUnit4.class)
public class AutoValueJava8Test {
@SuppressWarnings("NonFinalStaticField") // b/314784069
private static boolean javacHandlesTypeAnnotationsCorrectly;

// This is appalling. Some versions of javac do not correctly report annotations on type uses in
Expand Down Expand Up @@ -170,18 +175,44 @@ public void testEqualsParameterIsAnnotated() throws NoSuchMethodException {
// Some versions do, some don't. So skip the test unless we are on at least JDK 9.
double javaVersion = Double.parseDouble(JAVA_SPECIFICATION_VERSION.value());
assume().that(javaVersion).isAtLeast(9.0);
Method equals =
NullableProperties.create(null, 23).getClass().getMethod("equals", Object.class);
AnnotatedType[] parameterTypes = equals.getAnnotatedParameterTypes();
assertThat(parameterTypes).hasLength(1);
assertThat(parameterTypes[0].getAnnotation(Nullable.class)).isNotNull();
NullableProperties nullableProperties = NullableProperties.create(null, 23);
Method equals = nullableProperties.getClass().getMethod("equals", Object.class);
// If `java.lang.Object.equals` is itself annotated, for example with the JSpecify `@Nullable`,
// then we will copy that annotation onto the parameter of the generated `equals`
// implementation. Otherwise we will copy the `@Nullable` from the return type of the
// `nullableString()` method. So we accept either @Nullable here.
// (You might think we could just reflect on Object.equals to see if it has @Nullable, but in
// some environments we have nullness annotations at compile time but not at run time.)
assertThat(equals.getAnnotatedParameterTypes()[0].getAnnotations())
.asList()
.containsAnyIn(nullables(nullableProperties.getClass()));
}

@AutoAnnotation
static Nullable nullable() {
return new AutoAnnotation_AutoValueJava8Test_nullable();
}

/**
* Returns a set containing this test's {@link Nullable @Nullable} annotation, plus possibly
* another {@code @Nullable} that is present on the parameter of {@link Object#equals}.
*/
static ImmutableSet<Annotation> nullables(Class<?> autoValueImplClass) {
try {
return Stream.concat(
Stream.of(nullable()),
stream(
autoValueImplClass
.getMethod("equals", Object.class)
.getAnnotatedParameterTypes()[0]
.getAnnotations())
.filter(a -> a.annotationType().getSimpleName().equals("Nullable")))
.collect(toImmutableSet());
} catch (ReflectiveOperationException e) {
throw new LinkageError(e.getMessage(), e);
}
}

@Test
public void testNullablePropertyImplementationIsNullable() throws NoSuchMethodException {
Method method =
Expand Down Expand Up @@ -1080,14 +1111,20 @@ public void typeParameterBuilderFieldsAreNullable() throws ReflectiveOperationEx
// Even though neither t() nor string() has a @Nullable return type, the corresponding builder
// fields should be @Nullable. This test depends on the knowledge that for a property `t`, we
// will have a field also called `t`.
// For `nullableT`, the @Nullable in question should be the same as the one on the return type
// of nullableT(). For `t`, it is a @Nullable that AutoValue found somewhere, either there or
// possibly on the parameter of the inherited Object.equals method.
Field builderT = NotNullableVariableBound.builder().getClass().getDeclaredField("t");
assertThat(builderT.getAnnotatedType().getAnnotations()).asList().contains(nullable());
assertThat(builderT.getAnnotatedType().getAnnotations())
.asList()
.containsAnyIn(nullables(AutoValue_AutoValueJava8Test_NotNullableVariableBound.class));
Field builderNullableT =
NotNullableVariableBound.builder().getClass().getDeclaredField("nullableT");
assertThat(builderNullableT.getAnnotatedType().getAnnotations()).asList().contains(nullable());

// Meanwhile the AutoValue class itself should have @Nullable on the private field, the getter
// method, and the constructor parameter for nullableT.
// method, and the constructor parameter for nullableT. This @Nullable should be the same as
// the one on the return type of nullableT().
Class<?> autoValueClass = AutoValue_AutoValueJava8Test_NotNullableVariableBound.class;
Field nullableTField = autoValueClass.getDeclaredField("nullableT");
assertThat(nullableTField.getAnnotatedType().getAnnotations()).asList().contains(nullable());
Expand Down

0 comments on commit cd07d0d

Please sign in to comment.