-
Notifications
You must be signed in to change notification settings - Fork 39
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
Introduce ImmutableCollection
templates
#40
Changes from all commits
29a031d
2904a75
be9117d
55a2437
eb4d03d
6630b6e
1876587
a92c05e
a58862f
7aa801d
f4b0285
f8c2048
59ef9e9
dbae0c1
920a2e1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,37 +41,6 @@ ImmutableList.Builder<T> after() { | |
} | ||
} | ||
|
||
/** Prefer {@link ImmutableList#of()} over more contrived alternatives. */ | ||
static final class EmptyImmutableList<T> { | ||
@BeforeTemplate | ||
ImmutableList<T> before() { | ||
return Refaster.anyOf( | ||
ImmutableList.<T>builder().build(), Stream.<T>empty().collect(toImmutableList())); | ||
} | ||
|
||
@AfterTemplate | ||
ImmutableList<T> after() { | ||
return ImmutableList.of(); | ||
} | ||
} | ||
|
||
/** | ||
* Prefer {@link ImmutableList#of(Object)} over alternatives that don't communicate the | ||
* immutability of the resulting list at the type level. | ||
*/ | ||
// XXX: Note that this rewrite rule is incorrect for nullable elements. | ||
static final class SingletonImmutableList<T> { | ||
@BeforeTemplate | ||
List<T> before(T element) { | ||
return Collections.singletonList(element); | ||
} | ||
|
||
@AfterTemplate | ||
ImmutableList<T> after(T element) { | ||
return ImmutableList.of(element); | ||
} | ||
} | ||
|
||
/** | ||
* Prefer {@link ImmutableList#copyOf(Iterable)} and variants over more contrived alternatives. | ||
*/ | ||
|
@@ -186,4 +155,117 @@ ImmutableList<T> after(Stream<T> stream) { | |
return stream.collect(toImmutableSet()).asList(); | ||
} | ||
} | ||
|
||
/** | ||
* Prefer {@link ImmutableList#of()} over more contrived alternatives or alternatives that don't | ||
* communicate the immutability of the resulting list at the type level. | ||
*/ | ||
// XXX: The `Stream` variant may be too contrived to warrant inclusion. Review its usage if/when | ||
// this and similar Refaster templates are replaced with an Error Prone check. | ||
static final class ImmutableListOf<T> { | ||
@BeforeTemplate | ||
List<T> before() { | ||
return Refaster.anyOf( | ||
ImmutableList.<T>builder().build(), | ||
Stream.<T>empty().collect(toImmutableList()), | ||
Collections.emptyList(), | ||
List.of()); | ||
} | ||
|
||
@AfterTemplate | ||
ImmutableList<T> after() { | ||
return ImmutableList.of(); | ||
} | ||
} | ||
|
||
/** | ||
* Prefer {@link ImmutableList#of(Object)} over more contrived alternatives or alternatives that | ||
* don't communicate the immutability of the resulting list at the type level. | ||
*/ | ||
// XXX: Note that the replacement of `Collections#singletonList` is incorrect for nullable | ||
// elements. | ||
static final class ImmutableListOf1<T> { | ||
@BeforeTemplate | ||
List<T> before(T e1) { | ||
return Refaster.anyOf( | ||
ImmutableList.<T>builder().add(e1).build(), Collections.singletonList(e1), List.of(e1)); | ||
} | ||
|
||
@AfterTemplate | ||
ImmutableList<T> after(T e1) { | ||
return ImmutableList.of(e1); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Strictly speaking the signature uses There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I also prefer this for consistency :) |
||
} | ||
} | ||
|
||
/** | ||
* Prefer {@link ImmutableList#of(Object, Object)} over alternatives that don't communicate the | ||
* immutability of the resulting list at the type level. | ||
*/ | ||
// XXX: Consider writing an Error Prone check which also flags straightforward | ||
// `ImmutableList.builder()` usages. | ||
static final class ImmutableListOf2<T> { | ||
@BeforeTemplate | ||
List<T> before(T e1, T e2) { | ||
return List.of(e1, e2); | ||
} | ||
|
||
@AfterTemplate | ||
ImmutableList<T> after(T e1, T e2) { | ||
return ImmutableList.of(e1, e2); | ||
} | ||
} | ||
|
||
/** | ||
* Prefer {@link ImmutableList#of(Object, Object, Object)} over alternatives that don't | ||
* communicate the immutability of the resulting list at the type level. | ||
*/ | ||
// XXX: Consider writing an Error Prone check which also flags straightforward | ||
// `ImmutableList.builder()` usages. | ||
static final class ImmutableListOf3<T> { | ||
@BeforeTemplate | ||
List<T> before(T e1, T e2, T e3) { | ||
return List.of(e1, e2, e3); | ||
} | ||
|
||
@AfterTemplate | ||
ImmutableList<T> after(T e1, T e2, T e3) { | ||
return ImmutableList.of(e1, e2, e3); | ||
} | ||
} | ||
|
||
/** | ||
* Prefer {@link ImmutableList#of(Object, Object, Object, Object)} over alternatives that don't | ||
* communicate the immutability of the resulting list at the type level. | ||
*/ | ||
// XXX: Consider writing an Error Prone check which also flags straightforward | ||
// `ImmutableList.builder()` usages. | ||
static final class ImmutableListOf4<T> { | ||
@BeforeTemplate | ||
List<T> before(T e1, T e2, T e3, T e4) { | ||
return List.of(e1, e2, e3, e4); | ||
} | ||
|
||
@AfterTemplate | ||
ImmutableList<T> after(T e1, T e2, T e3, T e4) { | ||
return ImmutableList.of(e1, e2, e3, e4); | ||
} | ||
} | ||
|
||
/** | ||
* Prefer {@link ImmutableList#of(Object, Object, Object, Object, Object)} over alternatives that | ||
* don't communicate the immutability of the resulting list at the type level. | ||
*/ | ||
// XXX: Consider writing an Error Prone check which also flags straightforward | ||
// `ImmutableList.builder()` usages. | ||
static final class ImmutableListOf5<T> { | ||
@BeforeTemplate | ||
List<T> before(T e1, T e2, T e3, T e4, T e5) { | ||
return List.of(e1, e2, e3, e4, e5); | ||
} | ||
|
||
@AfterTemplate | ||
ImmutableList<T> after(T e1, T e2, T e3, T e4, T e5) { | ||
return ImmutableList.of(e1, e2, e3, e4, e5); | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Location-wise I would probably have located these templates further up in the file, as we generally start with "construction" checks. But since we're planning to auto-sort the templates lexicographically: let's roll with this :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Based on the other files, I got the idea that we list templates with different number of params overloads at the end of a file. Nonetheless, good point about "construction" checks :). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed, the auto-generated checks in |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,41 +40,6 @@ ImmutableMap.Builder<K, V> after() { | |
} | ||
} | ||
|
||
/** Prefer {@link ImmutableMap#of()} over more contrived alternatives. */ | ||
static final class EmptyImmutableMap<K, V> { | ||
@BeforeTemplate | ||
ImmutableMap<K, V> before() { | ||
return ImmutableMap.<K, V>builder().build(); | ||
} | ||
|
||
@AfterTemplate | ||
ImmutableMap<K, V> after() { | ||
return ImmutableMap.of(); | ||
} | ||
} | ||
|
||
/** | ||
* Prefer {@link ImmutableMap#of(Object, Object)} over more contrived alternatives and | ||
* alternatives that don't communicate the immutability of the resulting map at the type level. | ||
*/ | ||
// XXX: One can define variants for more than one key-value pair, but at some point the builder | ||
// actually produces nicer code. So it's not clear we should add Refaster templates for those | ||
// variants. | ||
// XXX: Note that the `singletonMap` rewrite rule is incorrect for nullable elements. | ||
static final class PairToImmutableMap<K, V> { | ||
@BeforeTemplate | ||
Map<K, V> before(K key, V value) { | ||
return Refaster.anyOf( | ||
ImmutableMap.<K, V>builder().put(key, value).build(), | ||
Collections.singletonMap(key, value)); | ||
} | ||
|
||
@AfterTemplate | ||
ImmutableMap<K, V> after(K key, V value) { | ||
return ImmutableMap.of(key, value); | ||
} | ||
} | ||
|
||
/** Prefer {@link ImmutableMap#of(Object, Object)} over more contrived alternatives. */ | ||
static final class EntryToImmutableMap<K, V> { | ||
@BeforeTemplate | ||
|
@@ -242,6 +207,113 @@ ImmutableMap<K, V2> after(Map<K, V1> map) { | |
} | ||
} | ||
|
||
/** | ||
* Prefer {@link ImmutableMap#of()} over more contrived alternatives or alternatives that don't | ||
* communicate the immutability of the resulting map at the type level. | ||
*/ | ||
static final class ImmutableMapOf<K, V> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This one should be merged with |
||
@BeforeTemplate | ||
Map<K, V> before() { | ||
return Refaster.anyOf(ImmutableMap.<K, V>builder().build(), Collections.emptyMap(), Map.of()); | ||
} | ||
|
||
@AfterTemplate | ||
ImmutableMap<K, V> after() { | ||
return ImmutableMap.of(); | ||
} | ||
} | ||
|
||
/** | ||
* Prefer {@link ImmutableMap#of(Object, Object)} over more contrived alternatives or alternatives | ||
* that don't communicate the immutability of the resulting map at the type level. | ||
*/ | ||
// XXX: Note that the replacement of `Collections#singletonMap` is incorrect for nullable | ||
// elements. | ||
static final class ImmutableMapOf1<K, V> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This check should be merged with |
||
@BeforeTemplate | ||
Map<K, V> before(K k1, V v1) { | ||
return Refaster.anyOf( | ||
ImmutableMap.<K, V>builder().put(k1, v1).build(), | ||
Collections.singletonMap(k1, v1), | ||
Map.of(k1, v1)); | ||
} | ||
|
||
@AfterTemplate | ||
ImmutableMap<K, V> after(K k1, V v1) { | ||
return ImmutableMap.of(k1, v1); | ||
} | ||
} | ||
|
||
/** | ||
* Prefer {@link ImmutableMap#of(Object, Object, Object, Object)} over alternatives that don't | ||
* communicate the immutability of the resulting map at the type level. | ||
*/ | ||
// XXX: Also rewrite the `ImmutableMap.builder()` variant? | ||
static final class ImmutableMapOf2<K, V> { | ||
@BeforeTemplate | ||
Map<K, V> before(K k1, V v1, K k2, V v2) { | ||
return Map.of(k1, v1, k2, v2); | ||
} | ||
|
||
@AfterTemplate | ||
ImmutableMap<K, V> after(K k1, V v1, K k2, V v2) { | ||
return ImmutableMap.of(k1, v1, k2, v2); | ||
} | ||
} | ||
|
||
/** | ||
* Prefer {@link ImmutableMap#of(Object, Object, Object, Object, Object, Object)} over | ||
* alternatives that don't communicate the immutability of the resulting map at the type level. | ||
*/ | ||
// XXX: Also rewrite the `ImmutableMap.builder()` variant? | ||
static final class ImmutableMapOf3<K, V> { | ||
@BeforeTemplate | ||
Map<K, V> before(K k1, V v1, K k2, V v2, K k3, V v3) { | ||
return Map.of(k1, v1, k2, v2, k3, v3); | ||
} | ||
|
||
@AfterTemplate | ||
ImmutableMap<K, V> after(K k1, V v1, K k2, V v2, K k3, V v3) { | ||
return ImmutableMap.of(k1, v1, k2, v2, k3, v3); | ||
} | ||
} | ||
|
||
/** | ||
* Prefer {@link ImmutableMap#of(Object, Object, Object, Object, Object, Object, Object, Object)} | ||
* over alternatives that don't communicate the immutability of the resulting map at the type | ||
* level. | ||
*/ | ||
// XXX: Also rewrite the `ImmutableMap.builder()` variant? | ||
static final class ImmutableMapOf4<K, V> { | ||
@BeforeTemplate | ||
Map<K, V> before(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { | ||
return Map.of(k1, v1, k2, v2, k3, v3, k4, v4); | ||
} | ||
|
||
@AfterTemplate | ||
ImmutableMap<K, V> after(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { | ||
return ImmutableMap.of(k1, v1, k2, v2, k3, v3, k4, v4); | ||
} | ||
} | ||
|
||
/** | ||
* Prefer {@link ImmutableMap#of(Object, Object, Object, Object, Object, Object, Object, Object, | ||
* Object, Object)} over alternatives that don't communicate the immutability of the resulting map | ||
* at the type level. | ||
*/ | ||
// XXX: Also rewrite the `ImmutableMap.builder()` variant? | ||
static final class ImmutableMapOf5<K, V> { | ||
@BeforeTemplate | ||
Map<K, V> before(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { | ||
return Map.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5); | ||
} | ||
|
||
@AfterTemplate | ||
ImmutableMap<K, V> after(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { | ||
return ImmutableMap.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5); | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's add a newline between the class and the comments. |
||
|
||
// XXX: Add a template for this: | ||
// Maps.transformValues(streamOfEntries.collect(groupBy(fun)), ImmutableMap::copyOf) | ||
// -> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The other templates in this class have a Javadoc, let's add it for the other templates we introduce in this PR as well.
Perhaps we could do something like this example:
The implementation of
List.of(element ...)
is:So the example Javadoc has some similarities with the Refaster templates we are adding in this PR.
This also applies for the other introduced Refaster templates in
Immutable{Map,Set}.java
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For most templates the Javadoc is now good. Only for this case, the
emptyList()
I'm not 100% sure. So theList.of(..)
calls uses theImmutableCollections
under the hood. However, for theemptyList()
this is not the case:I'm not sure what to write in the Javadoc there, so also leaving this open for other reviewers to give their input :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should be very careful here (also when considering
List.of()
as before template, see other comment). We have three differentList
implementations with different behavior:@Before Collections.emptyList()
: uses Java'sCollections.EmptyList
which silently ignores calls tosort()
,replaceAll()
andremoveIf()
as there are no elements anyway.@Before List.of()
: uses Java'sImmutableCollections.ListN
which throwsUnsupportedOperationException
on those methods.@After ImmutableList.of()
: uses Guava'sImmutableList
which throwsUnsupportedOperationException
on those methods.My suggestion (after further implementation investigation):
List.of()
andImmutableList.of()
have the most similar implementation and I would be happy to make that conversion. I would create anErrorProne
check forCollections.emptyList()
to suggest usingImmutableList.of()
warning them for possible side-effects due to differences in List implementations. WDYT?Regarding JavaDoc, I'm happy with current state on this method, except that it mentions
{@link ImmutableList#of(Object)}
instead of{@link ImmutableList#of()}
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good remark, we should do this 😄.
For the
Collections.emptyList()
we can use the same setup asFluxFlatMapUsageCheck.java
. We should do two suggested fixes there, such that it will say: "Do you want to useImmutableList.of()
or add aSuppressWarnings("...")
"?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets create a new PR to create an error prone rule to validate Collections.emptyList() and suggest ImmutableList.of()
And on this PR I will change current refaster template to List.of() -> ImmutableList.of()