1 /* 2 * Copyright (C) 2019 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.hilt.processor.internal.aggregateddeps; 18 19 import static com.google.common.base.Preconditions.checkState; 20 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; 21 22 import com.google.auto.value.AutoValue; 23 import com.google.common.collect.ImmutableSet; 24 import com.google.common.collect.ImmutableSetMultimap; 25 import com.squareup.javapoet.ClassName; 26 import dagger.hilt.processor.internal.ClassNames; 27 import dagger.hilt.processor.internal.ComponentDescriptor; 28 import dagger.hilt.processor.internal.earlyentrypoint.AggregatedEarlyEntryPointMetadata; 29 import dagger.hilt.processor.internal.uninstallmodules.AggregatedUninstallModulesMetadata; 30 import javax.lang.model.element.TypeElement; 31 import javax.lang.model.util.Elements; 32 33 /** Represents information needed to create a component (i.e. modules, entry points, etc) */ 34 @AutoValue 35 public abstract class ComponentDependencies { builder()36 private static Builder builder() { 37 return new AutoValue_ComponentDependencies.Builder(); 38 } 39 40 /** Returns the modules for a component, without any filtering. */ modules()41 public abstract ImmutableSetMultimap<ClassName, TypeElement> modules(); 42 43 /** Returns the entry points associated with the given a component. */ entryPoints()44 public abstract ImmutableSetMultimap<ClassName, TypeElement> entryPoints(); 45 46 /** Returns the component entry point associated with the given a component. */ componentEntryPoints()47 public abstract ImmutableSetMultimap<ClassName, TypeElement> componentEntryPoints(); 48 49 @AutoValue.Builder 50 abstract static class Builder { modulesBuilder()51 abstract ImmutableSetMultimap.Builder<ClassName, TypeElement> modulesBuilder(); 52 entryPointsBuilder()53 abstract ImmutableSetMultimap.Builder<ClassName, TypeElement> entryPointsBuilder(); 54 componentEntryPointsBuilder()55 abstract ImmutableSetMultimap.Builder<ClassName, TypeElement> componentEntryPointsBuilder(); 56 build()57 abstract ComponentDependencies build(); 58 } 59 60 /** Returns the component dependencies for the given metadata. */ from( ImmutableSet<ComponentDescriptor> descriptors, ImmutableSet<AggregatedDepsMetadata> aggregatedDepsMetadata, ImmutableSet<AggregatedUninstallModulesMetadata> aggregatedUninstallModulesMetadata, ImmutableSet<AggregatedEarlyEntryPointMetadata> aggregatedEarlyEntryPointMetadata, Elements elements)61 public static ComponentDependencies from( 62 ImmutableSet<ComponentDescriptor> descriptors, 63 ImmutableSet<AggregatedDepsMetadata> aggregatedDepsMetadata, 64 ImmutableSet<AggregatedUninstallModulesMetadata> aggregatedUninstallModulesMetadata, 65 ImmutableSet<AggregatedEarlyEntryPointMetadata> aggregatedEarlyEntryPointMetadata, 66 Elements elements) { 67 ImmutableSet<TypeElement> uninstalledModules = 68 ImmutableSet.<TypeElement>builder() 69 .addAll( 70 aggregatedUninstallModulesMetadata.stream() 71 .flatMap(metadata -> metadata.uninstallModuleElements().stream()) 72 // @AggregatedUninstallModules always references the user module, so convert to 73 // the generated public wrapper if needed. 74 // TODO(bcorso): Consider converting this to the public module in the processor. 75 .map(module -> PkgPrivateMetadata.publicModule(module, elements)) 76 .collect(toImmutableSet())) 77 .addAll( 78 aggregatedDepsMetadata.stream() 79 .flatMap(metadata -> metadata.replacedDependencies().stream()) 80 .collect(toImmutableSet())) 81 .build(); 82 83 ComponentDependencies.Builder componentDependencies = ComponentDependencies.builder(); 84 ImmutableSet<ClassName> componentNames = 85 descriptors.stream().map(ComponentDescriptor::component).collect(toImmutableSet()); 86 for (AggregatedDepsMetadata metadata : aggregatedDepsMetadata) { 87 for (TypeElement componentElement : metadata.componentElements()) { 88 ClassName componentName = ClassName.get(componentElement); 89 checkState( 90 componentNames.contains(componentName), "%s is not a valid Component.", componentName); 91 switch (metadata.dependencyType()) { 92 case MODULE: 93 if (!uninstalledModules.contains(metadata.dependency())) { 94 componentDependencies.modulesBuilder().put(componentName, metadata.dependency()); 95 } 96 break; 97 case ENTRY_POINT: 98 componentDependencies.entryPointsBuilder().put(componentName, metadata.dependency()); 99 break; 100 case COMPONENT_ENTRY_POINT: 101 componentDependencies 102 .componentEntryPointsBuilder() 103 .put(componentName, metadata.dependency()); 104 break; 105 } 106 } 107 } 108 109 componentDependencies 110 .entryPointsBuilder() 111 .putAll( 112 ClassNames.SINGLETON_COMPONENT, 113 aggregatedEarlyEntryPointMetadata.stream() 114 .map(AggregatedEarlyEntryPointMetadata::earlyEntryPoint) 115 // @AggregatedEarlyEntryPointMetadata always references the user module, so convert 116 // to the generated public wrapper if needed. 117 // TODO(bcorso): Consider converting this to the public module in the processor. 118 .map(entryPoint -> PkgPrivateMetadata.publicEarlyEntryPoint(entryPoint, elements)) 119 .collect(toImmutableSet())); 120 121 return componentDependencies.build(); 122 } 123 } 124