Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't emit @SafeVarargs for reifiable types #71

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import com.squareup.javapoet.WildcardTypeName;
import io.norberg.automatter.AutoMatter;
import java.io.IOException;
import java.lang.reflect.Parameter;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
Expand All @@ -43,6 +45,7 @@
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.function.Function;
import java.util.stream.Stream;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
Expand Down Expand Up @@ -524,7 +527,9 @@ private MethodSpec collectionVarargSetter(final Descriptor d, final ExecutableEl
.varargs()
.returns(builderType(d));

ensureSafeVarargs(setter);
if (!isReifiable(itemType)) {
ensureSafeVarargs(setter);
}

collectionNullGuard(setter, field);

Expand All @@ -533,7 +538,6 @@ private MethodSpec collectionVarargSetter(final Descriptor d, final ExecutableEl
}

private void ensureSafeVarargs(MethodSpec.Builder setter) {
// TODO: Add SafeVarargs annotation only for non-reifiable types.
AnnotationSpec safeVarargsAnnotation = AnnotationSpec.builder(SafeVarargs.class).build();

setter
Expand Down Expand Up @@ -1433,6 +1437,35 @@ private static String capitalizeFirstLetter(String s) {
return s.substring(0, 1).toUpperCase() + (s.length() > 1 ? s.substring(1) : "");
}

private static boolean isUnboundedWildcard(TypeName type) {
if (type instanceof WildcardTypeName) {
WildcardTypeName t = (WildcardTypeName) type;
return t.lowerBounds.isEmpty() && t.upperBounds.stream().allMatch(bound -> bound.equals(TypeName.OBJECT));
}
return false;
}

public static boolean isReifiable(TypeName type) {
if (type.isPrimitive()) return true;
if (type.isBoxedPrimitive()) return true;

// TODO: handle nested types, per JLS §4.7
// JavaPoet does not expose ParameterizedTypeName's enclosing type,
// so we can't verify that the enclosing type is reifiable.

if (type instanceof ParameterizedTypeName) {
ParameterizedTypeName parameterized = (ParameterizedTypeName) type;
return parameterized.typeArguments.stream().allMatch(AutoMatterProcessor::isUnboundedWildcard);
} else if (type instanceof ArrayTypeName) {
ArrayTypeName array = (ArrayTypeName) type;
return isReifiable(array.componentType);
} else if (type instanceof ClassName) {
return true;
}

return false;
}

@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,23 @@
import static com.google.testing.compile.Compiler.javac;
import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
import static com.squareup.javapoet.WildcardTypeName.subtypeOf;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import com.google.common.collect.ImmutableSet;
import com.google.common.io.Resources;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
import com.squareup.javapoet.ArrayTypeName;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.WildcardTypeName;
import io.norberg.automatter.processor.AutoMatterProcessor;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.tools.Diagnostic;
Expand Down Expand Up @@ -420,4 +429,28 @@ private boolean hasJutOptional() {
return false;
}
}

private TypeName[] wildcards(final int size) {
final WildcardTypeName wildcard = subtypeOf(ClassName.get(Object.class));
final TypeName[] wildcards = new TypeName[size];
for (int i = 0; i < size; i++) {
wildcards[i] = wildcard;
}
return wildcards;
}

@Test
public void testReifiable() {
ParameterizedTypeName listOfObject = ParameterizedTypeName.get(ClassName.get("java.util", "List"), TypeName.OBJECT);
assertTrue(AutoMatterProcessor.isReifiable(TypeName.BOOLEAN));
assertTrue(AutoMatterProcessor.isReifiable(TypeName.get(String.class)));
assertTrue(AutoMatterProcessor.isReifiable(ClassName.get("java.util", "List")));
assertTrue(AutoMatterProcessor.isReifiable(ParameterizedTypeName.get(ClassName.get("java.util", "List"), wildcards(1)[0])));
assertFalse(AutoMatterProcessor.isReifiable(listOfObject));
assertTrue(AutoMatterProcessor.isReifiable(ArrayTypeName.of(String.class)));
assertFalse(AutoMatterProcessor.isReifiable(ArrayTypeName.of(listOfObject)));

// TODO: handle nested classes
//assertFalse(AutoMatterProcessor.isReifiable(listOfObject.nestedClass("Foo")));
}
}
16 changes: 4 additions & 12 deletions processor/src/test/resources/expected/CollectionFieldsBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,7 @@ public CollectionFieldsBuilder strings(Iterator<? extends String> strings) {
return this;
}

@SafeVarargs
@SuppressWarnings("varargs")
public final CollectionFieldsBuilder strings(String... strings) {
public CollectionFieldsBuilder strings(String... strings) {
if (strings == null) {
throw new NullPointerException("strings");
}
Expand Down Expand Up @@ -474,9 +472,7 @@ public CollectionFieldsBuilder numbers(Iterator<? extends Long> numbers) {
return this;
}

@SafeVarargs
@SuppressWarnings("varargs")
public final CollectionFieldsBuilder numbers(Long... numbers) {
public CollectionFieldsBuilder numbers(Long... numbers) {
if (numbers == null) {
throw new NullPointerException("numbers");
}
Expand Down Expand Up @@ -543,9 +539,7 @@ public CollectionFieldsBuilder sortedNumbers(Iterator<? extends Long> sortedNumb
return this;
}

@SafeVarargs
@SuppressWarnings("varargs")
public final CollectionFieldsBuilder sortedNumbers(Long... sortedNumbers) {
public CollectionFieldsBuilder sortedNumbers(Long... sortedNumbers) {
if (sortedNumbers == null) {
throw new NullPointerException("sortedNumbers");
}
Expand Down Expand Up @@ -612,9 +606,7 @@ public CollectionFieldsBuilder navigableNumbers(Iterator<? extends Long> navigab
return this;
}

@SafeVarargs
@SuppressWarnings("varargs")
public final CollectionFieldsBuilder navigableNumbers(Long... navigableNumbers) {
public CollectionFieldsBuilder navigableNumbers(Long... navigableNumbers) {
if (navigableNumbers == null) {
throw new NullPointerException("navigableNumbers");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,7 @@ public CollectionInterfaceFieldBuilder strings(Iterator<? extends String> string
return this;
}

@SafeVarargs
@SuppressWarnings("varargs")
public final CollectionInterfaceFieldBuilder strings(String... strings) {
public CollectionInterfaceFieldBuilder strings(String... strings) {
if (strings == null) {
throw new NullPointerException("strings");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,7 @@ public NullableCollectionFieldsBuilder strings(Iterator<? extends String> string
return this;
}

@SafeVarargs
@SuppressWarnings("varargs")
public final NullableCollectionFieldsBuilder strings(String... strings) {
public NullableCollectionFieldsBuilder strings(String... strings) {
if (strings == null) {
this.strings = null;
return this;
Expand Down Expand Up @@ -199,9 +197,7 @@ public NullableCollectionFieldsBuilder numbers(Iterator<? extends Long> numbers)
return this;
}

@SafeVarargs
@SuppressWarnings("varargs")
public final NullableCollectionFieldsBuilder numbers(Long... numbers) {
public NullableCollectionFieldsBuilder numbers(Long... numbers) {
if (numbers == null) {
this.numbers = null;
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,7 @@ public ConcreteExtensionOfGenericParentBuilder foos(Iterator<? extends Integer>
return this;
}

@SafeVarargs
@SuppressWarnings("varargs")
public final ConcreteExtensionOfGenericParentBuilder foos(Integer... foos) {
public ConcreteExtensionOfGenericParentBuilder foos(Integer... foos) {
if (foos == null) {
throw new NullPointerException("foos");
}
Expand Down