1 /*
2  * Copyright (C) 2014 The Dagger Authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package dagger.internal.codegen.binding;
18 
19 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
20 import static dagger.internal.codegen.langmodel.DaggerTypes.isFutureType;
21 
22 import com.google.auto.value.AutoValue;
23 import com.google.auto.value.extension.memoized.Memoized;
24 import com.google.common.collect.ImmutableList;
25 import com.google.common.collect.ImmutableSet;
26 import com.google.errorprone.annotations.CanIgnoreReturnValue;
27 import dagger.internal.codegen.base.ContributionType;
28 import dagger.internal.codegen.base.SetType;
29 import dagger.model.DependencyRequest;
30 import dagger.model.Key;
31 import java.util.Optional;
32 import java.util.stream.Stream;
33 import javax.lang.model.element.ExecutableElement;
34 import javax.lang.model.type.TypeMirror;
35 
36 /** A value object representing the mechanism by which a {@link Key} can be produced. */
37 @AutoValue
38 public abstract class ProductionBinding extends ContributionBinding {
39 
40   @Override
bindingType()41   public BindingType bindingType() {
42     return BindingType.PRODUCTION;
43   }
44 
45   @Override
unresolved()46   public abstract Optional<ProductionBinding> unresolved();
47 
48   @Override
implicitDependencies()49   public ImmutableSet<DependencyRequest> implicitDependencies() {
50     return Stream.of(executorRequest(), monitorRequest())
51         .filter(Optional::isPresent)
52         .map(Optional::get)
53         .collect(toImmutableSet());
54   }
55 
56   /** What kind of object a {@code @Produces}-annotated method returns. */
57   public enum ProductionKind {
58     /** A value. */
59     IMMEDIATE,
60     /** A {@code ListenableFuture<T>}. */
61     FUTURE,
62     /** A {@code Set<ListenableFuture<T>>}. */
63     SET_OF_FUTURE;
64 
65     /** Returns the kind of object a {@code @Produces}-annotated method returns. */
fromProducesMethod(ExecutableElement producesMethod)66     public static ProductionKind fromProducesMethod(ExecutableElement producesMethod) {
67       if (isFutureType(producesMethod.getReturnType())) {
68         return FUTURE;
69       } else if (ContributionType.fromBindingElement(producesMethod)
70               .equals(ContributionType.SET_VALUES)
71           && isFutureType(SetType.from(producesMethod.getReturnType()).elementType())) {
72         return SET_OF_FUTURE;
73       } else {
74         return IMMEDIATE;
75       }
76     }
77   }
78 
79   /**
80    * Returns the kind of object the produces method returns. All production bindings from
81    * {@code @Produces} methods will have a production kind, but synthetic production bindings may
82    * not.
83    */
productionKind()84   public abstract Optional<ProductionKind> productionKind();
85 
86   /** Returns the list of types in the throws clause of the method. */
thrownTypes()87   public abstract ImmutableList<? extends TypeMirror> thrownTypes();
88 
89   /**
90    * If this production requires an executor, this will be the corresponding request.  All
91    * production bindings from {@code @Produces} methods will have an executor request, but
92    * synthetic production bindings may not.
93    */
executorRequest()94   abstract Optional<DependencyRequest> executorRequest();
95 
96   /** If this production requires a monitor, this will be the corresponding request.  All
97    * production bindings from {@code @Produces} methods will have a monitor request, but synthetic
98    * production bindings may not.
99    */
monitorRequest()100   abstract Optional<DependencyRequest> monitorRequest();
101 
102   // Profiling determined that this method is called enough times that memoizing it had a measurable
103   // performance improvement for large components.
104   @Memoized
105   @Override
requiresModuleInstance()106   public boolean requiresModuleInstance() {
107     return super.requiresModuleInstance();
108   }
109 
builder()110   public static Builder builder() {
111     return new AutoValue_ProductionBinding.Builder()
112         .explicitDependencies(ImmutableList.<DependencyRequest>of())
113         .thrownTypes(ImmutableList.<TypeMirror>of());
114   }
115 
116   @Override
toBuilder()117   public abstract Builder toBuilder();
118 
119   @Memoized
120   @Override
hashCode()121   public abstract int hashCode();
122 
123   // TODO(ronshapiro,dpb): simplify the equality semantics
124   @Override
equals(Object obj)125   public abstract boolean equals(Object obj);
126 
127   /** A {@link ProductionBinding} builder. */
128   @AutoValue.Builder
129   @CanIgnoreReturnValue
130   public abstract static class Builder
131       extends ContributionBinding.Builder<ProductionBinding, Builder> {
132 
133     @Override
dependencies(Iterable<DependencyRequest> dependencies)134     public Builder dependencies(Iterable<DependencyRequest> dependencies) {
135       return explicitDependencies(dependencies);
136     }
137 
explicitDependencies(Iterable<DependencyRequest> dependencies)138     abstract Builder explicitDependencies(Iterable<DependencyRequest> dependencies);
139 
productionKind(ProductionKind productionKind)140     abstract Builder productionKind(ProductionKind productionKind);
141 
142     @Override
unresolved(ProductionBinding unresolved)143     public abstract Builder unresolved(ProductionBinding unresolved);
144 
thrownTypes(Iterable<? extends TypeMirror> thrownTypes)145     abstract Builder thrownTypes(Iterable<? extends TypeMirror> thrownTypes);
146 
executorRequest(DependencyRequest executorRequest)147     abstract Builder executorRequest(DependencyRequest executorRequest);
148 
monitorRequest(DependencyRequest monitorRequest)149     abstract Builder monitorRequest(DependencyRequest monitorRequest);
150   }
151 }
152