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