Skip to content

Commit

Permalink
Refactor module information into ModuleDescriptor. This provides a si…
Browse files Browse the repository at this point in the history
…ngle, consistent way to access information about modules.

Note: This CL changes the order in which modules are referenced in component implementations, but that shouldn't ever matter.

-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=98344654
  • Loading branch information
gk5885 authored and cgruber committed Oct 23, 2015
1 parent 73123dd commit a1b74e7
Show file tree
Hide file tree
Showing 11 changed files with 280 additions and 146 deletions.
69 changes: 28 additions & 41 deletions compiler/src/main/java/dagger/internal/codegen/BindingGraph.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
import com.google.auto.common.MoreTypes;
import com.google.auto.value.AutoValue;
import com.google.common.base.Equivalence;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
Expand All @@ -27,35 +29,27 @@
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import dagger.Component;
import dagger.Provides;
import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
import dagger.producers.Produces;
import dagger.producers.ProductionComponent;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Executor;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;

import static com.google.auto.common.MoreElements.getAnnotationMirror;
import static com.google.auto.common.MoreElements.isAnnotationPresent;
import static dagger.internal.codegen.ComponentDescriptor.isComponentContributionMethod;
import static dagger.internal.codegen.ComponentDescriptor.isComponentProductionMethod;
import static dagger.internal.codegen.ComponentDescriptor.Kind.PRODUCTION_COMPONENT;
import static dagger.internal.codegen.ConfigurationAnnotations.getComponentDependencies;
import static dagger.internal.codegen.ConfigurationAnnotations.getComponentModules;
import static dagger.internal.codegen.ConfigurationAnnotations.getTransitiveModules;
import static dagger.internal.codegen.MembersInjectionBinding.Strategy.DELEGATE;
import static dagger.internal.codegen.MembersInjectionBinding.Strategy.NO_OP;
import static dagger.internal.codegen.Util.componentCanMakeNewInstances;
import static javax.lang.model.util.ElementFilter.methodsIn;

/**
* The canonical representation of a full-resolved graph.
Expand All @@ -64,34 +58,42 @@
*/
@AutoValue
abstract class BindingGraph {
enum ModuleStrategy {
PASSED,
CONSTRUCTED,
}

abstract ComponentDescriptor componentDescriptor();
abstract ImmutableMap<TypeElement, ModuleStrategy> transitiveModules();
abstract ImmutableMap<BindingKey, ResolvedBindings> resolvedBindings();
abstract ImmutableMap<ExecutableElement, BindingGraph> subgraphs();

/**
* Returns the set of types necessary to implement the component, but are not part of the injected
* graph. This includes modules, component dependencies and an {@link Executor} in the case of
* {@link ProductionComponent}.
*/
ImmutableSet<TypeElement> componentRequirements() {
return FluentIterable.from(componentDescriptor().transitiveModules())
.transform(new Function<ModuleDescriptor, TypeElement>() {
@Override public TypeElement apply(ModuleDescriptor input) {
return input.moduleElement();
}
})
.append(componentDescriptor().dependencies())
.append(componentDescriptor().executorDependency().asSet())
.toSet();
}

static final class Factory {
private final Elements elements;
private final Types types;
private final InjectBindingRegistry injectBindingRegistry;
private final Key.Factory keyFactory;
private final DependencyRequest.Factory dependencyRequestFactory;
private final ProvisionBinding.Factory provisionBindingFactory;
private final ProductionBinding.Factory productionBindingFactory;

Factory(Elements elements,
Types types,
InjectBindingRegistry injectBindingRegistry,
Key.Factory keyFactory,
DependencyRequest.Factory dependencyRequestFactory,
ProvisionBinding.Factory provisionBindingFactory,
ProductionBinding.Factory productionBindingFactory) {
this.elements = elements;
this.types = types;
this.injectBindingRegistry = injectBindingRegistry;
this.keyFactory = keyFactory;
this.dependencyRequestFactory = dependencyRequestFactory;
Expand All @@ -109,7 +111,6 @@ private BindingGraph create(Optional<RequestResolver> parentResolver,
ImmutableSet.builder();
ImmutableSet.Builder<ProductionBinding> explicitProductionBindingsBuilder =
ImmutableSet.builder();
AnnotationMirror componentAnnotation = componentDescriptor.componentAnnotation();

// binding for the component itself
TypeElement componentDefinitionType = componentDescriptor.componentDefinitionType();
Expand Down Expand Up @@ -144,28 +145,15 @@ && isComponentProductionMethod(elements, method)) {
}
}

// Collect transitive modules provisions.
ImmutableSet<TypeElement> moduleTypes =
MoreTypes.asTypeElements(getComponentModules(componentAnnotation));

ImmutableMap.Builder<TypeElement, ModuleStrategy> transitiveModules = ImmutableMap.builder();
for (TypeElement module : getTransitiveModules(types, elements, moduleTypes)) {
transitiveModules.put(module,
(componentCanMakeNewInstances(module) && module.getTypeParameters().isEmpty())
? ModuleStrategy.CONSTRUCTED
: ModuleStrategy.PASSED);

// traverse the modules, collect the bindings
List<ExecutableElement> moduleMethods = methodsIn(elements.getAllMembers(module));
for (ExecutableElement moduleMethod : moduleMethods) {
if (isAnnotationPresent(moduleMethod, Provides.class)) {
explicitProvisionBindingsBuilder.add(
provisionBindingFactory.forProvidesMethod(moduleMethod, module.asType()));
// Collect transitive module bindings.
for (ModuleDescriptor moduleDescriptor : componentDescriptor.transitiveModules()) {
for (ContributionBinding binding : moduleDescriptor.bindings()) {
if (binding instanceof ProvisionBinding) {
explicitProvisionBindingsBuilder.add((ProvisionBinding) binding);
}
if (binding instanceof ProductionBinding) {
explicitProductionBindingsBuilder.add((ProductionBinding) binding);
}
if (isAnnotationPresent(moduleMethod, Produces.class)) {
explicitProductionBindingsBuilder.add(
productionBindingFactory.forProducesMethod(moduleMethod, module.asType()));
}
}
}

Expand All @@ -191,7 +179,6 @@ && isComponentProductionMethod(elements, method)) {

return new AutoValue_BindingGraph(
componentDescriptor,
transitiveModules.build(),
requestResolver.getResolvedBindings(),
subgraphsBuilder.build());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
import java.util.Formatter;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.inject.Singleton;
import javax.lang.model.element.AnnotationMirror;
Expand Down Expand Up @@ -392,7 +391,7 @@ private boolean validateMembersInjectionBinding(
*/
private void validateDependencyScopes(BindingGraph subject) {
ComponentDescriptor descriptor = subject.componentDescriptor();
Optional<AnnotationMirror> scope = subject.componentDescriptor().scope();
Optional<AnnotationMirror> scope = descriptor.scope();
ImmutableSet<TypeElement> scopedDependencies = scopedTypesIn(descriptor.dependencies());
if (scope.isPresent()) {
// Dagger 1.x scope compatibility requires this be suppress-able.
Expand Down Expand Up @@ -449,18 +448,13 @@ private void validateBuilders(BindingGraph subject) {
return;
}

Set<TypeElement> allDependents =
Sets.union(
Sets.union(
subject.transitiveModules().keySet(),
componentDesc.dependencies()),
componentDesc.executorDependency().asSet());
Set<TypeElement> allDependents = subject.componentRequirements();
Set<TypeElement> requiredDependents =
Sets.filter(allDependents, new Predicate<TypeElement>() {
@Override public boolean apply(TypeElement input) {
return !Util.componentCanMakeNewInstances(input);
}
});
});
final BuilderSpec spec = componentDesc.builderSpec().get();
Map<TypeElement, ExecutableElement> allSetters = spec.methodMap();

Expand All @@ -480,7 +474,7 @@ private void validateBuilders(BindingGraph subject) {
spec.builderDefinitionType());
}

Set<TypeElement> missingSetters = Sets.difference(requiredDependents, allSetters.keySet());
Set<TypeElement> missingSetters = Sets.difference(requiredDependents, allSetters.keySet());
if (!missingSetters.isEmpty()) {
reportBuilder.addItem(String.format(msgs.missingSetters(), missingSetters),
spec.builderDefinitionType());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@
import dagger.Subcomponent;
import dagger.producers.ProductionComponent;
import java.lang.annotation.Annotation;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;
import javax.inject.Provider;
import javax.lang.model.element.AnnotationMirror;
Expand All @@ -51,6 +53,7 @@
import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.ConfigurationAnnotations.enclosedBuilders;
import static dagger.internal.codegen.ConfigurationAnnotations.getComponentDependencies;
import static dagger.internal.codegen.ConfigurationAnnotations.getComponentModules;
import static dagger.internal.codegen.ConfigurationAnnotations.isComponent;
import static dagger.internal.codegen.InjectionAnnotations.getScopeAnnotation;
import static dagger.internal.codegen.Util.unwrapOptionalEquivalence;
Expand Down Expand Up @@ -84,7 +87,7 @@ enum Kind {
Class<? extends Annotation> annotationType() {
return annotationType;
}

Class<? extends Annotation> builderAnnotationType() {
return builderType;
}
Expand All @@ -105,6 +108,26 @@ Class<? extends Annotation> builderAnnotationType() {
*/
abstract ImmutableSet<TypeElement> dependencies();

abstract ImmutableSet<ModuleDescriptor> modules();

ImmutableSet<ModuleDescriptor> transitiveModules() {
Set<ModuleDescriptor> transitiveModules = new LinkedHashSet<>();
for (ModuleDescriptor module : modules()) {
addTransitiveModules(transitiveModules, module);
}
return ImmutableSet.copyOf(transitiveModules);
}

private static Set<ModuleDescriptor> addTransitiveModules(
Set<ModuleDescriptor> transitiveModules, ModuleDescriptor module) {
if (transitiveModules.add(module)) {
for (ModuleDescriptor includedModule : module.includedModules()) {
addTransitiveModules(transitiveModules, includedModule);
}
}
return transitiveModules;
}

/**
* An index of the type to which this component holds a reference (the type listed in
* {@link Component#dependencies} or {@link ProductionComponent#dependencies} as opposed to the
Expand Down Expand Up @@ -153,9 +176,9 @@ enum ComponentMethodKind {
SUBCOMPONENT,
SUBCOMPONENT_BUILDER,
}

@AutoValue
static abstract class BuilderSpec {
static abstract class BuilderSpec {
abstract TypeElement builderDefinitionType();
abstract Map<TypeElement, ExecutableElement> methodMap();
abstract ExecutableElement buildMethod();
Expand All @@ -166,11 +189,17 @@ static final class Factory {
private final Elements elements;
private final Types types;
private final DependencyRequest.Factory dependencyRequestFactory;
private final ModuleDescriptor.Factory moduleDescriptorFactory;

Factory(Elements elements, Types types, DependencyRequest.Factory dependencyRequestFactory) {
Factory(
Elements elements,
Types types,
DependencyRequest.Factory dependencyRequestFactory,
ModuleDescriptor.Factory moduleDescriptorFactory) {
this.elements = elements;
this.types = types;
this.dependencyRequestFactory = dependencyRequestFactory;
this.moduleDescriptorFactory = moduleDescriptorFactory;
}

ComponentDescriptor forComponent(TypeElement componentDefinitionType) {
Expand Down Expand Up @@ -210,6 +239,11 @@ private ComponentDescriptor create(TypeElement componentDefinitionType, Kind kin
? Optional.of(elements.getTypeElement(Executor.class.getCanonicalName()))
: Optional.<TypeElement>absent();

ImmutableSet.Builder<ModuleDescriptor> modules = ImmutableSet.builder();
for (TypeMirror moduleIncludesType : getComponentModules(componentMirror)) {
modules.add(moduleDescriptorFactory.create(MoreTypes.asTypeElement(moduleIncludesType)));
}

ImmutableSet<ExecutableElement> unimplementedMethods =
Util.getUnimplementedMethods(elements, componentDefinitionType);

Expand Down Expand Up @@ -237,21 +271,22 @@ private ComponentDescriptor create(TypeElement componentDefinitionType, Kind kin
break;
default: // nothing special to do for other methods.
}

}

ImmutableList<DeclaredType> enclosedBuilders = kind.builderAnnotationType() == null
? ImmutableList.<DeclaredType>of()
: enclosedBuilders(componentDefinitionType, kind.builderAnnotationType());
Optional<DeclaredType> builderType =
Optional.fromNullable(getOnlyElement(enclosedBuilders, null));
Optional.fromNullable(getOnlyElement(enclosedBuilders, null));

Optional<AnnotationMirror> scope = getScopeAnnotation(componentDefinitionType);
return new AutoValue_ComponentDescriptor(
kind,
componentMirror,
componentDefinitionType,
componentDependencyTypes,
modules.build(),
dependencyMethodIndex.build(),
executorDependency,
wrapOptionalInEquivalence(AnnotationMirrors.equivalence(), scope),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.collect.Sets.SetView;
import com.google.common.util.concurrent.ListenableFuture;
import dagger.Component;
import dagger.MembersInjector;
Expand Down Expand Up @@ -273,11 +272,7 @@ private ClassWriter writeBuilder(BindingGraph input, ClassName componentApiName,
// the full set of types that calling code uses to construct a component instance
ImmutableMap<TypeElement, String> componentContributionNames =
ImmutableMap.copyOf(Maps.asMap(
Sets.union(
Sets.union(
input.transitiveModules().keySet(),
input.componentDescriptor().dependencies()),
input.componentDescriptor().executorDependency().asSet()),
input.componentRequirements(),
Functions.compose(
CaseFormat.UPPER_CAMEL.converterTo(LOWER_CAMEL),
new Function<TypeElement, String>() {
Expand Down Expand Up @@ -362,14 +357,8 @@ private ClassWriter writeBuilder(BindingGraph input, ClassName componentApiName,

/** Returns true if the graph has any dependents that can't be automatically constructed. */
private boolean requiresUserSuppliedDependents(BindingGraph input) {
Set<TypeElement> allDependents =
Sets.union(
Sets.union(
input.transitiveModules().keySet(),
input.componentDescriptor().dependencies()),
input.componentDescriptor().executorDependency().asSet());
Set<TypeElement> userRequiredDependents =
Sets.filter(allDependents, new Predicate<TypeElement>() {
Sets.filter(input.componentRequirements(), new Predicate<TypeElement>() {
@Override public boolean apply(TypeElement input) {
return !Util.componentCanMakeNewInstances(input);
}
Expand Down Expand Up @@ -566,7 +555,6 @@ private void writeSubcomponentWithoutBuilder(ExecutableElement subcomponentFacto
VariableElement moduleVariable = params.get(i);
TypeElement moduleTypeElement = MoreTypes.asTypeElement(paramTypes.get(i));
TypeName moduleType = TypeNames.forTypeMirror(paramTypes.get(i));
verify(subgraph.transitiveModules().containsKey(moduleTypeElement));
componentMethod.addParameter(moduleType, moduleVariable.getSimpleName().toString());
if (!componentContributionFields.containsKey(moduleTypeElement)) {
String preferredModuleName = CaseFormat.UPPER_CAMEL.to(LOWER_CAMEL,
Expand All @@ -590,8 +578,12 @@ private void writeSubcomponentWithoutBuilder(ExecutableElement subcomponentFacto
}
}

SetView<TypeElement> uninitializedModules = Sets.difference(
subgraph.transitiveModules().keySet(), componentContributionFields.keySet());
ImmutableSet<TypeElement> uninitializedModules =
FluentIterable.from(subgraph.componentDescriptor().transitiveModules())
.transform(ModuleDescriptor.getModuleElement())
.filter(Predicates.not(Predicates.in(componentContributionFields.keySet())))
.toSet();

for (TypeElement moduleType : uninitializedModules) {
String preferredModuleName = CaseFormat.UPPER_CAMEL.to(LOWER_CAMEL,
moduleType.getSimpleName().toString());
Expand Down
Loading

0 comments on commit a1b74e7

Please sign in to comment.