diff --git a/build.gradle b/build.gradle index 86d4b016..7c5f054f 100644 --- a/build.gradle +++ b/build.gradle @@ -65,5 +65,15 @@ subprojects { check("JavaxInjectOnAbstractMethod", CheckSeverity.OFF) option("NullAway:AnnotatedPackages", "dagger.reflect") } + options.setCompilerArgs(options.getCompilerArgs() + [ + // strict compilation, treat all warnings as errors, including errorprone + '-Werror', + // enable all warnings + '-Xlint:all', + // hide warning: No processor claimed any of these annotations: dagger.*,org.junit.Test + '-Xlint:-processing', + // hide warning: MethodParameters attribute introduced in version 52.0 class files is ignored in version 51.0 class files + '-Xlint:-classfile' + ]) } } diff --git a/codegen/src/main/java/dagger/internal/DaggerCodegen.java b/codegen/src/main/java/dagger/internal/DaggerCodegen.java index 6a386c0f..a635cb87 100644 --- a/codegen/src/main/java/dagger/internal/DaggerCodegen.java +++ b/codegen/src/main/java/dagger/internal/DaggerCodegen.java @@ -23,7 +23,7 @@ public static C create(Class componentClass) { return invokeStatic(findImplementationClass(componentClass), "create", componentClass); } - public static B builder(Class builderClass) { + public static B builder(Class builderClass) { Class componentClass = builderClass.getEnclosingClass(); if (componentClass == null) { throw new IllegalArgumentException(builderClass.getCanonicalName() @@ -32,6 +32,7 @@ public static B builder(Class builderClass) { return invokeStatic(findImplementationClass(componentClass), "builder", builderClass); } + @SuppressWarnings("unchecked") private static Class findImplementationClass(Class componentClass) { String implementationName = componentClass.getPackage().getName() + ".Dagger" + componentClass.getSimpleName(); diff --git a/integration-tests/src/main/java/com/example/BindsProviderNull.java b/integration-tests/src/main/java/com/example/BindsProviderNull.java new file mode 100644 index 00000000..5e3c7fdf --- /dev/null +++ b/integration-tests/src/main/java/com/example/BindsProviderNull.java @@ -0,0 +1,21 @@ +package com.example; + +import dagger.Binds; +import dagger.Component; +import dagger.Module; +import dagger.Provides; +import org.jetbrains.annotations.Nullable; + +@Component(modules = BindsProviderNull.Module1.class) +interface BindsProviderNull { + + @Nullable CharSequence string(); + + @Module + abstract class Module1 { + @Provides static @Nullable String string() { + return null; + } + @Binds abstract CharSequence charSequence(@Nullable String foo); + } +} diff --git a/integration-tests/src/main/java/com/example/ComponentProviderNull.java b/integration-tests/src/main/java/com/example/ComponentProviderNull.java new file mode 100644 index 00000000..76dbfcb0 --- /dev/null +++ b/integration-tests/src/main/java/com/example/ComponentProviderNull.java @@ -0,0 +1,19 @@ +package com.example; + +import dagger.Component; +import dagger.Module; +import dagger.Provides; +import org.jetbrains.annotations.Nullable; + +@Component(modules = ComponentProviderNull.Module1.class) +interface ComponentProviderNull { + + @Nullable String string(); + + @Module + abstract class Module1 { + @Provides static @Nullable String string() { + return null; + } + } +} diff --git a/integration-tests/src/test/java/com/example/IntegrationTest.java b/integration-tests/src/test/java/com/example/IntegrationTest.java index 1af7e331..a38893ae 100644 --- a/integration-tests/src/test/java/com/example/IntegrationTest.java +++ b/integration-tests/src/test/java/com/example/IntegrationTest.java @@ -28,6 +28,11 @@ public static Object[] parameters() { assertThat(component.string()).isEqualTo("foo"); } + @Test public void componentProviderNull() { + ComponentProviderNull component = backend.create(ComponentProviderNull.class); + assertThat(component.string()).isNull(); + } + @Test public void componentProviderQualified() { ComponentProviderQualified component = backend.create(ComponentProviderQualified.class); assertThat(component.string()).isEqualTo("foo"); @@ -40,7 +45,12 @@ public static Object[] parameters() { @Test public void bindsProvider() { BindsProvider component = backend.create(BindsProvider.class); - assertThat(component.string()).isEqualTo("foo"); + assertThat((String) component.string()).isEqualTo("foo"); + } + + @Test public void bindsProviderNull() { + BindsProviderNull component = backend.create(BindsProviderNull.class); + assertThat(component.string()).isNull(); } @Test public void bindIntoSet() { @@ -347,18 +357,18 @@ public static Object[] parameters() { @Test public void moduleClassAndInterfaceHierarchy() { ModuleClassAndInterfaceHierarchy component = backend.create(ModuleClassAndInterfaceHierarchy.class); - assertThat(component.string()).isEqualTo("foo"); + assertThat((String) component.string()).isEqualTo("foo"); } @Test public void moduleClassAndInterfaceDuplicatesHierarchy() { ModuleClassAndInterfaceDuplicatesHierarchy component = backend.create(ModuleClassAndInterfaceDuplicatesHierarchy.class); - assertThat(component.string()).isEqualTo("foo"); + assertThat((String) component.string()).isEqualTo("foo"); } @Test public void moduleClassHierarchy() { ModuleClassHierarchy component = backend.create(ModuleClassHierarchy.class); - assertThat(component.string()).isEqualTo("foo"); + assertThat((String) component.string()).isEqualTo("foo"); } @Test public void moduleClassHierarchyStatics() { @@ -368,12 +378,12 @@ public static Object[] parameters() { @Test public void moduleInterface() { ModuleInterface component = backend.create(ModuleInterface.class); - assertThat(component.string()).isEqualTo("foo"); + assertThat((String) component.string()).isEqualTo("foo"); } @Test public void moduleInterfaceHierarchy() { ModuleInterface component = backend.create(ModuleInterface.class); - assertThat(component.string()).isEqualTo("foo"); + assertThat((String) component.string()).isEqualTo("foo"); } private void ignoreReflectionBackend() { diff --git a/reflect-compiler/src/main/java/dagger/reflect/compiler/DaggerReflectCompiler.java b/reflect-compiler/src/main/java/dagger/reflect/compiler/DaggerReflectCompiler.java index 14a45229..e7f2ead5 100644 --- a/reflect-compiler/src/main/java/dagger/reflect/compiler/DaggerReflectCompiler.java +++ b/reflect-compiler/src/main/java/dagger/reflect/compiler/DaggerReflectCompiler.java @@ -87,7 +87,7 @@ public boolean process(Set annotations, RoundEnvironment return false; } - private static @Nullable TypeElement findBuilder(TypeElement component) { + private static @Nullable TypeElement findBuilder(Element component) { for (Element enclosed : component.getEnclosedElements()) { if (enclosed.getAnnotation(Component.Builder.class) != null) { return (TypeElement) enclosed; diff --git a/reflect/src/main/java/dagger/reflect/Binding.java b/reflect/src/main/java/dagger/reflect/Binding.java index 2335f549..5222ca00 100644 --- a/reflect/src/main/java/dagger/reflect/Binding.java +++ b/reflect/src/main/java/dagger/reflect/Binding.java @@ -92,6 +92,7 @@ final class UnlinkedBinds extends UnlinkedBinding { return new Key[] { dependency }; } + @SuppressWarnings("unchecked") @Override public Binding link(Binding[] dependencies) { return (Binding) dependencies[0]; } @@ -137,7 +138,9 @@ public Optional get() { if (dependency == null) { return Optional.empty(); } - return Optional.of((T) dependency.get()); + @SuppressWarnings("unchecked") + T value = (T) dependency.get(); + return Optional.of(value); } } @@ -179,12 +182,14 @@ final class LinkedProvides extends LinkedBinding { this.dependencies = dependencies; } - @Override public T get() { + @Override public @Nullable T get() { Object[] arguments = new Object[dependencies.length]; for (int i = 0; i < arguments.length; i++) { arguments[i] = dependencies[i].get(); } - return (T) tryInvoke(instance, method, arguments); + @SuppressWarnings("unchecked") // the binding is associated with the return type of method as key + T value = (T) tryInvoke(instance, method, arguments); + return value; } } diff --git a/reflect/src/main/java/dagger/reflect/BindingGraph.java b/reflect/src/main/java/dagger/reflect/BindingGraph.java index 545a9ed5..0d0607c2 100644 --- a/reflect/src/main/java/dagger/reflect/BindingGraph.java +++ b/reflect/src/main/java/dagger/reflect/BindingGraph.java @@ -32,6 +32,9 @@ private BindingGraph(Map> bindings, JustInTimeProvider jitProvid Binding getBinding(Key key) { Binding binding = locateBinding(key); + if (binding == null) { + throw new IllegalArgumentException("Unable to locate binding for " + key); + } return binding.isLinked() ? binding : performLinking(key, binding, new LinkedHashMap<>()); @@ -41,14 +44,17 @@ private Binding performLinking(Key key, Binding unlinked, Map[] dependencies = new Binding[dependencyKeys.length]; + Binding[] dependencies = new Binding[dependencyKeys.length]; for (int i = 0; i < dependencyKeys.length; i++) { Key dependencyKey = dependencyKeys[i]; @Nullable Binding dependency = locateBinding(dependencyKey); - if (dependency == null && Types.equals(Types.getRawType(key.type()), Optional.class)) { - continue; + if (dependency == null) { + if (Types.equals(Types.getRawType(key.type()), Optional.class)) { + continue; + } + throw new IllegalArgumentException("Unable to locate binding for " + key); } if (!dependency.isLinked()) { @@ -94,7 +100,7 @@ private Binding performLinking(Key key, Binding unlinked, Map locateBinding(Key key) { + private @Nullable Binding locateBinding(Key key) { Binding binding = bindings.get(key); if (binding != null) { return binding; @@ -107,9 +113,8 @@ private Binding performLinking(Key key, Binding unlinked, Map T create(Class componentClass, Class builderClass, Set + " must be public in order to be reflectively created"); } return builderClass.cast( - Proxy.newProxyInstance(builderClass.getClassLoader(), new Class[] { builderClass }, + Proxy.newProxyInstance(builderClass.getClassLoader(), new Class[] { builderClass }, new ComponentBuilderInvocationHandler(componentClass, builderClass, modules, dependencies))); } @@ -52,7 +52,7 @@ static T create(Class componentClass, Class builderClass, Set private final Map, Object> dependencyInstances; private ComponentBuilderInvocationHandler(Class componentClass, Class builderClass, - Set> componentModules, Set> componentDependencies) { + Iterable> componentModules, Iterable> componentDependencies) { this.componentClass = componentClass; this.builderClass = builderClass; this.boundInstances = new LinkedHashMap<>(); diff --git a/reflect/src/main/java/dagger/reflect/ComponentInvocationHandler.java b/reflect/src/main/java/dagger/reflect/ComponentInvocationHandler.java index cbf96893..05edff60 100644 --- a/reflect/src/main/java/dagger/reflect/ComponentInvocationHandler.java +++ b/reflect/src/main/java/dagger/reflect/ComponentInvocationHandler.java @@ -29,7 +29,7 @@ final class ComponentInvocationHandler implements InvocationHandler { static T create(Class cls, BindingGraph graph) { - return cls.cast(Proxy.newProxyInstance(cls.getClassLoader(), new Class[] { cls }, + return cls.cast(Proxy.newProxyInstance(cls.getClassLoader(), new Class[] { cls }, new ComponentInvocationHandler(graph))); } @@ -74,6 +74,7 @@ private static ComponentInvocationHandler.MethodInvocationHandler createMethodIn "Members injection methods may only return the injected type or void: " + method); } + @SuppressWarnings({"unchecked", "RedundantCast"}) MembersInjector injector = (MembersInjector) ReflectiveMembersInjector.create(parameterTypes[0], graph); return new MembersInjectorMethodInvocationHandler(injector, returnInstance); diff --git a/reflect/src/main/java/dagger/reflect/Reflection.java b/reflect/src/main/java/dagger/reflect/Reflection.java index 6fe2c218..e003bc69 100644 --- a/reflect/src/main/java/dagger/reflect/Reflection.java +++ b/reflect/src/main/java/dagger/reflect/Reflection.java @@ -54,7 +54,7 @@ final class Reflection { return scope; } - static void trySet(@Nullable Object instance, Field field, Object value) { + static void trySet(@Nullable Object instance, Field field, @Nullable Object value) { if ((field.getModifiers() & Modifier.PUBLIC) == 0) { field.setAccessible(true); } @@ -65,8 +65,7 @@ static void trySet(@Nullable Object instance, Field field, Object value) { } } - @Nullable - static Object tryInvoke(@Nullable Object instance, Method method, Object... arguments) { + static @Nullable Object tryInvoke(@Nullable Object instance, Method method, Object... arguments) { if ((method.getModifiers() & Modifier.PUBLIC) == 0) { method.setAccessible(true); } diff --git a/reflect/src/main/java/dagger/reflect/ReflectiveJustInTimeProvider.java b/reflect/src/main/java/dagger/reflect/ReflectiveJustInTimeProvider.java index 52285c8b..c4571caf 100644 --- a/reflect/src/main/java/dagger/reflect/ReflectiveJustInTimeProvider.java +++ b/reflect/src/main/java/dagger/reflect/ReflectiveJustInTimeProvider.java @@ -20,22 +20,25 @@ final class ReflectiveJustInTimeProvider implements BindingGraph.JustInTimeProvi if (!(type instanceof Class)) { return null; // Parameterized/array types can't be just-in-time satisfied. } - Class cls = (Class) type; + return create((Class) type); + } + private static @Nullable Binding create(Class cls) { Annotation scope = findScope(cls.getAnnotations()); if (scope != null) { throw notImplemented("Just-in-time scoped bindings"); } - Constructor[] constructors = cls.getDeclaredConstructors(); - Constructor target = null; - for (Constructor constructor : constructors) { + @SuppressWarnings("unchecked") + Constructor[] constructors = (Constructor[]) cls.getDeclaredConstructors(); + Constructor target = null; + for (Constructor constructor : constructors) { if (constructor.getAnnotation(Inject.class) != null) { if (target != null) { throw new IllegalStateException( cls.getCanonicalName() + " defines multiple @Inject-annotations constructors"); } - target = (Constructor) constructor; + target = constructor; } } if (target == null) { diff --git a/reflect/src/main/java/dagger/reflect/ReflectiveMembersInjector.java b/reflect/src/main/java/dagger/reflect/ReflectiveMembersInjector.java index d928f515..20c5352c 100644 --- a/reflect/src/main/java/dagger/reflect/ReflectiveMembersInjector.java +++ b/reflect/src/main/java/dagger/reflect/ReflectiveMembersInjector.java @@ -75,8 +75,7 @@ static MembersInjector create(Class cls, BindingGraph graph) { Type[] parameterTypes = method.getGenericParameterTypes(); Annotation[][] parameterAnnotations = method.getParameterAnnotations(); - @SuppressWarnings("rawtypes") - Binding[] bindings = new Binding[parameterTypes.length]; + Binding[] bindings = new Binding[parameterTypes.length]; for (int i = 0; i < parameterTypes.length; i++) { Key key = Key.of(findQualifier(parameterAnnotations[i]), parameterTypes[i]); bindings[i] = graph.getBinding(key); diff --git a/reflect/src/main/java/dagger/reflect/ReflectiveModuleParser.java b/reflect/src/main/java/dagger/reflect/ReflectiveModuleParser.java index 7446ae3f..ffa2c052 100644 --- a/reflect/src/main/java/dagger/reflect/ReflectiveModuleParser.java +++ b/reflect/src/main/java/dagger/reflect/ReflectiveModuleParser.java @@ -46,10 +46,10 @@ static void parse(Class moduleClass, @Nullable Object instance, TypeWrapper wrapper = TypeWrapper.NONE; if ((method.getModifiers() & ABSTRACT) != 0) { if (method.getAnnotation(Binds.class) != null) { - binding = new Binding.UnlinkedBinds(method); + binding = new Binding.UnlinkedBinds<>(method); } else if (method.getAnnotation(BindsOptionalOf.class) != null) { wrapper = TypeWrapper.OPTIONAL; - binding = new Binding.UnlinkedOptionalBinding(method); + binding = new Binding.UnlinkedOptionalBinding<>(method); } else { continue; } @@ -59,7 +59,7 @@ static void parse(Class moduleClass, @Nullable Object instance, } if (method.getAnnotation(Provides.class) != null) { - binding = new Binding.UnlinkedProvides(instance, method); + binding = new Binding.UnlinkedProvides<>(instance, method); } else { continue; } diff --git a/reflect/src/test/java/dagger/reflect/ReflectiveMembersInjectorTest.java b/reflect/src/test/java/dagger/reflect/ReflectiveMembersInjectorTest.java index 6dd8d96a..757ff427 100644 --- a/reflect/src/test/java/dagger/reflect/ReflectiveMembersInjectorTest.java +++ b/reflect/src/test/java/dagger/reflect/ReflectiveMembersInjectorTest.java @@ -21,7 +21,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; -@SuppressWarnings("ALL") // Unused fields/parameters and over-specified visibility for testing. +@SuppressWarnings("unused") // Unused fields/parameters and over-specified visibility for testing. public final class ReflectiveMembersInjectorTest { private static class PrivateField { // [dagger-compiler] error: Dagger does not support injection into private fields @@ -95,7 +95,7 @@ private static class StaticMethod { } } - private static interface Interface { + private interface Interface { // [dagger-compile] Methods with @Inject may not be abstract @Inject void interfaceMethod(String one); }