• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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;
18 
19 import com.google.common.collect.ImmutableSet;
20 
21 /**
22  * A label for a binding indicating whether, and how, it may be redefined across implementations of
23  * a subcomponent.
24  *
25  * <p>A subcomponent has multiple implementations only when generating ahead-of-time subcomponents.
26  * Specifically, each subcomponent type in a component hierarchy is implemented as an abstract
27  * class, and descendent components are implemented as abstract inner classes. A consequence of this
28  * is that a given subcomponent has an implementation for each ancestor component. Each
29  * implementation represents a different sub-binding-graph of the full subcomponent. A binding is
30  * modifiable if it's definition may change depending on the characteristics of its ancestor
31  * components.
32  */
33 enum ModifiableBindingType {
34   /** A binding that is not modifiable */
35   NONE,
36 
37   /**
38    * A binding that is missing when generating the abstract base class implementation of a
39    * subcomponent.
40    */
41   MISSING,
42 
43   /**
44    * A binding that requires an instance of a generated type. These binding are modifiable in the
45    * sense that they are encapsulated in a method when they are first required, possibly in an
46    * abstract implementation of a subcomponent, where, in general, no concrete instances of
47    * generated types are available, and the method is satisfied in a final concrete implementation.
48    */
49   GENERATED_INSTANCE,
50 
51   /**
52    * Multibindings may have contributions come from any ancestor component. Therefore, each
53    * implementation of a subcomponent may have newly available contributions, and so the binding
54    * method is reimplemented with each subcomponent implementation.
55    */
56   MULTIBINDING,
57 
58   /**
59    * A Optional binding that may be empty when looking at a partial binding graph, but bound to a
60    * value when considering the complete binding graph, thus modifiable across subcomponent
61    * implementations.
62    */
63   OPTIONAL,
64 
65   /**
66    * If a binding is defined according to an {@code @Inject} annotated constructor on the object it
67    * is valid for that binding to be redefined a single time by an {@code @Provides} annotated
68    * module method. It is possible that the {@code @Provides} binding isn't available in a partial
69    * binding graph, but becomes available when considering a more complete binding graph, therefore
70    * such bindings are modifiable across subcomponent implementations.
71    */
72   INJECTION,
73 
74   /**
75    * A {@link dagger.Binds} method whose dependency is {@link #MISSING}.
76    *
77    * <p>There's not much to do for @Binds bindings if the dependency is missing - at best, if the
78    * dependency is a weaker scope/unscoped, we save only a few lines that implement the scoping. But
79    * it's also possible, if the dependency is the same or stronger scope, that no extra code is
80    * necessary, in which case we'd be overriding a method that just returns another.
81    */
82   BINDS_METHOD_WITH_MISSING_DEPENDENCY,
83   ;
84 
85   private static final ImmutableSet<ModifiableBindingType> TYPES_WITH_BASE_CLASS_IMPLEMENTATIONS =
86       ImmutableSet.of(NONE, INJECTION, MULTIBINDING, OPTIONAL);
87 
isModifiable()88   boolean isModifiable() {
89     return !equals(NONE);
90   }
91 
92   /**
93    * Returns true if the method encapsulating the modifiable binding should have a concrete
94    * implementation in the abstract base class for a subcomponent.
95    */
hasBaseClassImplementation()96   boolean hasBaseClassImplementation() {
97     return TYPES_WITH_BASE_CLASS_IMPLEMENTATIONS.contains(this);
98   }
99 }
100