|
4 | 4 | import com.google.common.collect.ImmutableList; |
5 | 5 | import com.google.common.collect.Iterables; |
6 | 6 | import com.google.common.collect.Lists; |
| 7 | +import com.google.common.collect.Streams; |
7 | 8 | import com.google.errorprone.refaster.Refaster; |
8 | 9 | import com.google.errorprone.refaster.annotation.AfterTemplate; |
9 | 10 | import com.google.errorprone.refaster.annotation.AlsoNegation; |
|
17 | 18 | import java.util.NavigableSet; |
18 | 19 | import java.util.Optional; |
19 | 20 | import java.util.Queue; |
| 21 | +import java.util.SequencedCollection; |
20 | 22 | import java.util.Set; |
21 | 23 | import java.util.SortedSet; |
22 | 24 | import java.util.function.Consumer; |
@@ -484,29 +486,140 @@ void after(Collection<T> collection, Consumer<? super T> consumer) { |
484 | 486 | } |
485 | 487 | } |
486 | 488 |
|
487 | | - /** Prefer {@link List#getFirst()} over less idiomatic alternatives. */ |
488 | | - static final class ListGetFirst<T> { |
| 489 | + /** Prefer {@code collection.iterator().next()} over more contrived alternatives. */ |
| 490 | + static final class CollectionIteratorNext<T> { |
| 491 | + @BeforeTemplate |
| 492 | + T before(Collection<T> collection) { |
| 493 | + return collection.stream().findFirst().orElseThrow(); |
| 494 | + } |
| 495 | + |
| 496 | + @AfterTemplate |
| 497 | + T after(Collection<T> collection) { |
| 498 | + return collection.iterator().next(); |
| 499 | + } |
| 500 | + } |
| 501 | + |
| 502 | + /** Prefer {@link SequencedCollection#getFirst()} over less idiomatic alternatives. */ |
| 503 | + static final class SequencedCollectionGetFirst<T> { |
| 504 | + @BeforeTemplate |
| 505 | + T before(SequencedCollection<T> collection) { |
| 506 | + return collection.iterator().next(); |
| 507 | + } |
| 508 | + |
| 509 | + @BeforeTemplate |
| 510 | + T before(List<T> collection) { |
| 511 | + return collection.get(0); |
| 512 | + } |
| 513 | + |
| 514 | + @AfterTemplate |
| 515 | + T after(SequencedCollection<T> collection) { |
| 516 | + return collection.getFirst(); |
| 517 | + } |
| 518 | + } |
| 519 | + |
| 520 | + /** Prefer {@link SequencedCollection#getLast()} over less idiomatic alternatives. */ |
| 521 | + static final class SequencedCollectionGetLast<T> { |
| 522 | + @BeforeTemplate |
| 523 | + T before(SequencedCollection<T> collection) { |
| 524 | + return Refaster.anyOf( |
| 525 | + collection.reversed().getFirst(), Streams.findLast(collection.stream()).orElseThrow()); |
| 526 | + } |
| 527 | + |
| 528 | + @BeforeTemplate |
| 529 | + T before(List<T> collection) { |
| 530 | + return collection.get(collection.size() - 1); |
| 531 | + } |
| 532 | + |
| 533 | + @AfterTemplate |
| 534 | + T after(SequencedCollection<T> collection) { |
| 535 | + return collection.getLast(); |
| 536 | + } |
| 537 | + } |
| 538 | + |
| 539 | + /** Prefer {@link List#addFirst(Object)} over less idiomatic alternatives. */ |
| 540 | + static final class ListAddFirst<S, T extends S> { |
| 541 | + @BeforeTemplate |
| 542 | + void before(List<S> list, T element) { |
| 543 | + list.add(0, element); |
| 544 | + } |
| 545 | + |
| 546 | + @AfterTemplate |
| 547 | + void after(List<S> list, T element) { |
| 548 | + list.addFirst(element); |
| 549 | + } |
| 550 | + } |
| 551 | + |
| 552 | + /** Prefer {@link List#add(Object)} over less idiomatic alternatives. */ |
| 553 | + static final class ListAdd<S, T extends S> { |
| 554 | + @BeforeTemplate |
| 555 | + void before(List<S> list, T element) { |
| 556 | + list.addLast(element); |
| 557 | + } |
| 558 | + |
| 559 | + @BeforeTemplate |
| 560 | + void before2(List<S> list, T element) { |
| 561 | + list.add(list.size(), element); |
| 562 | + } |
| 563 | + |
| 564 | + @AfterTemplate |
| 565 | + void after(List<S> list, T element) { |
| 566 | + list.add(element); |
| 567 | + } |
| 568 | + } |
| 569 | + |
| 570 | + /** Prefer {@link List#removeFirst()}} over less idiomatic alternatives. */ |
| 571 | + // XXX: This rule changes the exception thrown for empty lists from `IndexOutOfBoundsException` to |
| 572 | + // `NoSuchElementException`. |
| 573 | + static final class ListRemoveFirst<T> { |
489 | 574 | @BeforeTemplate |
490 | 575 | T before(List<T> list) { |
491 | | - return list.get(0); |
| 576 | + return list.remove(0); |
492 | 577 | } |
493 | 578 |
|
494 | 579 | @AfterTemplate |
495 | 580 | T after(List<T> list) { |
496 | | - return list.getFirst(); |
| 581 | + return list.removeFirst(); |
497 | 582 | } |
498 | 583 | } |
499 | 584 |
|
500 | | - /** Prefer {@link List#getLast()} over less idiomatic alternatives. */ |
501 | | - static final class ListGetLast<T> { |
| 585 | + /** Prefer {@link List#removeLast()}} over less idiomatic alternatives. */ |
| 586 | + // XXX: This rule changes the exception thrown for empty lists from `IndexOutOfBoundsException` to |
| 587 | + // `NoSuchElementException`. |
| 588 | + static final class ListRemoveLast<T> { |
502 | 589 | @BeforeTemplate |
503 | 590 | T before(List<T> list) { |
504 | | - return list.get(list.size() - 1); |
| 591 | + return list.remove(list.size() - 1); |
505 | 592 | } |
506 | 593 |
|
507 | 594 | @AfterTemplate |
508 | 595 | T after(List<T> list) { |
509 | | - return list.getLast(); |
| 596 | + return list.removeLast(); |
| 597 | + } |
| 598 | + } |
| 599 | + |
| 600 | + /** Prefer {@link SortedSet#first()} over more verbose alternatives. */ |
| 601 | + static final class SortedSetFirst<T> { |
| 602 | + @BeforeTemplate |
| 603 | + T before(SortedSet<T> set) { |
| 604 | + return set.getFirst(); |
| 605 | + } |
| 606 | + |
| 607 | + @AfterTemplate |
| 608 | + T after(SortedSet<T> set) { |
| 609 | + return set.first(); |
| 610 | + } |
| 611 | + } |
| 612 | + |
| 613 | + /** Prefer {@link SortedSet#last()} over more verbose alternatives. */ |
| 614 | + static final class SortedSetLast<T> { |
| 615 | + @BeforeTemplate |
| 616 | + T before(SortedSet<T> set) { |
| 617 | + return set.getLast(); |
| 618 | + } |
| 619 | + |
| 620 | + @AfterTemplate |
| 621 | + T after(SortedSet<T> set) { |
| 622 | + return set.last(); |
510 | 623 | } |
511 | 624 | } |
512 | 625 |
|
|
0 commit comments