• 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 static com.google.common.base.Verify.verify;
20 
21 import com.google.auto.common.MoreTypes;
22 import com.google.auto.value.AutoValue;
23 import com.google.common.base.Equivalence;
24 import com.google.common.collect.ImmutableList;
25 import com.google.common.collect.ImmutableMap;
26 import com.google.common.collect.Maps;
27 import com.squareup.javapoet.MethodSpec;
28 import java.util.Map;
29 import java.util.Optional;
30 import javax.lang.model.type.TypeMirror;
31 
32 /**
33  * A registry for those methods which each wrap a binding whose definition may be modified across
34  * each class in the class hierarchy implementing a subcomponent. Subcomponent implementations are
35  * spread across a class hierarchy when generating ahead-of-time subcomponents. There is one
36  * subcomponent implementation class for each of the subcomponent's ancestor components. An instance
37  * of {@link ModifiableBindingMethod} is associated with a single class in this hierarchy. For a
38  * given subcomponent implementation class we can use the {@link ModifiableBindingMethod}s of its
39  * superclasses to know what binding methods to attempt to modify.
40  */
41 final class ModifiableBindingMethods {
42   private final Map<BindingRequest, ModifiableBindingMethod> methods = Maps.newLinkedHashMap();
43 
44   /** Registers a new method encapsulating a modifiable binding. */
addModifiableMethod( ModifiableBindingType type, BindingRequest request, TypeMirror returnType, MethodSpec method, boolean finalized)45   void addModifiableMethod(
46       ModifiableBindingType type,
47       BindingRequest request,
48       TypeMirror returnType,
49       MethodSpec method,
50       boolean finalized) {
51     // It's ok for the type to not be modifiable, since it could be overriding a previously
52     // modifiable method (such as with addReimplementedMethod).
53     addMethod(ModifiableBindingMethod.create(type, request, returnType, method, finalized));
54   }
55 
56   /** Registers a reimplemented modifiable method. */
addReimplementedMethod(ModifiableBindingMethod method)57   void addReimplementedMethod(ModifiableBindingMethod method) {
58     addMethod(method);
59   }
60 
addMethod(ModifiableBindingMethod method)61   private void addMethod(ModifiableBindingMethod method) {
62     ModifiableBindingMethod previousMethod = methods.put(method.request(), method);
63     verify(
64         previousMethod == null,
65         "registering %s but %s is already registered for the same binding request",
66         method,
67         previousMethod);
68   }
69 
70   /** Returns all {@link ModifiableBindingMethod}s that have not been marked as finalized. */
getNonFinalizedMethods()71   ImmutableMap<BindingRequest, ModifiableBindingMethod> getNonFinalizedMethods() {
72     return ImmutableMap.copyOf(Maps.filterValues(methods, m -> !m.finalized()));
73   }
74 
75   /** Returns the {@link ModifiableBindingMethod} for the given binding if present. */
getMethod(BindingRequest request)76   Optional<ModifiableBindingMethod> getMethod(BindingRequest request) {
77     return Optional.ofNullable(methods.get(request));
78   }
79 
80   /** Returns all of the {@link ModifiableBindingMethod}s. */
allMethods()81   ImmutableList<ModifiableBindingMethod> allMethods() {
82     return ImmutableList.copyOf(methods.values());
83   }
84 
85   /** Whether a given binding has been marked as finalized. */
86   // TODO(ronshapiro): possibly rename this to something that indicates that the BindingRequest for
87   // `method` has been finalized in *this* component implementation?
finalized(ModifiableBindingMethod method)88   boolean finalized(ModifiableBindingMethod method) {
89     ModifiableBindingMethod storedMethod = methods.get(method.request());
90     return storedMethod != null && storedMethod.finalized();
91   }
92 
93   @AutoValue
94   abstract static class ModifiableBindingMethod {
create( ModifiableBindingType type, BindingRequest request, TypeMirror returnType, MethodSpec methodSpec, boolean finalized)95     private static ModifiableBindingMethod create(
96         ModifiableBindingType type,
97         BindingRequest request,
98         TypeMirror returnType,
99         MethodSpec methodSpec,
100         boolean finalized) {
101       return new AutoValue_ModifiableBindingMethods_ModifiableBindingMethod(
102           type, request, MoreTypes.equivalence().wrap(returnType), methodSpec, finalized);
103     }
104 
105     /** Creates a {@ModifiableBindingMethod} that reimplements the current method. */
reimplement( ModifiableBindingType newModifiableBindingType, MethodSpec newImplementation, boolean finalized)106     ModifiableBindingMethod reimplement(
107         ModifiableBindingType newModifiableBindingType,
108         MethodSpec newImplementation,
109         boolean finalized) {
110       return new AutoValue_ModifiableBindingMethods_ModifiableBindingMethod(
111           newModifiableBindingType, request(), returnTypeWrapper(), newImplementation, finalized);
112     }
113 
type()114     abstract ModifiableBindingType type();
115 
request()116     abstract BindingRequest request();
117 
returnType()118     final TypeMirror returnType() {
119       return returnTypeWrapper().get();
120     }
121 
returnTypeWrapper()122     abstract Equivalence.Wrapper<TypeMirror> returnTypeWrapper();
123 
methodSpec()124     abstract MethodSpec methodSpec();
125 
finalized()126     abstract boolean finalized();
127 
128     /** Whether a {@link ModifiableBindingMethod} is for the same binding request. */
fulfillsSameRequestAs(ModifiableBindingMethod other)129     boolean fulfillsSameRequestAs(ModifiableBindingMethod other) {
130       return request().equals(other.request());
131     }
132   }
133 }
134