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.writing; 18 19 import static com.google.common.base.Preconditions.checkNotNull; 20 import static dagger.internal.codegen.writing.DelegateRequestRepresentation.instanceRequiresCast; 21 22 import androidx.room.compiler.processing.XProcessingEnv; 23 import com.squareup.javapoet.ClassName; 24 import dagger.assisted.Assisted; 25 import dagger.assisted.AssistedFactory; 26 import dagger.assisted.AssistedInject; 27 import dagger.internal.codegen.base.MapType; 28 import dagger.internal.codegen.binding.BindsTypeChecker; 29 import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor; 30 import dagger.internal.codegen.binding.ContributionBinding; 31 import dagger.internal.codegen.binding.DelegateBinding; 32 import dagger.internal.codegen.binding.FrameworkType; 33 import dagger.internal.codegen.javapoet.Expression; 34 import dagger.internal.codegen.javapoet.TypeNames; 35 import dagger.internal.codegen.model.BindingKind; 36 import dagger.internal.codegen.model.RequestKind; 37 38 /** A binding expression that depends on a framework instance. */ 39 final class DerivedFromFrameworkInstanceRequestRepresentation extends RequestRepresentation { 40 private final ContributionBinding binding; 41 private final RequestRepresentation frameworkRequestRepresentation; 42 private final RequestKind requestKind; 43 private final FrameworkType frameworkType; 44 private final XProcessingEnv processingEnv; 45 private final BindsTypeChecker bindsTypeChecker; 46 47 @AssistedInject DerivedFromFrameworkInstanceRequestRepresentation( @ssisted ContributionBinding binding, @Assisted RequestRepresentation frameworkRequestRepresentation, @Assisted RequestKind requestKind, @Assisted FrameworkType frameworkType, XProcessingEnv processingEnv, BindsTypeChecker bindsTypeChecker)48 DerivedFromFrameworkInstanceRequestRepresentation( 49 @Assisted ContributionBinding binding, 50 @Assisted RequestRepresentation frameworkRequestRepresentation, 51 @Assisted RequestKind requestKind, 52 @Assisted FrameworkType frameworkType, 53 XProcessingEnv processingEnv, 54 BindsTypeChecker bindsTypeChecker) { 55 this.binding = binding; 56 this.frameworkRequestRepresentation = checkNotNull(frameworkRequestRepresentation); 57 this.requestKind = requestKind; 58 this.frameworkType = checkNotNull(frameworkType); 59 this.processingEnv = processingEnv; 60 this.bindsTypeChecker = bindsTypeChecker; 61 } 62 63 @Override getDependencyExpression(ClassName requestingClass)64 Expression getDependencyExpression(ClassName requestingClass) { 65 return getDependencyExpressionFromFrameworkExpression( 66 frameworkRequestRepresentation.getDependencyExpression(requestingClass), 67 requestingClass); 68 } 69 70 @Override getDependencyExpressionForComponentMethod( ComponentMethodDescriptor componentMethod, ComponentImplementation component)71 Expression getDependencyExpressionForComponentMethod( 72 ComponentMethodDescriptor componentMethod, ComponentImplementation component) { 73 return getDependencyExpressionFromFrameworkExpression( 74 frameworkRequestRepresentation 75 .getDependencyExpressionForComponentMethod(componentMethod, component), 76 component.name()); 77 } 78 getDependencyExpressionFromFrameworkExpression( Expression frameworkExpression, ClassName requestingClass)79 private Expression getDependencyExpressionFromFrameworkExpression( 80 Expression frameworkExpression, ClassName requestingClass) { 81 Expression expression = 82 frameworkType.to( 83 requestKind, 84 frameworkExpression, 85 processingEnv); 86 87 // If it is a map type we need to do a raw type cast. This is because a user requested field 88 // type like dagger.internal.Provider<Map<K, javax.inject.Provider<V>>> isn't always assignable 89 // from something like dagger.internal.Provider<Map<K, dagger.internal.Provider<V>>> just due 90 // to variance issues. 91 if (MapType.isMapOfProvider(binding.contributedType())) { 92 return castMapOfProvider(expression, binding); 93 } 94 95 return requiresTypeCast(expression, requestingClass) 96 ? expression.castTo(binding.contributedType()) 97 : expression; 98 } 99 castMapOfProvider(Expression expression, ContributionBinding binding)100 private Expression castMapOfProvider(Expression expression, ContributionBinding binding) { 101 switch (requestKind) { 102 case INSTANCE: 103 return expression.castTo(binding.contributedType()); 104 case PROVIDER: 105 case PROVIDER_OF_LAZY: 106 return expression.castTo(processingEnv.requireType(TypeNames.DAGGER_PROVIDER).getRawType()); 107 case LAZY: 108 return expression.castTo(processingEnv.requireType(TypeNames.LAZY).getRawType()); 109 case PRODUCER: 110 case FUTURE: 111 return expression.castTo(processingEnv.requireType(TypeNames.PRODUCER).getRawType()); 112 case PRODUCED: 113 return expression.castTo(processingEnv.requireType(TypeNames.PRODUCED).getRawType()); 114 115 case MEMBERS_INJECTION: // fall through 116 } 117 throw new IllegalStateException("Unexpected request kind: " + requestKind); 118 } 119 requiresTypeCast(Expression expression, ClassName requestingClass)120 private boolean requiresTypeCast(Expression expression, ClassName requestingClass) { 121 return binding.kind().equals(BindingKind.DELEGATE) 122 && requestKind.equals(RequestKind.INSTANCE) 123 && instanceRequiresCast( 124 (DelegateBinding) binding, expression, requestingClass, bindsTypeChecker); 125 } 126 127 @AssistedFactory 128 static interface Factory { create( ContributionBinding binding, RequestRepresentation frameworkRequestRepresentation, RequestKind requestKind, FrameworkType frameworkType)129 DerivedFromFrameworkInstanceRequestRepresentation create( 130 ContributionBinding binding, 131 RequestRepresentation frameworkRequestRepresentation, 132 RequestKind requestKind, 133 FrameworkType frameworkType); 134 } 135 } 136