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; 18 19 import com.google.common.collect.ImmutableSet; 20 import com.google.common.collect.Sets; 21 import com.squareup.javapoet.ClassName; 22 import com.squareup.javapoet.CodeBlock; 23 import dagger.internal.codegen.ModifiableBindingMethods.ModifiableBindingMethod; 24 import dagger.internal.codegen.javapoet.Expression; 25 import dagger.model.DependencyRequest; 26 import dagger.model.Key; 27 import dagger.model.RequestKind; 28 import java.util.Optional; 29 import java.util.Set; 30 31 /** An abstract base class for multibinding {@link BindingExpression}s. */ 32 abstract class MultibindingExpression extends SimpleInvocationBindingExpression { 33 private final ProvisionBinding binding; 34 private final ComponentImplementation componentImplementation; 35 MultibindingExpression( ResolvedBindings resolvedBindings, ComponentImplementation componentImplementation)36 MultibindingExpression( 37 ResolvedBindings resolvedBindings, ComponentImplementation componentImplementation) { 38 super(resolvedBindings); 39 this.componentImplementation = componentImplementation; 40 this.binding = (ProvisionBinding) resolvedBindings.contributionBinding(); 41 } 42 43 @Override getDependencyExpression(ClassName requestingClass)44 Expression getDependencyExpression(ClassName requestingClass) { 45 Expression expression = buildDependencyExpression(requestingClass); 46 componentImplementation.registerImplementedMultibinding(binding, bindingRequest()); 47 return expression; 48 } 49 50 /** 51 * Returns an expression that evaluates to the value of a multibinding request for the given 52 * requesting class. 53 */ buildDependencyExpression(ClassName requestingClass)54 protected abstract Expression buildDependencyExpression(ClassName requestingClass); 55 56 /** 57 * Returns the subset of {@code dependencies} that represent multibinding contributions that were 58 * not included in a superclass implementation of this multibinding method. This is relevant only 59 * for ahead-of-time subcomponents. When not generating ahead-of-time subcomponents there is only 60 * one implementation of a multibinding expression and all {@link DependencyRequest}s from the 61 * argment are returned. 62 */ getNewContributions( ImmutableSet<DependencyRequest> dependencies)63 protected Set<DependencyRequest> getNewContributions( 64 ImmutableSet<DependencyRequest> dependencies) { 65 ImmutableSet<Key> superclassContributions = superclassContributions(); 66 return Sets.filter( 67 dependencies, dependency -> !superclassContributions.contains(dependency.key())); 68 } 69 70 /** 71 * Returns the {@link CodeBlock} representing a call to a superclass implementation of the 72 * modifiable binding method that encapsulates this binding, if it exists. This is only possible 73 * when generating ahead-of-time subcomponents. 74 */ superMethodCall()75 protected Optional<CodeBlock> superMethodCall() { 76 if (componentImplementation.superclassImplementation().isPresent()) { 77 Optional<ModifiableBindingMethod> method = 78 componentImplementation.getModifiableBindingMethod(bindingRequest()); 79 if (method.isPresent()) { 80 if (!superclassContributions().isEmpty()) { 81 return Optional.of(CodeBlock.of("super.$L()", method.get().methodSpec().name)); 82 } 83 } 84 } 85 return Optional.empty(); 86 } 87 bindingRequest()88 private BindingRequest bindingRequest() { 89 return BindingRequest.bindingRequest(binding.key(), RequestKind.INSTANCE); 90 } 91 superclassContributions()92 private ImmutableSet<Key> superclassContributions() { 93 return componentImplementation.superclassContributionsMade(bindingRequest()); 94 } 95 } 96