private String multibindingTypeString(dagger.model.Binding multibinding) { switch (multibinding.kind()) { case MULTIBOUND_MAP: return "Map"; case MULTIBOUND_SET: return "Set"; default: throw new AssertionError(multibinding); } }
/** Returns the binding of the given kind that is closest to the root component. */ private static Binding rootmostBindingWithKind( Predicate<BindingKind> bindingKindPredicate, ImmutableCollection<Binding> bindings) { return bindings.stream() .filter(b -> bindingKindPredicate.test(b.kind())) .min(BY_LENGTH_OF_COMPONENT_PATH) .get(); }
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)); }
private static BindingElement forBinding(Binding binding) { return new AutoValue_DuplicateBindingsValidator_BindingElement( binding.kind(), binding.bindingElement(), binding.contributingModule()); } }
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))); }
private String incompatibleBindingsMessage( Key key, ImmutableSet<Binding> duplicateBindings, BindingGraph graph) { ImmutableSet<dagger.model.Binding> multibindings = duplicateBindings.stream() .filter(binding -> binding.kind().isMultibinding()) .collect(toImmutableSet()); verify( multibindings.size() == 1, "expected only one multibinding for %s: %s", key, multibindings); StringBuilder message = new StringBuilder(); java.util.Formatter messageFormatter = new java.util.Formatter(message); messageFormatter.format("%s has incompatible bindings or declarations:\n", key); message.append(INDENT); dagger.model.Binding multibinding = getOnlyElement(multibindings); messageFormatter.format("%s bindings and declarations:", multibindingTypeString(multibinding)); formatDeclarations(message, 2, declarations(graph, multibindings)); Set<dagger.model.Binding> uniqueBindings = Sets.filter(duplicateBindings, binding -> !binding.equals(multibinding)); message.append('\n').append(INDENT).append("Unique bindings and declarations:"); formatDeclarations( message, 2, Sets.filter( declarations(graph, uniqueBindings), declaration -> !(declaration instanceof MultibindingDeclaration))); return message.toString(); }
/** * 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); }); }
switch (binding.kind()) { case DELEGATE: case PROVISION:
@Override public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) { ImmutableSetMultimap.Builder<ComponentNode, dagger.model.Binding> incompatibleBindings = ImmutableSetMultimap.builder(); for (dagger.model.Binding binding : bindingGraph.bindings()) { binding .scope() .filter(scope -> !scope.isReusable()) .ifPresent( scope -> { ComponentNode componentNode = bindingGraph.componentNode(binding.componentPath()).get(); if (!componentNode.scopes().contains(scope)) { // @Inject bindings in module binding graphs will appear at the properly scoped // ancestor component, so ignore them here. if (binding.kind().equals(INJECTION) && bindingGraph.isModuleBindingGraph()) { return; } incompatibleBindings.put(componentNode, binding); } }); } Multimaps.asMap(incompatibleBindings.build()) .forEach( (componentNode, bindings) -> report(componentNode, bindings, bindingGraph, diagnosticReporter)); }
private void reportDuplicateBindings( ImmutableSetMultimap<BindingElement, Binding> duplicateBindings, BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) { if (explicitBindingConfictsWithInject(duplicateBindings.keySet())) { compilerOptions .explicitBindingConflictsWithInjectValidationType() .diagnosticKind() .ifPresent( diagnosticKind -> reportExplicitBindingConflictsWithInject( duplicateBindings, diagnosticReporter, diagnosticKind)); return; } ImmutableSet<Binding> bindings = ImmutableSet.copyOf(duplicateBindings.values()); Binding oneBinding = bindings.asList().get(0); diagnosticReporter.reportBinding( ERROR, oneBinding, Iterables.any(bindings, binding -> binding.kind().isMultibinding()) ? incompatibleBindingsMessage(oneBinding.key(), bindings, bindingGraph) : duplicateBindingMessage(oneBinding.key(), bindings, bindingGraph)); }
ImmutableSetMultimap<Key, dagger.model.Binding> mapMultibindings = bindingGraph.bindings().stream() .filter(node -> node.kind().equals(MULTIBOUND_MAP)) .collect(toImmutableSetMultimap(dagger.model.Binding::key, node -> node));
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; }