1 /* 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 17 package dagger.internal.codegen.writing; 18 19 import static com.google.common.base.Preconditions.checkArgument; 20 import static com.google.common.base.Preconditions.checkNotNull; 21 import static com.google.common.collect.Iterables.getOnlyElement; 22 import static dagger.internal.codegen.base.RequestKinds.requestType; 23 import static dagger.internal.codegen.binding.BindingRequest.bindingRequest; 24 import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom; 25 import static dagger.model.BindingKind.DELEGATE; 26 27 import com.squareup.javapoet.ClassName; 28 import dagger.internal.codegen.binding.Binding; 29 import dagger.internal.codegen.binding.BindingGraph; 30 import dagger.internal.codegen.binding.BindsTypeChecker; 31 import dagger.internal.codegen.binding.ContributionBinding; 32 import dagger.internal.codegen.javapoet.Expression; 33 import dagger.internal.codegen.langmodel.DaggerElements; 34 import dagger.internal.codegen.langmodel.DaggerTypes; 35 import dagger.model.RequestKind; 36 import javax.lang.model.type.TypeMirror; 37 38 /** A {@link dagger.internal.codegen.writing.BindingExpression} for {@code @Binds} methods. */ 39 final class DelegateBindingExpression extends BindingExpression { 40 private final ContributionBinding binding; 41 private final RequestKind requestKind; 42 private final ComponentBindingExpressions componentBindingExpressions; 43 private final DaggerTypes types; 44 private final BindsTypeChecker bindsTypeChecker; 45 DelegateBindingExpression( ContributionBinding binding, RequestKind requestKind, ComponentBindingExpressions componentBindingExpressions, DaggerTypes types, DaggerElements elements)46 DelegateBindingExpression( 47 ContributionBinding binding, 48 RequestKind requestKind, 49 ComponentBindingExpressions componentBindingExpressions, 50 DaggerTypes types, 51 DaggerElements elements) { 52 this.binding = checkNotNull(binding); 53 this.requestKind = checkNotNull(requestKind); 54 this.componentBindingExpressions = checkNotNull(componentBindingExpressions); 55 this.types = checkNotNull(types); 56 this.bindsTypeChecker = new BindsTypeChecker(types, elements); 57 } 58 59 /** 60 * Returns {@code true} if the {@code @Binds} binding's scope is stronger than the scope of the 61 * binding it depends on. 62 */ isBindsScopeStrongerThanDependencyScope( ContributionBinding bindsBinding, BindingGraph graph)63 static boolean isBindsScopeStrongerThanDependencyScope( 64 ContributionBinding bindsBinding, BindingGraph graph) { 65 checkArgument(bindsBinding.kind().equals(DELEGATE)); 66 Binding dependencyBinding = 67 graph.contributionBinding(getOnlyElement(bindsBinding.dependencies()).key()); 68 ScopeKind bindsScope = ScopeKind.get(bindsBinding); 69 ScopeKind dependencyScope = ScopeKind.get(dependencyBinding); 70 return bindsScope.isStrongerScopeThan(dependencyScope); 71 } 72 73 @Override getDependencyExpression(ClassName requestingClass)74 Expression getDependencyExpression(ClassName requestingClass) { 75 Expression delegateExpression = 76 componentBindingExpressions.getDependencyExpression( 77 bindingRequest(getOnlyElement(binding.dependencies()).key(), requestKind), 78 requestingClass); 79 80 TypeMirror contributedType = binding.contributedType(); 81 switch (requestKind) { 82 case INSTANCE: 83 return instanceRequiresCast(delegateExpression, requestingClass) 84 ? delegateExpression.castTo(contributedType) 85 : delegateExpression; 86 default: 87 return castToRawTypeIfNecessary( 88 delegateExpression, requestType(requestKind, contributedType, types)); 89 } 90 } 91 instanceRequiresCast(Expression delegateExpression, ClassName requestingClass)92 private boolean instanceRequiresCast(Expression delegateExpression, ClassName requestingClass) { 93 // delegateExpression.type() could be Object if expression is satisfied with a raw 94 // Provider's get() method. 95 return !bindsTypeChecker.isAssignable( 96 delegateExpression.type(), binding.contributedType(), binding.contributionType()) 97 && isTypeAccessibleFrom(binding.contributedType(), requestingClass.packageName()); 98 } 99 100 /** 101 * If {@code delegateExpression} can be assigned to {@code desiredType} safely, then {@code 102 * delegateExpression} is returned unchanged. If the {@code delegateExpression} is already a raw 103 * type, returns {@code delegateExpression} as well, as casting would have no effect. Otherwise, 104 * returns a {@link Expression#castTo(TypeMirror) casted} version of {@code delegateExpression} 105 * to the raw type of {@code desiredType}. 106 */ 107 // TODO(ronshapiro): this probably can be generalized for usage in InjectionMethods castToRawTypeIfNecessary( Expression delegateExpression, TypeMirror desiredType)108 private Expression castToRawTypeIfNecessary( 109 Expression delegateExpression, TypeMirror desiredType) { 110 if (types.isAssignable(delegateExpression.type(), desiredType)) { 111 return delegateExpression; 112 } 113 return delegateExpression.castTo(types.erasure(desiredType)); 114 } 115 116 private enum ScopeKind { 117 UNSCOPED, 118 SINGLE_CHECK, 119 DOUBLE_CHECK, 120 ; 121 get(Binding binding)122 static ScopeKind get(Binding binding) { 123 return binding 124 .scope() 125 .map(scope -> scope.isReusable() ? SINGLE_CHECK : DOUBLE_CHECK) 126 .orElse(UNSCOPED); 127 } 128 isStrongerScopeThan(ScopeKind other)129 boolean isStrongerScopeThan(ScopeKind other) { 130 return this.ordinal() > other.ordinal(); 131 } 132 } 133 } 134