private static BindingElement forBinding(Binding binding) { return new AutoValue_DuplicateBindingsValidator_BindingElement( binding.kind(), binding.bindingElement(), binding.contributingModule()); } }
private void reportError(DiagnosticReporter diagnosticReporter, dagger.model.Binding binding) { diagnosticReporter.reportBinding( ERROR, binding, "%s may not depend on the production executor", binding.key()); } }
private String formatWithComponentPath(Binding binding) { return String.format( "\n%s%s [%s]", Formatter.INDENT, bindingDeclarationFormatter.format(((BindingNode) binding).delegate()), binding.componentPath()); }
switch (binding.kind()) { case DELEGATE: case PROVISION: message.append( methodSignatureFormatter.format( MoreElements.asExecutable(binding.bindingElement().get()))); break; .append(getReadableSource(binding.scope().get())) .append(" class ") .append( closestEnclosingTypeElement(binding.bindingElement().get()).getQualifiedName()); break;
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 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); }); }
@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 ImmutableSet<TypeElement> findMissingModules( ChildFactoryMethodEdge edge, BindingGraph graph) { ImmutableSet<TypeElement> factoryMethodParameters = subgraphFactoryMethodParameters(edge, graph); ComponentNode child = (ComponentNode) graph.network().incidentNodes(edge).target(); SetView<TypeElement> modulesOwnedByChild = ownedModules(child, graph); return graph.bindings().stream() // bindings owned by child .filter(binding -> binding.componentPath().equals(child.componentPath())) // that require a module instance .filter(binding -> binding.requiresModuleInstance()) .map(binding -> binding.contributingModule().get()) .distinct() // module owned by child .filter(module -> modulesOwnedByChild.contains(module)) // module not in the method parameters .filter(module -> !factoryMethodParameters.contains(module)) // module doesn't have an accessible no-arg constructor .filter(moduleType -> !componentCanMakeNewInstances(moduleType)) .collect(toImmutableSet()); }
private Optional<AnnotationMirror> mapKey(Binding binding) { return binding .bindingElement() .map(bindingElement -> getAnnotatedAnnotations(bindingElement, MapKey.class)) .flatMap( annotations -> annotations.isEmpty() ? Optional.empty() : Optional.of(getOnlyElement(annotations))); }
private Stream<DependencyEdge> provisionDependenciesOnProductionBindings( BindingGraph bindingGraph) { return bindingGraph.bindings().stream() .filter(binding -> binding.isProduction()) .flatMap(binding -> incomingDependencies(binding, bindingGraph)) .filter(edge -> !dependencyCanUseProduction(edge, bindingGraph)); }
private ImmutableList<dagger.model.Binding> nullableBindings(BindingGraph bindingGraph) { return bindingGraph.bindings().stream() .filter(binding -> binding.isNullable()) .collect(toImmutableList()); }
/** 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 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)); }
private boolean dependencyCanBeProduction(DependencyEdge edge, BindingGraph graph) { Node source = graph.network().incidentNodes(edge).source(); if (source instanceof ComponentNode) { return entryPointCanUseProduction(edge.dependencyRequest().kind()); } if (source instanceof dagger.model.Binding) { return ((dagger.model.Binding) source).isProduction(); } throw new IllegalArgumentException( "expected a dagger.model.Binding or ComponentNode: " + source); }
private String dependencyErrorMessage( DependencyEdge dependencyOnProduction, BindingGraph bindingGraph) { return String.format( "%s is a provision, which cannot depend on a production.", bindingRequestingDependency(dependencyOnProduction, bindingGraph).key()); } }
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()); }
private boolean dependencyCanUseProduction(DependencyEdge edge, BindingGraph bindingGraph) { return edge.isEntryPoint() ? entryPointCanUseProduction(edge.dependencyRequest().kind()) : bindingRequestingDependency(edge, bindingGraph).isProduction(); }
private String missingBindingErrorMessage(MissingBinding missingBinding, BindingGraph graph) { Key key = missingBinding.key(); StringBuilder errorMessage = new StringBuilder(); // Wildcards should have already been checked by DependencyRequestValidator. verify(!key.type().getKind().equals(TypeKind.WILDCARD), "unexpected wildcard request: %s", key); // TODO(ronshapiro): replace "provided" with "satisfied"? errorMessage.append(key).append(" cannot be provided without "); if (isValidImplicitProvisionKey(key, types)) { errorMessage.append("an @Inject constructor or "); } errorMessage.append("an @Provides-"); // TODO(dpb): s/an/a if (allIncomingDependenciesCanUseProduction(missingBinding, graph)) { errorMessage.append(" or @Produces-"); } errorMessage.append("annotated method."); if (isValidMembersInjectionKey(key) && typeHasInjectionSites(key)) { errorMessage.append( " This type supports members injection but cannot be implicitly provided."); } graph.bindings(key).stream() .map(binding -> binding.componentPath().currentComponent()) .distinct() .forEach( component -> errorMessage .append("\nA binding with matching key exists in component: ") .append(component.getQualifiedName())); return errorMessage.toString(); }
private boolean isDispatchingAndroidInjector(Binding binding) { Key key = binding.key(); return MoreTypes.isTypeOf(DispatchingAndroidInjector.class, key.type()) && !key.qualifier().isPresent(); }
@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)); }