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.checkNotNull; 20 import static com.squareup.javapoet.MethodSpec.methodBuilder; 21 import static dagger.internal.codegen.langmodel.Accessibility.isRawTypeAccessible; 22 import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom; 23 import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.PRIVATE_METHOD; 24 import static dagger.internal.codegen.xprocessing.XTypes.isDeclared; 25 import static javax.lang.model.element.Modifier.PRIVATE; 26 27 import androidx.room.compiler.processing.XProcessingEnv; 28 import androidx.room.compiler.processing.XType; 29 import com.squareup.javapoet.CodeBlock; 30 import com.squareup.javapoet.TypeName; 31 import dagger.assisted.Assisted; 32 import dagger.assisted.AssistedFactory; 33 import dagger.assisted.AssistedInject; 34 import dagger.internal.codegen.binding.BindingRequest; 35 import dagger.internal.codegen.binding.ContributionBinding; 36 import dagger.internal.codegen.compileroption.CompilerOptions; 37 import dagger.internal.codegen.javapoet.ExpressionType; 38 import dagger.internal.codegen.model.RequestKind; 39 import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation; 40 41 /** 42 * A binding expression that wraps the dependency expressions in a private, no-arg method. 43 * 44 * <p>Dependents of this binding expression will just call the no-arg private method. 45 */ 46 final class PrivateMethodRequestRepresentation extends MethodRequestRepresentation { 47 private final ShardImplementation shardImplementation; 48 private final ContributionBinding binding; 49 private final BindingRequest request; 50 private final RequestRepresentation wrappedRequestRepresentation; 51 private final CompilerOptions compilerOptions; 52 private final XProcessingEnv processingEnv; 53 private String methodName; 54 55 @AssistedInject PrivateMethodRequestRepresentation( @ssisted BindingRequest request, @Assisted ContributionBinding binding, @Assisted RequestRepresentation wrappedRequestRepresentation, ComponentImplementation componentImplementation, XProcessingEnv processingEnv, CompilerOptions compilerOptions)56 PrivateMethodRequestRepresentation( 57 @Assisted BindingRequest request, 58 @Assisted ContributionBinding binding, 59 @Assisted RequestRepresentation wrappedRequestRepresentation, 60 ComponentImplementation componentImplementation, 61 XProcessingEnv processingEnv, 62 CompilerOptions compilerOptions) { 63 super(componentImplementation.shardImplementation(binding), processingEnv); 64 this.binding = checkNotNull(binding); 65 this.request = checkNotNull(request); 66 this.wrappedRequestRepresentation = checkNotNull(wrappedRequestRepresentation); 67 this.shardImplementation = componentImplementation.shardImplementation(binding); 68 this.compilerOptions = compilerOptions; 69 this.processingEnv = processingEnv; 70 } 71 72 @Override methodCall()73 protected CodeBlock methodCall() { 74 return CodeBlock.of("$N()", methodName()); 75 } 76 77 @Override returnType()78 protected ExpressionType returnType() { 79 XType type = request.isRequestKind(RequestKind.INSTANCE) 80 && binding.contributedPrimitiveType().isPresent() 81 ? binding.contributedPrimitiveType().get() 82 : request.requestedType(binding.contributedType(), processingEnv); 83 String requestingPackage = shardImplementation.name().packageName(); 84 if (isTypeAccessibleFrom(type, requestingPackage)) { 85 return ExpressionType.create(type); 86 } else if (isDeclared(type) && isRawTypeAccessible(type, requestingPackage)) { 87 return ExpressionType.createRawType(type); 88 } else { 89 return ExpressionType.create(processingEnv.requireType(TypeName.OBJECT)); 90 } 91 } 92 methodName()93 private String methodName() { 94 if (methodName == null) { 95 // Have to set methodName field before implementing the method in order to handle recursion. 96 methodName = shardImplementation.getUniqueMethodName(request); 97 98 // TODO(bcorso): Fix the order that these generated methods are written to the component. 99 shardImplementation.addMethod( 100 PRIVATE_METHOD, 101 methodBuilder(methodName) 102 .addModifiers(PRIVATE) 103 .returns(returnType().getTypeName()) 104 .addStatement( 105 "return $L", 106 wrappedRequestRepresentation 107 .getDependencyExpression(shardImplementation.name()) 108 .codeBlock()) 109 .build()); 110 } 111 return methodName; 112 } 113 114 @AssistedFactory 115 static interface Factory { create( BindingRequest request, ContributionBinding binding, RequestRepresentation wrappedRequestRepresentation)116 PrivateMethodRequestRepresentation create( 117 BindingRequest request, 118 ContributionBinding binding, 119 RequestRepresentation wrappedRequestRepresentation); 120 } 121 } 122