1 /* 2 * Copyright (C) 2022 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 dagger.internal.codegen.model.BindingKind.DELEGATE; 20 21 import dagger.internal.codegen.binding.ContributionBinding; 22 import dagger.internal.codegen.writing.ComponentImplementation.CompilerMode; 23 24 /** Generation mode for satisfying framework request to Provision Binding. */ 25 enum FrameworkInstanceKind { 26 SWITCHING_PROVIDER, 27 STATIC_FACTORY, 28 PROVIDER_FIELD; 29 from(ContributionBinding binding, CompilerMode compilerMode)30 public static FrameworkInstanceKind from(ContributionBinding binding, CompilerMode compilerMode) { 31 if (usesSwitchingProvider(binding, compilerMode)) { 32 if (compilerMode.isFastInit()) { 33 return SWITCHING_PROVIDER; 34 } else { 35 throw new IllegalStateException( 36 "Compiler mode " + compilerMode + " cannot use Switching Provider."); 37 } 38 } else if (usesStaticFactoryCreation(binding, compilerMode)) { 39 return STATIC_FACTORY; 40 } else { 41 return PROVIDER_FIELD; 42 } 43 } 44 usesSwitchingProvider( ContributionBinding binding, CompilerMode compilerMode)45 private static boolean usesSwitchingProvider( 46 ContributionBinding binding, CompilerMode compilerMode) { 47 if (!compilerMode.isFastInit()) { 48 return false; 49 } 50 switch (binding.kind()) { 51 case ASSISTED_INJECTION: 52 case BOUND_INSTANCE: 53 case COMPONENT: 54 case COMPONENT_DEPENDENCY: 55 case DELEGATE: 56 case MEMBERS_INJECTOR: // TODO(b/199889259): Consider optimizing this for fastInit mode. 57 // These binding kinds avoid SwitchingProvider when the backing instance already exists, 58 // e.g. a component provider can use FactoryInstance.create(this). 59 return false; 60 case MULTIBOUND_SET: 61 case MULTIBOUND_MAP: 62 case OPTIONAL: 63 // These binding kinds avoid SwitchingProvider when their are no dependencies, 64 // e.g. a multibound set with no dependency can use a singleton, SetFactory.empty(). 65 return !binding.dependencies().isEmpty(); 66 case INJECTION: 67 case PROVISION: 68 case ASSISTED_FACTORY: 69 case COMPONENT_PROVISION: 70 case SUBCOMPONENT_CREATOR: 71 case PRODUCTION: 72 case COMPONENT_PRODUCTION: 73 case MEMBERS_INJECTION: 74 return true; 75 } 76 throw new AssertionError(String.format("No such binding kind: %s", binding.kind())); 77 } 78 usesStaticFactoryCreation( ContributionBinding binding, CompilerMode compilerMode)79 private static boolean usesStaticFactoryCreation( 80 ContributionBinding binding, CompilerMode compilerMode) { 81 // If {@code binding} is an unscoped provision binding with no factory arguments, then 82 // we don't need a field to hold its factory. In that case, this method returns the static 83 // select that returns the factory. 84 // member 85 if (!binding.dependencies().isEmpty() || binding.scope().isPresent()) { 86 return false; 87 } 88 switch (binding.kind()) { 89 case MULTIBOUND_MAP: 90 case MULTIBOUND_SET: 91 return true; 92 case PROVISION: 93 return !compilerMode.isFastInit() 94 && !binding.requiresModuleInstance(); 95 case INJECTION: 96 return !compilerMode.isFastInit(); 97 default: 98 return false; 99 } 100 } 101 } 102