Add ImmutableSet support to SetBindingRequestFulfillment

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=160912106
diff --git a/java/dagger/internal/SetBuilder.java b/java/dagger/internal/SetBuilder.java
index 2ca8462..16bc589 100644
--- a/java/dagger/internal/SetBuilder.java
+++ b/java/dagger/internal/SetBuilder.java
@@ -37,7 +37,7 @@
   /**
    * {@code estimatedSize} is the number of bindings which contribute to the set. They may each
    * provide {@code [0..n)} instances to the set. Because the final size is unknown, {@code
-   * contributions} are collected in a list and only hashed in {@link #create()}.
+   * contributions} are collected in a list and only hashed in {@link #build()}.
    */
   public static <T> SetBuilder<T> newSetBuilder(int estimatedSize) {
     return new SetBuilder<T>(estimatedSize);
@@ -53,7 +53,7 @@
     return this;
   }
 
-  public Set<T> create() {
+  public Set<T> build() {
     switch (contributions.size()) {
       case 0:
         return Collections.emptySet();
diff --git a/java/dagger/internal/codegen/AbstractComponentWriter.java b/java/dagger/internal/codegen/AbstractComponentWriter.java
index 84b999d..193022a 100644
--- a/java/dagger/internal/codegen/AbstractComponentWriter.java
+++ b/java/dagger/internal/codegen/AbstractComponentWriter.java
@@ -174,7 +174,7 @@
     this.optionalFactories = optionalFactories;
     this.bindingExpressionFactory =
         new BindingExpression.Factory(
-            name, this, childComponentNames(keyFactory, subcomponentNames), graph);
+            name, this, childComponentNames(keyFactory, subcomponentNames), graph, elements);
   }
 
   private static ImmutableMap<BindingKey, String> childComponentNames(
diff --git a/java/dagger/internal/codegen/BindingExpression.java b/java/dagger/internal/codegen/BindingExpression.java
index c271b2f..fd43c8f 100644
--- a/java/dagger/internal/codegen/BindingExpression.java
+++ b/java/dagger/internal/codegen/BindingExpression.java
@@ -30,6 +30,7 @@
 import dagger.internal.DelegateFactory;
 import java.util.Optional;
 import java.util.function.BiConsumer;
+import javax.lang.model.util.Elements;
 
 /** The code expressions to declare, initialize, and/or access a binding in a component. */
 final class BindingExpression extends RequestFulfillment {
@@ -57,16 +58,19 @@
     private final HasBindingExpressions hasBindingExpressions;
     private final ImmutableMap<BindingKey, String> subcomponentNames;
     private final BindingGraph graph;
+    private final Elements elements;
 
     Factory(
         ClassName componentName,
         HasBindingExpressions hasBindingExpressions,
         ImmutableMap<BindingKey, String> subcomponentNames,
-        BindingGraph graph) {
+        BindingGraph graph,
+        Elements elements) {
       this.componentName = checkNotNull(componentName);
       this.hasBindingExpressions = checkNotNull(hasBindingExpressions);
       this.subcomponentNames = checkNotNull(subcomponentNames);
       this.graph = checkNotNull(graph);
+      this.elements = elements;
     }
 
     /** Creates a binding expression for a field. */
@@ -112,7 +116,8 @@
                   provisionBinding,
                   graph,
                   hasBindingExpressions,
-                  providerFieldRequestFulfillment);
+                  providerFieldRequestFulfillment,
+                  elements);
             case INJECTION:
             case PROVISION:
               if (provisionBinding.implicitDependencies().isEmpty()
diff --git a/java/dagger/internal/codegen/SetBindingRequestFulfillment.java b/java/dagger/internal/codegen/SetBindingRequestFulfillment.java
index f5368e5..502a15b 100644
--- a/java/dagger/internal/codegen/SetBindingRequestFulfillment.java
+++ b/java/dagger/internal/codegen/SetBindingRequestFulfillment.java
@@ -17,14 +17,19 @@
 package dagger.internal.codegen;
 
 import static com.google.common.collect.Iterables.getOnlyElement;
-import static com.squareup.javapoet.CodeBlock.of;
 import static dagger.internal.codegen.Accessibility.isTypeAccessibleFrom;
+import static dagger.internal.codegen.CodeBlocks.toParametersCodeBlock;
 
+import com.google.common.collect.ImmutableSet;
 import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.TypeName;
 import dagger.internal.SetBuilder;
 import java.util.Collections;
+import java.util.Set;
+import java.util.function.Function;
 import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
 
 /**
  * A {@link RequestFulfillment} for {@link
@@ -34,24 +39,46 @@
   private final ProvisionBinding binding;
   private final BindingGraph graph;
   private final HasBindingExpressions hasBindingExpressions;
+  private final Elements elements;
 
   SetBindingRequestFulfillment(
       BindingKey bindingKey,
       ProvisionBinding binding,
       BindingGraph graph,
       HasBindingExpressions hasBindingExpressions,
-      RequestFulfillment delegate) {
+      RequestFulfillment delegate,
+      Elements elements) {
     super(bindingKey, delegate);
     this.binding = binding;
     this.graph = graph;
     this.hasBindingExpressions = hasBindingExpressions;
+    this.elements = elements;
   }
 
   @Override
   CodeBlock getSimpleInvocation(DependencyRequest request, ClassName requestingClass) {
-    // TODO(ronshapiro): if you have ImmutableSet on your classpath, use ImmutableSet.Builder
-    // otherwise, we can consider providing our own static factories for multibinding cases where
-    // all of the dependencies are @IntoSet
+    Function<DependencyRequest, CodeBlock> getRequestFulfillmentForDependency =
+        dependency ->
+            hasBindingExpressions
+                .getBindingExpression(dependency.bindingKey())
+                .getSnippetForDependencyRequest(dependency, requestingClass);
+
+    // TODO(ronshapiro): We should also make an ImmutableSet version of SetFactory
+    boolean isImmutableSetAvailable = isImmutableSetAvailable();
+    // TODO(ronshapiro, gak): Use Sets.immutableEnumSet() if it's available?
+    if (isImmutableSetAvailable && binding.dependencies().stream().allMatch(this::isSingleValue)) {
+      return CodeBlock.builder()
+          .add("$T.", ImmutableSet.class)
+          .add(maybeTypeParameter(request, requestingClass))
+          .add(
+              "of($L)",
+              binding
+                  .dependencies()
+                  .stream()
+                  .map(getRequestFulfillmentForDependency)
+                  .collect(toParametersCodeBlock()))
+          .build();
+    }
     switch (binding.dependencies().size()) {
       case 0:
         return collectionsStaticFactoryInvocation(
@@ -59,22 +86,30 @@
       case 1:
         {
           DependencyRequest dependency = getOnlyElement(binding.dependencies());
+          CodeBlock dependencySnippet =
+              getRequestFulfillmentForDependency(dependency, requestingClass);
           if (isSingleValue(dependency)) {
             return collectionsStaticFactoryInvocation(
-                request,
-                requestingClass,
-                CodeBlock.of(
-                    "singleton($L)",
-                    getRequestFulfillmentForDependency(dependency, requestingClass)));
+                request, requestingClass, CodeBlock.of("singleton($L)", dependencySnippet));
+          } else if (isImmutableSetAvailable) {
+            return CodeBlock.builder()
+                .add("$T.", ImmutableSet.class)
+                .add(maybeTypeParameter(request, requestingClass))
+                .add("copyOf($L)", dependencySnippet)
+                .build();
           }
         }
         // fall through
       default:
         CodeBlock.Builder instantiation = CodeBlock.builder();
         instantiation
-            .add("$T.", SetBuilder.class)
-            .add(maybeTypeParameter(request, requestingClass))
-            .add("newSetBuilder($L)", binding.dependencies().size());
+            .add("$T.", isImmutableSetAvailable ? ImmutableSet.class : SetBuilder.class)
+            .add(maybeTypeParameter(request, requestingClass));
+        if (isImmutableSetAvailable) {
+          instantiation.add("builder()");
+        } else {
+          instantiation.add("newSetBuilder($L)", binding.dependencies().size());
+        }
         for (DependencyRequest dependency : binding.dependencies()) {
           String builderMethod = isSingleValue(dependency) ? "add" : "addAll";
           instantiation.add(
@@ -82,7 +117,7 @@
               builderMethod,
               getRequestFulfillmentForDependency(dependency, requestingClass));
         }
-        return instantiation.add(".create()").build();
+        return instantiation.add(".build()").build();
     }
   }
 
@@ -106,8 +141,8 @@
       DependencyRequest request, ClassName requestingClass) {
     TypeMirror elementType = SetType.from(request.key()).elementType();
     return isTypeAccessibleFrom(elementType, requestingClass.packageName())
-        ? of("<$T>", elementType)
-        : of("");
+        ? CodeBlock.of("<$T>", elementType)
+        : CodeBlock.of("");
   }
 
   private boolean isSingleValue(DependencyRequest dependency) {
@@ -118,4 +153,21 @@
         .contributionType()
         .equals(ContributionType.SET);
   }
+
+  private boolean isImmutableSetAvailable() {
+    return elements.getTypeElement(ImmutableSet.class.getCanonicalName()) != null;
+  }
+
+  @Override
+  protected CodeBlock explicitTypeParameter(ClassName requestingClass) {
+    if (isImmutableSetAvailable()) {
+      TypeMirror keyType = binding.key().type();
+      return CodeBlock.of(
+          "<$T>",
+          isTypeAccessibleFrom(keyType, requestingClass.packageName())
+              ? TypeName.get(keyType)
+              : ClassName.get(Set.class));
+    }
+    return CodeBlock.of("");
+  }
 }
diff --git a/java/dagger/internal/codegen/SimpleInvocationRequestFulfillment.java b/java/dagger/internal/codegen/SimpleInvocationRequestFulfillment.java
index 0e43011..94e19bd 100644
--- a/java/dagger/internal/codegen/SimpleInvocationRequestFulfillment.java
+++ b/java/dagger/internal/codegen/SimpleInvocationRequestFulfillment.java
@@ -34,6 +34,17 @@
 
   abstract CodeBlock getSimpleInvocation(DependencyRequest request, ClassName requestingClass);
 
+  /**
+   * Java 7 type inference is not as strong as in Java 8, and therefore some generated code must
+   * make type parameters for {@link Futures#immediateFuture(Object)} explicit.
+   *
+   * <p>For example, {@code javac7} cannot detect that Futures.immediateFuture(ImmutableSet.of(T))}
+   * can safely be assigned to {@code ListenableFuture<Set<T>>}.
+   */
+  protected CodeBlock explicitTypeParameter(ClassName requestingClass) {
+    return CodeBlock.of("");
+  }
+
   @Override
   final CodeBlock getSnippetForDependencyRequest(
       DependencyRequest request, ClassName requestingClass) {
@@ -41,8 +52,11 @@
       case INSTANCE:
         return getSimpleInvocation(request, requestingClass);
       case FUTURE:
-        return CodeBlock.of(
-            "$T.immediateFuture($L)", Futures.class, getSimpleInvocation(request, requestingClass));
+        return CodeBlock.builder()
+            .add("$T.", Futures.class)
+            .add(explicitTypeParameter(requestingClass))
+            .add("immediateFuture($L)", getSimpleInvocation(request, requestingClass))
+            .build();
       default:
         return delegate.getSnippetForDependencyRequest(request, requestingClass);
     }