/** * Returns {@code true} if the binding should use the static factory creation strategy. * * <p>In default mode, we always use the static factory creation strategy. In fastInit mode, we * prefer to use a SwitchingProvider instead of static factories in order to reduce class loading; * however, we allow static factories that can reused across multiple bindings, e.g. {@code * MapFactory} or {@code SetFactory}. */ private boolean useStaticFactoryCreation(ContributionBinding binding) { return !compilerOptions.fastInit() || binding.kind().equals(MULTIBOUND_MAP) || binding.kind().equals(MULTIBOUND_SET); }
static ImmutableList<TypeVariableName> bindingTypeElementTypeVariableNames(Binding binding) { if (binding instanceof ContributionBinding) { ContributionBinding contributionBinding = (ContributionBinding) binding; if (!contributionBinding.kind().equals(INJECTION) && !contributionBinding.requiresModuleInstance()) { return ImmutableList.of(); } } List<? extends TypeParameterElement> typeParameters = binding.bindingTypeElement().get().getTypeParameters(); return typeParameters.stream().map(TypeVariableName::get).collect(toImmutableList()); }
static ComponentRequirement forBoundInstance(ContributionBinding binding) { checkArgument(binding.kind().equals(BindingKind.BOUND_INSTANCE)); return forBoundInstance( binding.key(), binding.nullableType().isPresent(), binding.bindingElement().get().getSimpleName().toString()); } }
@Override public boolean equals(Object o) { if (o == this) { return true; } if (o instanceof DuplicateBindingsValidator.BindingElement) { DuplicateBindingsValidator.BindingElement that = (DuplicateBindingsValidator.BindingElement) o; return (this.bindingKind.equals(that.bindingKind())) && (this.bindingElement.equals(that.bindingElement())) && (this.contributingModule.equals(that.contributingModule())); } return false; }
private ImmutableSet<ContributionBinding> mapBindingContributions( dagger.model.Binding binding, BindingGraph bindingGraph) { checkArgument(binding.kind().equals(MULTIBOUND_MAP)); return bindingGraph.requestedBindings(binding).stream() .map(b -> (BindingNode) b) .map(b -> (ContributionBinding) b.delegate()) .collect(toImmutableSet()); }
@Override public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) { bindingGraph.bindings().stream() .filter(binding -> binding.kind().equals(INJECTION)) // TODO(dpb): Move to BindingGraph .forEach(binding -> validateInjectionBinding(binding, diagnosticReporter)); }
/** * When a binding is resolved for a {@link SubcomponentDeclaration}, adds corresponding {@link * ComponentDescriptor subcomponent} to a queue in the owning component's resolver. The queue * will be used to detect which subcomponents need to be resolved. */ private void addSubcomponentToOwningResolver(ProvisionBinding subcomponentCreatorBinding) { checkArgument(subcomponentCreatorBinding.kind().equals(SUBCOMPONENT_BUILDER)); Resolver owningResolver = getOwningResolver(subcomponentCreatorBinding).get(); TypeElement builderType = MoreTypes.asTypeElement(subcomponentCreatorBinding.key().type()); owningResolver.subcomponentsToResolve.add( owningResolver.componentDescriptor.getChildComponentWithBuilderType(builderType)); }
private void reportExplicitBindingConflictsWithInject( ImmutableSetMultimap<BindingElement, Binding> duplicateBindings, DiagnosticReporter diagnosticReporter, Kind diagnosticKind) { Binding injectBinding = rootmostBindingWithKind(k -> k.equals(INJECTION), duplicateBindings.values()); Binding explicitBinding = rootmostBindingWithKind(k -> !k.equals(INJECTION), duplicateBindings.values()); StringBuilder message = new StringBuilder() .append(explicitBinding.key()) .append(" is bound multiple times:") .append(formatWithComponentPath(injectBinding)) .append(formatWithComponentPath(explicitBinding)) .append( "\nThis condition was never validated before, and will soon be an error. " + "See https://google.github.io/dagger/conflicting-inject."); diagnosticReporter.reportBinding(diagnosticKind, explicitBinding, message.toString()); }
private static ImmutableSet<ImmutableSet<Binding>> groupBindingsByKey(BindingGraph bindingGraph) { return valueSetsForEachKey( bindingGraph.bindings().stream() .filter(binding -> !binding.kind().equals(MEMBERS_INJECTION)) .collect(toImmutableSetMultimap(Binding::key, binding -> binding))); }
/** * Returns true if this binding graph resolution is for a partial graph and the {@code @Inject} * binding's scope doesn't match any of the components in the current component ancestry. If so, * the binding is not owned by any of the currently known components, and will be owned by a * future ancestor (or, if never owned, will result in an incompatibly scoped binding error at * the root component). */ private boolean isIncorrectlyScopedInPartialGraph(ProvisionBinding binding) { checkArgument(binding.kind().equals(INJECTION)); Resolver owningResolver = getOwningResolver(binding).orElse(this); ComponentDescriptor owningComponent = owningResolver.componentDescriptor; return !rootComponent().kind().isRoot() && binding.scope().isPresent() && !owningComponent.scopes().contains(binding.scope().get()); }
/** * Returns {@code true} if the component needs to make sure the provided value is cached. * * <p>The component needs to cache the value for scoped bindings except for {@code @Binds} * bindings whose scope is no stronger than their delegate's. */ private boolean needsCaching(ResolvedBindings resolvedBindings) { if (!resolvedBindings.scope().isPresent()) { return false; } if (resolvedBindings.contributionBinding().kind().equals(DELEGATE)) { return isBindsScopeStrongerThanDependencyScope(resolvedBindings, graph); } return true; } }
/** Returns true if {@code binding} was installed in a module in this resolver's component. */ private boolean resolverContainsDelegateDeclarationForBinding(ContributionBinding binding) { return binding.kind().equals(DELEGATE) && delegateDeclarations.get(binding.key()).stream() .anyMatch( declaration -> declaration.contributingModule().equals(binding.contributingModule()) && declaration.bindingElement().equals(binding.bindingElement())); }
/** * Returns a stream of the dependencies of {@code binding} that have a key type of {@code Map<K, * Provider<AndroidInjector.Factory<?>>}. */ private Stream<Binding> injectorMapDependencies(Binding binding, BindingGraph graph) { return graph.requestedBindings(binding).stream() .filter(requestedBinding -> requestedBinding.kind().equals(BindingKind.MULTIBOUND_MAP)) .filter( requestedBinding -> { TypeMirror valueType = MoreTypes.asDeclared(requestedBinding.key().type()).getTypeArguments().get(1); if (!MoreTypes.isTypeOf(Provider.class, valueType) || !valueType.getKind().equals(TypeKind.DECLARED)) { return false; } TypeMirror providedType = MoreTypes.asDeclared(valueType).getTypeArguments().get(0); return MoreTypes.isTypeOf(AndroidInjector.Factory.class, providedType); }); }
private static String frameworkFieldName(ResolvedBindings resolvedBindings) { if (!resolvedBindings.contributionBindings().isEmpty()) { ContributionBinding binding = resolvedBindings.contributionBinding(); if (binding.bindingElement().isPresent()) { String name = BINDING_ELEMENT_NAME.visit(binding.bindingElement().get(), binding); return binding.kind().equals(MEMBERS_INJECTOR) ? name + "MembersInjector" : name; } } return KeyVariableNamer.name(resolvedBindings.key()); }
@Override public CodeBlock creationExpression() { CodeBlock createFactory = CodeBlock.of( "$T.create($L)", generatedClassNameForBinding(binding), componentBindingExpressions.getCreateMethodArgumentsCodeBlock(binding)); // When scoping a parameterized factory for an @Inject class, Java 7 cannot always infer the // type properly, so cast to a raw framework type before scoping. if (binding.kind().equals(INJECTION) && binding.unresolved().isPresent() && binding.scope().isPresent()) { return CodeBlocks.cast(createFactory, Provider.class); } else { return createFactory; } } }
/** * Returns {@code true} if the {@code @Binds} binding's scope is stronger than the scope of the * binding it depends on. */ static boolean isBindsScopeStrongerThanDependencyScope( ResolvedBindings resolvedBindings, BindingGraph graph) { ContributionBinding bindsBinding = resolvedBindings.contributionBinding(); checkArgument(bindsBinding.kind().equals(DELEGATE)); Binding dependencyBinding = graph .contributionBindings() .get(getOnlyElement(bindsBinding.dependencies()).key()) .binding(); ScopeKind bindsScope = ScopeKind.get(bindsBinding, graph); ScopeKind dependencyScope = ScopeKind.get(dependencyBinding, graph); return bindsScope.isStrongerScopeThan(dependencyScope); }
MapBindingExpression( ResolvedBindings resolvedBindings, ComponentImplementation componentImplementation, BindingGraph graph, ComponentBindingExpressions componentBindingExpressions, DaggerTypes types, DaggerElements elements) { super(resolvedBindings, componentImplementation); this.binding = (ProvisionBinding) resolvedBindings.contributionBinding(); BindingKind bindingKind = this.binding.kind(); checkArgument(bindingKind.equals(MULTIBOUND_MAP), bindingKind); this.componentBindingExpressions = componentBindingExpressions; this.types = types; this.elements = elements; this.dependencies = Maps.toMap( binding.dependencies(), dep -> graph.contributionBindings().get(dep.key()).contributionBinding()); }
/** * The {@link java.util.Set} factory class name appropriate for set bindings. * * <ul> * <li>{@link SetFactory} for provision bindings. * <li>{@link SetProducer} for production bindings for {@code Set<T>}. * <li>{@link SetOfProducedProducer} for production bindings for {@code Set<Produced<T>>}. * </ul> */ static ClassName setFactoryClassName(ContributionBinding binding) { checkArgument(binding.kind().equals(MULTIBOUND_SET)); if (binding.bindingType().equals(BindingType.PROVISION)) { return SET_FACTORY; } else { SetType setType = SetType.from(binding.key()); return setType.elementsAreTypeOf(Produced.class) ? SET_OF_PRODUCED_PRODUCER : SET_PRODUCER; } }
/** The {@link java.util.Map} factory class name appropriate for map bindings. */ static ClassName mapFactoryClassName(ContributionBinding binding) { checkState(binding.kind().equals(MULTIBOUND_MAP), binding.kind()); MapType mapType = MapType.from(binding.key()); switch (binding.bindingType()) { case PROVISION: return mapType.valuesAreTypeOf(Provider.class) ? MAP_PROVIDER_FACTORY : MAP_FACTORY; case PRODUCTION: return mapType.valuesAreFrameworkType() ? mapType.valuesAreTypeOf(Producer.class) ? MAP_OF_PRODUCER_PRODUCER : MAP_OF_PRODUCED_PRODUCER : MAP_PRODUCER; default: throw new IllegalArgumentException(binding.bindingType().toString()); } }
private boolean breaksCycle(DependencyEdge edge, BindingGraph graph) { if (edge.dependencyRequest().key().multibindingContributionIdentifier().isPresent()) { return false; } if (breaksCycle(edge.dependencyRequest().key().type(), edge.dependencyRequest().kind())) { return true; } Node target = graph.network().incidentNodes(edge).target(); if (target instanceof dagger.model.Binding && ((dagger.model.Binding) target).kind().equals(BindingKind.OPTIONAL)) { /* For @BindsOptionalOf bindings, unwrap the type inside the Optional. If the unwrapped type * breaks the cycle, so does the optional binding. */ TypeMirror optionalValueType = OptionalType.from(edge.dependencyRequest().key()).valueType(); RequestKind requestKind = getRequestKind(optionalValueType); return breaksCycle(extractKeyType(requestKind, optionalValueType), requestKind); } return false; }