• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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