All Downloads are FREE. Search and download functionalities are using the official Maven repository.

tech.picnic.errorprone.refasterrules.ImmutableSetMultimapRules Maven / Gradle / Ivy

There is a newer version: 0.19.1
Show newest version
package tech.picnic.errorprone.refasterrules;

import static com.google.common.collect.ImmutableSetMultimap.flatteningToImmutableSetMultimap;
import static com.google.common.collect.ImmutableSetMultimap.toImmutableSetMultimap;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;

import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.SortedSetMultimap;
import com.google.common.collect.Streams;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.MayOptionallyUse;
import com.google.errorprone.refaster.annotation.Placeholder;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.Collection;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;

/** Refaster rules related to expressions dealing with {@link ImmutableSetMultimap}s. */
@OnlineDocumentation
final class ImmutableSetMultimapRules {
  private ImmutableSetMultimapRules() {}

  /** Prefer {@link ImmutableSetMultimap#builder()} over the associated constructor. */
  // XXX: This drops generic type information, sometimes leading to non-compilable code. See
  // https://github.com/google/error-prone/pull/2706.
  static final class ImmutableSetMultimapBuilder {
    @BeforeTemplate
    ImmutableSetMultimap.Builder before() {
      return new ImmutableSetMultimap.Builder<>();
    }

    @AfterTemplate
    ImmutableSetMultimap.Builder after() {
      return ImmutableSetMultimap.builder();
    }
  }

  /** Prefer {@link ImmutableSetMultimap#of()} over more contrived alternatives. */
  static final class EmptyImmutableSetMultimap {
    @BeforeTemplate
    ImmutableSetMultimap before() {
      return ImmutableSetMultimap.builder().build();
    }

    @AfterTemplate
    ImmutableSetMultimap after() {
      return ImmutableSetMultimap.of();
    }
  }

  /** Prefer {@link ImmutableSetMultimap#of(Object, Object)} over more contrived alternatives. */
  // 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 rules for those
  // variants.
  static final class PairToImmutableSetMultimap {
    @BeforeTemplate
    ImmutableSetMultimap before(K key, V value) {
      return ImmutableSetMultimap.builder().put(key, value).build();
    }

    @AfterTemplate
    ImmutableSetMultimap after(K key, V value) {
      return ImmutableSetMultimap.of(key, value);
    }
  }

  /** Prefer {@link ImmutableSetMultimap#of(Object, Object)} over more contrived alternatives. */
  static final class EntryToImmutableSetMultimap {
    @BeforeTemplate
    ImmutableSetMultimap before(Map.Entry entry) {
      return Refaster.anyOf(
          ImmutableSetMultimap.builder().put(entry).build(),
          Stream.of(entry).collect(toImmutableSetMultimap(Map.Entry::getKey, Map.Entry::getValue)));
    }

    @AfterTemplate
    ImmutableSetMultimap after(Map.Entry entry) {
      return ImmutableSetMultimap.of(entry.getKey(), entry.getValue());
    }
  }

  /** Prefer {@link ImmutableSetMultimap#copyOf(Iterable)} over more contrived alternatives. */
  static final class IterableToImmutableSetMultimap {
    @BeforeTemplate
    ImmutableSetMultimap before(Multimap iterable) {
      return Refaster.anyOf(
          ImmutableSetMultimap.copyOf(iterable.entries()),
          ImmutableSetMultimap.builder().putAll(iterable).build());
    }

    @BeforeTemplate
    ImmutableSetMultimap before(
        Iterable> iterable) {
      return Refaster.anyOf(
          ImmutableSetMultimap.builder().putAll(iterable).build(),
          Streams.stream(iterable)
              .collect(toImmutableSetMultimap(Map.Entry::getKey, Map.Entry::getValue)));
    }

    @BeforeTemplate
    ImmutableSetMultimap before(
        Collection> iterable) {
      return iterable.stream()
          .collect(toImmutableSetMultimap(Map.Entry::getKey, Map.Entry::getValue));
    }

    @AfterTemplate
    ImmutableSetMultimap after(
        Iterable> iterable) {
      return ImmutableSetMultimap.copyOf(iterable);
    }
  }

  /**
   * Don't map a a stream's elements to map entries, only to subsequently collect them into an
   * {@link ImmutableSetMultimap}. The collection can be performed directly.
   */
  abstract static class StreamOfMapEntriesToImmutableSetMultimap {
    @Placeholder(allowsIdentity = true)
    abstract K keyFunction(@MayOptionallyUse E element);

    @Placeholder(allowsIdentity = true)
    abstract V valueFunction(@MayOptionallyUse E element);

    // XXX: We could add variants in which the entry is created some other way, but we have another
    // rule which covers canonicalization to `Map.entry`.
    @BeforeTemplate
    ImmutableSetMultimap before(Stream stream) {
      return stream
          .map(e -> Map.entry(keyFunction(e), valueFunction(e)))
          .collect(toImmutableSetMultimap(Map.Entry::getKey, Map.Entry::getValue));
    }

    @AfterTemplate
    @UseImportPolicy(STATIC_IMPORT_ALWAYS)
    ImmutableSetMultimap after(Stream stream) {
      return stream.collect(toImmutableSetMultimap(e -> keyFunction(e), e -> valueFunction(e)));
    }
  }

  /**
   * Prefer creating an immutable copy of the result of {@link Multimaps#transformValues(Multimap,
   * com.google.common.base.Function)} over creating and directly collecting a stream.
   */
  abstract static class TransformMultimapValuesToImmutableSetMultimap {
    @Placeholder(allowsIdentity = true)
    abstract V2 valueTransformation(@MayOptionallyUse V1 value);

    @BeforeTemplate
    ImmutableSetMultimap before(Multimap multimap) {
      return multimap.entries().stream()
          .collect(
              toImmutableSetMultimap(Map.Entry::getKey, e -> valueTransformation(e.getValue())));
    }

    @AfterTemplate
    ImmutableSetMultimap after(Multimap multimap) {
      return ImmutableSetMultimap.copyOf(
          Multimaps.transformValues(multimap, e -> valueTransformation(e)));
    }
  }

  /**
   * Prefer creating an immutable copy of the result of {@link Multimaps#transformValues(Multimap,
   * com.google.common.base.Function)} over creating and directly collecting a stream.
   */
  static final class TransformMultimapValuesToImmutableSetMultimap2 {
    // XXX: Drop the `Refaster.anyOf` if we decide to rewrite one to the other.
    @BeforeTemplate
    ImmutableSetMultimap before(
        Multimap multimap, Function transformation) {
      return Refaster.anyOf(multimap.asMap(), Multimaps.asMap(multimap)).entrySet().stream()
          .collect(
              flatteningToImmutableSetMultimap(
                  Map.Entry::getKey, e -> e.getValue().stream().map(transformation)));
    }

    @BeforeTemplate
    ImmutableSetMultimap before(
        ListMultimap multimap, Function transformation) {
      return Multimaps.asMap(multimap).entrySet().stream()
          .collect(
              flatteningToImmutableSetMultimap(
                  Map.Entry::getKey, e -> e.getValue().stream().map(transformation)));
    }

    @BeforeTemplate
    ImmutableSetMultimap before(
        SetMultimap multimap, Function transformation) {
      return Multimaps.asMap(multimap).entrySet().stream()
          .collect(
              flatteningToImmutableSetMultimap(
                  Map.Entry::getKey, e -> e.getValue().stream().map(transformation)));
    }

    @BeforeTemplate
    ImmutableSetMultimap before(
        SortedSetMultimap multimap, Function transformation) {
      return Multimaps.asMap(multimap).entrySet().stream()
          .collect(
              flatteningToImmutableSetMultimap(
                  Map.Entry::getKey, e -> e.getValue().stream().map(transformation)));
    }

    @AfterTemplate
    ImmutableSetMultimap after(
        Multimap multimap,
        com.google.common.base.Function transformation) {
      return ImmutableSetMultimap.copyOf(Multimaps.transformValues(multimap, transformation));
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy