1 /* 2 * Copyright (C) 2018 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.internal.codegen.bindinggraphvalidation; 18 19 import static dagger.internal.codegen.extension.DaggerStreams.instancesOf; 20 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList; 21 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; 22 23 import com.google.common.annotations.VisibleForTesting; 24 import com.google.common.collect.ImmutableList; 25 import com.google.common.collect.ImmutableSet; 26 import dagger.internal.codegen.compileroption.CompilerOptions; 27 import dagger.internal.codegen.model.Binding; 28 import dagger.internal.codegen.model.BindingGraph; 29 import dagger.internal.codegen.model.BindingGraph.DependencyEdge; 30 import dagger.internal.codegen.model.DiagnosticReporter; 31 import dagger.internal.codegen.validation.ValidationBindingGraphPlugin; 32 import javax.inject.Inject; 33 34 /** 35 * Reports errors or warnings (depending on the {@code -Adagger.nullableValidation} value) for each 36 * non-nullable dependency request that is satisfied by a nullable binding. 37 */ 38 final class NullableBindingValidator extends ValidationBindingGraphPlugin { 39 40 private final CompilerOptions compilerOptions; 41 42 @Inject NullableBindingValidator(CompilerOptions compilerOptions)43 NullableBindingValidator(CompilerOptions compilerOptions) { 44 this.compilerOptions = compilerOptions; 45 } 46 47 @Override visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter)48 public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) { 49 for (Binding binding : nullableBindings(bindingGraph)) { 50 for (DependencyEdge dependencyEdge : nonNullableDependencies(bindingGraph, binding)) { 51 diagnosticReporter.reportDependency( 52 compilerOptions.nullableValidationKind(), 53 dependencyEdge, 54 nullableToNonNullable( 55 binding.key().toString(), 56 binding.toString())); // binding.toString() will include the @Nullable 57 } 58 } 59 } 60 61 @Override pluginName()62 public String pluginName() { 63 return "Dagger/Nullable"; 64 } 65 nullableBindings(BindingGraph bindingGraph)66 private ImmutableList<Binding> nullableBindings(BindingGraph bindingGraph) { 67 return bindingGraph.bindings().stream() 68 .filter(binding -> binding.isNullable()) 69 .collect(toImmutableList()); 70 } 71 nonNullableDependencies( BindingGraph bindingGraph, Binding binding)72 private ImmutableSet<DependencyEdge> nonNullableDependencies( 73 BindingGraph bindingGraph, Binding binding) { 74 return bindingGraph.network().inEdges(binding).stream() 75 .flatMap(instancesOf(DependencyEdge.class)) 76 .filter(edge -> !edge.dependencyRequest().isNullable()) 77 .collect(toImmutableSet()); 78 } 79 80 @VisibleForTesting nullableToNonNullable(String key, String binding)81 static String nullableToNonNullable(String key, String binding) { 82 return String.format("%s is not nullable, but is being provided by %s", key, binding); 83 } 84 } 85