• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.writing;
18 
19 import static dagger.internal.codegen.model.BindingKind.DELEGATE;
20 import static dagger.internal.codegen.writing.DelegateRequestRepresentation.isBindsScopeStrongerThanDependencyScope;
21 
22 import dagger.assisted.Assisted;
23 import dagger.assisted.AssistedFactory;
24 import dagger.assisted.AssistedInject;
25 import dagger.internal.codegen.binding.BindingGraph;
26 import dagger.internal.codegen.binding.BindingRequest;
27 import dagger.internal.codegen.binding.ProvisionBinding;
28 import dagger.internal.codegen.model.RequestKind;
29 import dagger.internal.codegen.writing.ComponentImplementation.CompilerMode;
30 
31 /**
32  * A binding representation that wraps code generation methods that satisfy all kinds of request for
33  * that binding.
34  */
35 final class ProvisionBindingRepresentation implements BindingRepresentation {
36   private final BindingGraph graph;
37   private final CompilerMode compilerMode;
38   private final ProvisionBinding binding;
39   private final DirectInstanceBindingRepresentation directInstanceBindingRepresentation;
40   private final FrameworkInstanceBindingRepresentation frameworkInstanceBindingRepresentation;
41 
42   @AssistedInject
ProvisionBindingRepresentation( @ssisted ProvisionBinding binding, DirectInstanceBindingRepresentation.Factory directInstanceBindingRepresentationFactory, FrameworkInstanceBindingRepresentation.Factory frameworkInstanceBindingRepresentationFactory, BindingGraph graph, ComponentImplementation componentImplementation)43   ProvisionBindingRepresentation(
44       @Assisted ProvisionBinding binding,
45       DirectInstanceBindingRepresentation.Factory directInstanceBindingRepresentationFactory,
46       FrameworkInstanceBindingRepresentation.Factory frameworkInstanceBindingRepresentationFactory,
47       BindingGraph graph,
48       ComponentImplementation componentImplementation) {
49     this.binding = binding;
50     this.graph = graph;
51     this.compilerMode = componentImplementation.compilerMode();
52     this.directInstanceBindingRepresentation =
53         directInstanceBindingRepresentationFactory.create(binding);
54     this.frameworkInstanceBindingRepresentation =
55         frameworkInstanceBindingRepresentationFactory.create(binding);
56   }
57 
58   @Override
getRequestRepresentation(BindingRequest request)59   public RequestRepresentation getRequestRepresentation(BindingRequest request) {
60     return usesDirectInstanceExpression(request.requestKind())
61         ? directInstanceBindingRepresentation.getRequestRepresentation(request)
62         : frameworkInstanceBindingRepresentation.getRequestRepresentation(request);
63   }
64 
usesDirectInstanceExpression(RequestKind requestKind)65   private boolean usesDirectInstanceExpression(RequestKind requestKind) {
66     if (requestKind != RequestKind.INSTANCE && requestKind != RequestKind.FUTURE) {
67       return false;
68     }
69 
70     // In fast init mode, we can avoid generating direct instance expressions if a framework
71     // instance expression already exists in the graph. Default mode has more edge cases, so can not
72     // be handled with simple pre-check in the graph. For example, a provider for a subcomponent
73     // builder is backed with its direct instance, returning framework instance for both cases will
74     // form a loop. There are also difficulties introduced by manually created framework requests.
75     // TODO(wanyingd): refactor framework instance so that we don't need to generate both direct
76     // instance and framework instance representation for the same binding.
77     if (compilerMode.isFastInit() && graph.topLevelBindingGraph().hasFrameworkRequest(binding)) {
78       return false;
79     }
80 
81     switch (binding.kind()) {
82       case MEMBERS_INJECTOR:
83         // Currently, we always use a framework instance for MembersInjectors, e.g.
84         // InstanceFactory.create(Foo_MembersInjector.create(...)).
85         // TODO(b/199889259): Consider optimizing this for fastInit mode.
86       case ASSISTED_FACTORY:
87         // Assisted factory binding can be requested with framework request, and it is essentially a
88         // provider for assisted injection binding. So we will always return framework instance for
89         // assisted factory bindings.
90         return false;
91       case ASSISTED_INJECTION:
92         throw new IllegalStateException(
93             "Assisted injection binding shouldn't be requested with an instance request.");
94       default:
95         // We don't need to use Provider#get() if there's no caching, so use a direct instance.
96         // TODO(bcorso): This can be optimized in cases where we know a Provider field already
97         // exists, in which case even if it's not scoped we might as well call Provider#get().
98         return !needsCaching(binding, graph);
99     }
100   }
101 
102   /**
103    * Returns {@code true} if the component needs to make sure the provided value is cached.
104    *
105    * <p>The component needs to cache the value for scoped bindings except for {@code @Binds}
106    * bindings whose scope is no stronger than their delegate's.
107    */
needsCaching(ProvisionBinding binding, BindingGraph graph)108   static boolean needsCaching(ProvisionBinding binding, BindingGraph graph) {
109     if (!binding.scope().isPresent()) {
110       return false;
111     }
112     if (binding.kind().equals(DELEGATE)) {
113       return isBindsScopeStrongerThanDependencyScope(binding, graph);
114     }
115     return true;
116   }
117 
118   @AssistedFactory
119   static interface Factory {
create(ProvisionBinding binding)120     ProvisionBindingRepresentation create(ProvisionBinding binding);
121   }
122 }
123