diff --git a/build.gradle b/build.gradle index 5f3fc4ed..e90dab41 100644 --- a/build.gradle +++ b/build.gradle @@ -101,6 +101,8 @@ subprojects { } tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' + options.errorprone { disableWarningsInGeneratedCode = true excludedPaths = ".*/build/generated/.*" @@ -118,6 +120,24 @@ subprojects { assertsEnabled = true } } + + options.compilerArgs += [ + // 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', + // hide warning: auxiliary class C in full/path/to/C.java should not be accessed from outside its own source file + '-Xlint:-auxiliaryclass' + ] + + if (project.findProperty("strict.compilation") == "true") { + options.compilerArgs += [ + // strict compilation, treat all warnings as errors, including errorprone + '-Werror' + ] + } } plugins.withId('java-library') { diff --git a/integration-tests/android/build.gradle b/integration-tests/android/build.gradle index 9aa37e0e..d37ce122 100644 --- a/integration-tests/android/build.gradle +++ b/integration-tests/android/build.gradle @@ -11,6 +11,7 @@ android { versionCode 1 versionName '1' + javaCompileOptions.annotationProcessorOptions.includeCompileClasspath = false } compileOptions { diff --git a/integration-tests/android/src/main/AndroidManifest.xml b/integration-tests/android/src/main/AndroidManifest.xml index ad8ab484..5a595e1f 100644 --- a/integration-tests/android/src/main/AndroidManifest.xml +++ b/integration-tests/android/src/main/AndroidManifest.xml @@ -1,11 +1,15 @@ diff --git a/integration-tests/upstream/build.gradle b/integration-tests/upstream/build.gradle index 38f182a4..1d96a7d0 100644 --- a/integration-tests/upstream/build.gradle +++ b/integration-tests/upstream/build.gradle @@ -106,3 +106,7 @@ def ensureDaggerSubmodule = tasks.create('ensureDaggerSubmodule') { } } compileTestJava.dependsOn(ensureDaggerSubmodule) + +tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' +} diff --git a/reflect-lint/src/main/java/dagger/reflect/lint/WrongRetentionDetector.java b/reflect-lint/src/main/java/dagger/reflect/lint/WrongRetentionDetector.java index 61262121..d92acdf7 100644 --- a/reflect-lint/src/main/java/dagger/reflect/lint/WrongRetentionDetector.java +++ b/reflect-lint/src/main/java/dagger/reflect/lint/WrongRetentionDetector.java @@ -134,7 +134,7 @@ private static String getQualifiedNameForValueKotlin( @NotNull JavaContext context, @Nullable UExpression annotationValue) { final Object evaluatedAnnotationValue = ConstantEvaluator.evaluate(context, annotationValue); if (evaluatedAnnotationValue instanceof kotlin.Pair) { - final kotlin.Pair value = (kotlin.Pair) evaluatedAnnotationValue; + final kotlin.Pair value = (kotlin.Pair) evaluatedAnnotationValue; final String qualifiedName = (value.getFirst() + "." + value.getSecond()); return qualifiedName.replace("/", "."); } diff --git a/reflect/src/main/java/dagger/reflect/ReflectiveJustInTimeLookupFactory.java b/reflect/src/main/java/dagger/reflect/ReflectiveJustInTimeLookupFactory.java index 20e2b3af..40bba4a0 100644 --- a/reflect/src/main/java/dagger/reflect/ReflectiveJustInTimeLookupFactory.java +++ b/reflect/src/main/java/dagger/reflect/ReflectiveJustInTimeLookupFactory.java @@ -17,28 +17,27 @@ final class ReflectiveJustInTimeLookupFactory implements JustInTimeLookup.Factor } Type type = key.type(); - Class cls; + return getJustInTimeLookup(type); + } + + private @Nullable JustInTimeLookup getJustInTimeLookup(Type type) { + Class cls; Type[] typeArguments = null; if (type instanceof ParameterizedType) { - cls = (Class) ((ParameterizedType) type).getRawType(); + // Assume that "representing the class or interface that declared this type" is a Class. + @SuppressWarnings("unchecked") + Class rawType = (Class) ((ParameterizedType) type).getRawType(); + cls = rawType; typeArguments = ((ParameterizedType) type).getActualTypeArguments(); } else if (type instanceof Class) { - cls = (Class) type; + @SuppressWarnings("unchecked") + Class directClass = (Class) type; + cls = directClass; } else { return null; // Array types can't be just-in-time satisfied. } - Constructor[] constructors = 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; - } - } + Constructor target = findSingleInjectConstructor(cls); if (target == null) { return null; // Types without an @Inject constructor cannot be just-in-time satisfied. } @@ -47,4 +46,21 @@ final class ReflectiveJustInTimeLookupFactory implements JustInTimeLookup.Factor Binding binding = new UnlinkedJustInTimeBinding<>(cls, target, typeArguments); return new JustInTimeLookup(scope, binding); } + + private static @Nullable Constructor findSingleInjectConstructor(Class cls) { + // Not modifying it, safe to use generics; see Class#getConstructors() for more info. + @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; + } + } + return target; + } } diff --git a/reflect/src/main/java/dagger/reflect/UnlinkedJustInTimeBinding.java b/reflect/src/main/java/dagger/reflect/UnlinkedJustInTimeBinding.java index 188a0dab..9601e043 100644 --- a/reflect/src/main/java/dagger/reflect/UnlinkedJustInTimeBinding.java +++ b/reflect/src/main/java/dagger/reflect/UnlinkedJustInTimeBinding.java @@ -16,7 +16,7 @@ final class UnlinkedJustInTimeBinding extends UnlinkedBinding { private final Class cls; private final Constructor constructor; // Type arguments might be used as types for this binding's parameterized constructor parameters. - @Nullable private Type[] concreteTypeArguments; + private @Nullable Type[] concreteTypeArguments; UnlinkedJustInTimeBinding( Class cls, Constructor constructor, @Nullable Type[] concreteTypeArguments) { @@ -45,7 +45,7 @@ public LinkedBinding link(Linker linker, Scope scope) { private Type getTypeKeyForParameter(Type parameterType) { if (isTypeVariable(parameterType)) { - return matchTypeToConcreteType((TypeVariable) parameterType); + return matchTypeToConcreteType((TypeVariable) parameterType); } else if (hasParameterizedTypeVariable(parameterType)) { return findKeyForParameterizedType((ParameterizedType) parameterType); } @@ -87,7 +87,7 @@ private Type[] matchingParameterizedType(Type[] typeArguments) { Type[] matchedTypeArguments = new Type[typeArguments.length]; for (int i = 0; i < typeArguments.length; i++) { if (isTypeVariable(typeArguments[i])) { - matchedTypeArguments[i] = matchTypeToConcreteType((TypeVariable) typeArguments[i]); + matchedTypeArguments[i] = matchTypeToConcreteType((TypeVariable) typeArguments[i]); } else { matchedTypeArguments[i] = typeArguments[i]; } @@ -103,7 +103,7 @@ private Type[] matchingParameterizedType(Type[] typeArguments) { * @param typeToLookup The parameterized type placeholder to lookup. * @return The matching concrete type for the placeholder. */ - private Type matchTypeToConcreteType(TypeVariable typeToLookup) { + private Type matchTypeToConcreteType(TypeVariable typeToLookup) { if (concreteTypeArguments == null) { throw new IllegalStateException( "No concrete type arguments for " + cls + " but needed for " + typeToLookup); diff --git a/reflect/src/main/java/dagger/reflect/UnlinkedMapOfProviderBinding.java b/reflect/src/main/java/dagger/reflect/UnlinkedMapOfProviderBinding.java index a22d1fe8..22d4f26a 100644 --- a/reflect/src/main/java/dagger/reflect/UnlinkedMapOfProviderBinding.java +++ b/reflect/src/main/java/dagger/reflect/UnlinkedMapOfProviderBinding.java @@ -13,11 +13,10 @@ final class UnlinkedMapOfProviderBinding extends UnlinkedBinding { } @Override - public LinkedBinding>> link(Linker linker, Scope scope) { - Map> mapOfProviders = new LinkedHashMap<>(entryBindings.size()); + public LinkedBinding link(Linker linker, Scope scope) { + Map> mapOfProviders = new LinkedHashMap<>(entryBindings.size()); for (Map.Entry entryBinding : entryBindings.entrySet()) { - LinkedBinding binding = - (LinkedBinding) entryBinding.getValue().link(linker, scope); + LinkedBinding binding = entryBinding.getValue().link(linker, scope); mapOfProviders.put(entryBinding.getKey(), binding); } return new LinkedInstanceBinding<>(mapOfProviders); diff --git a/reflect/src/main/java/dagger/reflect/UnlinkedMapOfValueBinding.java b/reflect/src/main/java/dagger/reflect/UnlinkedMapOfValueBinding.java index 92c6a153..def63329 100644 --- a/reflect/src/main/java/dagger/reflect/UnlinkedMapOfValueBinding.java +++ b/reflect/src/main/java/dagger/reflect/UnlinkedMapOfValueBinding.java @@ -13,6 +13,8 @@ final class UnlinkedMapOfValueBinding extends UnlinkedBinding { @Override public LinkedBinding link(Linker linker, Scope scope) { + // Assume that mapOfProviderKey is Map> and linker returns the correct Binding. + @SuppressWarnings("unchecked") LinkedBinding>> mapOfProviderBinding = (LinkedBinding>>) linker.get(mapOfProviderKey); return new LinkedMapOfValueBinding<>(mapOfProviderBinding); diff --git a/reflect/src/main/java/dagger/reflect/UnlinkedSetBinding.java b/reflect/src/main/java/dagger/reflect/UnlinkedSetBinding.java index d94b9f28..8f419d90 100644 --- a/reflect/src/main/java/dagger/reflect/UnlinkedSetBinding.java +++ b/reflect/src/main/java/dagger/reflect/UnlinkedSetBinding.java @@ -18,13 +18,22 @@ final class UnlinkedSetBinding extends UnlinkedBinding { public LinkedBinding link(Linker linker, Scope scope) { List> linkedElementBindings = new ArrayList<>(elementBindings.size()); for (Binding elementBinding : elementBindings) { - linkedElementBindings.add((LinkedBinding) elementBinding.link(linker, scope)); + @SuppressWarnings("unchecked") + LinkedBinding binding = (LinkedBinding) elementBinding.link(linker, scope); + linkedElementBindings.add(binding); } + List>> linkedElementsBindings = new ArrayList<>(elementsBindings.size()); for (Binding elementsBinding : elementsBindings) { - linkedElementsBindings.add((LinkedBinding>) elementsBinding.link(linker, scope)); + @SuppressWarnings("unchecked") + LinkedBinding> bindings = + (LinkedBinding>) elementsBinding.link(linker, scope); + linkedElementsBindings.add(bindings); } + + // `elementBinding` and `elementBindings` came from the same key so we can use Object as T; + // hence their types will match, this is why unchecked warnings are OK above. return new LinkedSetBinding<>(linkedElementBindings, linkedElementsBindings); }