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 androidx.room.compiler.processing.compat.XConverters.toJavac; 20 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList; 21 import static dagger.internal.codegen.langmodel.Accessibility.isRawTypeAccessible; 22 import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom; 23 24 import com.squareup.javapoet.CodeBlock; 25 import dagger.assisted.Assisted; 26 import dagger.assisted.AssistedFactory; 27 import dagger.assisted.AssistedInject; 28 import dagger.internal.codegen.base.ContributionType; 29 import dagger.internal.codegen.binding.BindsTypeChecker; 30 import dagger.internal.codegen.binding.FrameworkType; 31 import dagger.internal.codegen.binding.ProvisionBinding; 32 import dagger.internal.codegen.javapoet.Expression; 33 import dagger.internal.codegen.javapoet.TypeNames; 34 import dagger.internal.codegen.langmodel.DaggerElements; 35 import dagger.internal.codegen.langmodel.DaggerTypes; 36 import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation; 37 import dagger.spi.model.BindingKind; 38 import dagger.spi.model.DependencyRequest; 39 import dagger.spi.model.RequestKind; 40 import javax.lang.model.type.TypeMirror; 41 42 /** 43 * Returns type casted expressions to satisfy dependency requests from experimental switching 44 * providers. 45 */ 46 final class ExperimentalSwitchingProviderDependencyRepresentation { 47 private final ProvisionBinding binding; 48 private final ShardImplementation shardImplementation; 49 private final BindsTypeChecker bindsTypeChecker; 50 private final DaggerTypes types; 51 private final DaggerElements elements; 52 private final TypeMirror type; 53 54 @AssistedInject ExperimentalSwitchingProviderDependencyRepresentation( @ssisted ProvisionBinding binding, ComponentImplementation componentImplementation, DaggerTypes types, DaggerElements elements)55 ExperimentalSwitchingProviderDependencyRepresentation( 56 @Assisted ProvisionBinding binding, 57 ComponentImplementation componentImplementation, 58 DaggerTypes types, 59 DaggerElements elements) { 60 this.binding = binding; 61 this.shardImplementation = componentImplementation.shardImplementation(binding); 62 this.types = types; 63 this.elements = elements; 64 this.bindsTypeChecker = new BindsTypeChecker(types, elements); 65 this.type = 66 isDelegateSetValuesBinding() 67 ? types.erasure(elements.getTypeElement(TypeNames.COLLECTION).asType()) 68 : toJavac(binding.contributedType()); 69 } 70 getDependencyExpression(RequestKind requestKind, ProvisionBinding requestingBinding)71 Expression getDependencyExpression(RequestKind requestKind, ProvisionBinding requestingBinding) { 72 int index = findIndexOfDependency(requestingBinding); 73 TypeMirror frameworkType = 74 types.getDeclaredType(elements.getTypeElement(FrameworkType.PROVIDER.frameworkClassName())); 75 Expression expression = 76 FrameworkType.PROVIDER.to( 77 requestKind, 78 Expression.create( 79 frameworkType, CodeBlock.of("(($T) dependencies[$L])", frameworkType, index)), 80 types); 81 if (usesExplicitTypeCast(expression, requestKind)) { 82 return expression.castTo(type); 83 } 84 if (usesErasedTypeCast(requestKind)) { 85 return expression.castTo(types.erasure(type)); 86 } 87 return expression; 88 } 89 findIndexOfDependency(ProvisionBinding requestingBinding)90 private int findIndexOfDependency(ProvisionBinding requestingBinding) { 91 return requestingBinding.dependencies().stream() 92 .map(DependencyRequest::key) 93 .collect(toImmutableList()) 94 .indexOf(binding.key()) 95 + (requestingBinding.requiresModuleInstance() 96 && requestingBinding.contributingModule().isPresent() 97 ? 1 98 : 0); 99 } 100 isDelegateSetValuesBinding()101 private boolean isDelegateSetValuesBinding() { 102 return binding.kind().equals(BindingKind.DELEGATE) 103 && binding.contributionType().equals(ContributionType.SET_VALUES); 104 } 105 usesExplicitTypeCast(Expression expression, RequestKind requestKind)106 private boolean usesExplicitTypeCast(Expression expression, RequestKind requestKind) { 107 // If the type is accessible, we can directly cast the expression use the type. 108 return requestKind.equals(RequestKind.INSTANCE) 109 && !bindsTypeChecker.isAssignable(expression.type(), type, binding.contributionType()) 110 && isTypeAccessibleFrom(type, shardImplementation.name().packageName()); 111 } 112 usesErasedTypeCast(RequestKind requestKind)113 private boolean usesErasedTypeCast(RequestKind requestKind) { 114 // If a type has inaccessible type arguments, then cast to raw type. 115 return requestKind.equals(RequestKind.INSTANCE) 116 && !isTypeAccessibleFrom(type, shardImplementation.name().packageName()) 117 && isRawTypeAccessible(type, shardImplementation.name().packageName()); 118 } 119 120 @AssistedFactory 121 static interface Factory { create(ProvisionBinding binding)122 ExperimentalSwitchingProviderDependencyRepresentation create(ProvisionBinding binding); 123 } 124 } 125