blob: 9fc28d031aaa792a706026bad67a9e1bac8d5cb7 [file] [log] [blame]
dpb02db2132018-01-08 07:20:23 -08001/*
2 * Copyright (C) 2017 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
17package dagger.internal.codegen;
18
19import static com.google.common.base.Preconditions.checkNotNull;
dpb02db2132018-01-08 07:20:23 -080020
ronshapiro8d759b22018-11-05 09:57:39 -080021import com.google.common.base.Supplier;
dpb02db2132018-01-08 07:20:23 -080022import com.squareup.javapoet.CodeBlock;
ronshapiro8d759b22018-11-05 09:57:39 -080023import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
dpb02db2132018-01-08 07:20:23 -080024import dagger.model.RequestKind;
ronshapiro66dd69f2018-11-27 08:49:26 -080025import java.util.Optional;
dpb02db2132018-01-08 07:20:23 -080026import javax.lang.model.type.TypeMirror;
dpb02db2132018-01-08 07:20:23 -080027
28/** Defines a method body and return type for a given {@link BindingExpression}. */
29class BindingMethodImplementation {
ronshapiro66dd69f2018-11-27 08:49:26 -080030 private final ComponentImplementation component;
dpb356a6842018-02-07 07:45:50 -080031 private final ContributionBinding binding;
cgdecker60a5dde2018-09-07 08:44:34 -070032 private final BindingRequest request;
dpb02db2132018-01-08 07:20:23 -080033 private final BindingExpression bindingExpression;
dpb02db2132018-01-08 07:20:23 -080034 private final DaggerTypes types;
dpb02db2132018-01-08 07:20:23 -080035
36 BindingMethodImplementation(
ronshapiro66dd69f2018-11-27 08:49:26 -080037 ComponentImplementation component,
38 ContributionBinding binding,
cgdecker60a5dde2018-09-07 08:44:34 -070039 BindingRequest request,
dpb02db2132018-01-08 07:20:23 -080040 BindingExpression bindingExpression,
dpb356a6842018-02-07 07:45:50 -080041 DaggerTypes types) {
ronshapiro66dd69f2018-11-27 08:49:26 -080042 this.component = component;
43 this.binding = binding;
44 this.request = request;
dpb02db2132018-01-08 07:20:23 -080045 this.bindingExpression = checkNotNull(bindingExpression);
ronshapiro66dd69f2018-11-27 08:49:26 -080046 this.types = types;
dpb02db2132018-01-08 07:20:23 -080047 }
48
ronshapiro8d759b22018-11-05 09:57:39 -080049 /** The method's body. */
50 final CodeBlock body() {
ronshapiro66dd69f2018-11-27 08:49:26 -080051 return implementation(bindingExpression.getDependencyExpression(component.name())::codeBlock);
ronshapiro8d759b22018-11-05 09:57:39 -080052 }
53
54 /** The method's body if this method is a component method. */
ronshapiro66dd69f2018-11-27 08:49:26 -080055 final CodeBlock bodyForComponentMethod(ComponentMethodDescriptor componentMethod) {
ronshapiro8d759b22018-11-05 09:57:39 -080056 return implementation(
ronshapiro66dd69f2018-11-27 08:49:26 -080057 bindingExpression.getDependencyExpressionForComponentMethod(componentMethod, component)
58 ::codeBlock);
ronshapiro8d759b22018-11-05 09:57:39 -080059 }
60
dpb02db2132018-01-08 07:20:23 -080061 /**
62 * Returns the method body, which contains zero or more statements (including semicolons).
63 *
64 * <p>If the implementation has a non-void return type, the body will also include the {@code
65 * return} statement.
ronshapiro8d759b22018-11-05 09:57:39 -080066 *
67 * @param simpleBindingExpression the expression to retrieve an instance of this binding without
68 * the wrapping method.
dpb02db2132018-01-08 07:20:23 -080069 */
ronshapiro8d759b22018-11-05 09:57:39 -080070 CodeBlock implementation(Supplier<CodeBlock> simpleBindingExpression) {
71 return CodeBlock.of("return $L;", simpleBindingExpression.get());
dpb02db2132018-01-08 07:20:23 -080072 }
73
74 /** Returns the return type for the dependency request. */
75 final TypeMirror returnType() {
cgdecker60a5dde2018-09-07 08:44:34 -070076 if (request.isRequestKind(RequestKind.INSTANCE)
dpb02db2132018-01-08 07:20:23 -080077 && binding.contributedPrimitiveType().isPresent()) {
78 return binding.contributedPrimitiveType().get();
79 }
ronshapiro66dd69f2018-11-27 08:49:26 -080080
ronshapiro66dd69f2018-11-27 08:49:26 -080081 if (matchingComponentMethod().isPresent()) {
82 // Component methods are part of the user-defined API, and thus we must use the user-defined
ronshapiroaeec8dc2018-12-03 13:59:03 -080083 // type.
84 return matchingComponentMethod().get().resolvedReturnType(types);
ronshapiro66dd69f2018-11-27 08:49:26 -080085 }
86
87 // If the component is abstract, this method may be overridden by another implementation in a
88 // different package for which requestedType is inaccessible. In order to make that method
89 // overridable, we use the publicly accessible type. If the type is final, we don't need to
90 // worry about this, and instead just need to check accessibility of the file we're about to
91 // write
ronshapiroaeec8dc2018-12-03 13:59:03 -080092 TypeMirror requestedType = request.requestedType(binding.contributedType(), types);
ronshapiro66dd69f2018-11-27 08:49:26 -080093 return component.isAbstract()
94 ? types.publiclyAccessibleType(requestedType)
95 : types.accessibleType(requestedType, component.name());
96 }
97
98 private Optional<ComponentMethodDescriptor> matchingComponentMethod() {
99 return component.componentDescriptor().firstMatchingComponentMethod(request);
dpb02db2132018-01-08 07:20:23 -0800100 }
101}