Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ java_library(
"//dagger-compiler/main/java/dagger/internal/codegen/kotlin",
"//dagger-compiler/main/java/dagger/internal/codegen/model",
"//dagger-compiler/main/java/dagger/internal/codegen/xprocessing",
"//dagger-compiler/main/java/dagger/internal/codegen/xprocessing:nullability",
"//dagger-compiler/main/java/dagger/internal/codegen/xprocessing:xpoet",
"//dagger-runtime/main/java/dagger:core",
"//dagger-spi",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@

package dagger.internal.codegen.compileroption;

import androidx.room3.compiler.processing.XProcessingEnv;
import androidx.room3.compiler.processing.XTypeElement;
import com.google.common.base.Ascii;
import javax.tools.Diagnostic;

/** A collection of options that dictate how the compiler will run. */
Expand Down Expand Up @@ -168,4 +170,34 @@ public int keysPerComponentShard(XTypeElement component) {
* boundaries at compile time (for Maps) and runtime (for Sets).
*/
public abstract boolean mapMultibindingDuplicateDetectionFix();

/**
* Returns {@code true} if Dagger should also look for nullable type annotations.
*
* Note that when disabled, Dagger doesn't disallow usage of nullable type annotations. Instead,
* the behavior is simply that Dagger does not look for them, so types marked with nullable type
* annotations may appear to be non-nullable.
*/
public abstract boolean nullableTypeAnnotations();

/**
* Returns {@code true} if Dagger should also look for nullable type annotations.
*
* @deprecated use {@link CompilerOptions#nullableTypeAnnotations()}. This method should only be
* used for legacy code which requires accessing this flag from static methods that don't
* easily have access to an instance of {@link CompilerOptions}.
*/
@Deprecated
public static boolean nullableTypeAnnotations(XProcessingEnv processingEnv) {
String optionName =
ProcessingEnvironmentCompilerOptions.Feature.NULLABLE_TYPE_ANNOTATIONS.toString();
String defaultValue =
ProcessingEnvironmentCompilerOptions.Feature.NULLABLE_TYPE_ANNOTATIONS
.defaultValue().name();
String optionValue =
processingEnv.getOptions().containsKey(optionName)
? processingEnv.getOptions().get(optionName)
: defaultValue;
return Ascii.equalsIgnoreCase(optionValue, FeatureStatus.ENABLED.name());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.IGNORE_PROVISION_KEY_WILDCARDS;
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.INCLUDE_STACKTRACE_WITH_DEFERRED_ERROR_MESSAGES;
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.MAP_MULTIBINDING_DUPLICATE_DETECTION_FIX;
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.NULLABLE_TYPE_ANNOTATIONS;
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.PLUGINS_VISIT_FULL_BINDING_GRAPHS;
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.STRICT_MULTIBINDING_VALIDATION;
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.STRICT_SUPERFICIAL_VALIDATION;
Expand Down Expand Up @@ -216,6 +217,11 @@ public boolean mapMultibindingDuplicateDetectionFix() {
return isEnabled(MAP_MULTIBINDING_DUPLICATE_DETECTION_FIX);
}

@Override
public boolean nullableTypeAnnotations() {
return isEnabled(NULLABLE_TYPE_ANNOTATIONS);
}

@Override
public int keysPerComponentShard(XTypeElement component) {
if (options.containsKey(KEYS_PER_COMPONENT_SHARD)) {
Expand Down Expand Up @@ -357,7 +363,9 @@ enum Feature implements EnumOption<FeatureStatus> {

VALIDATE_TRANSITIVE_COMPONENT_DEPENDENCIES(ENABLED),

MAP_MULTIBINDING_DUPLICATE_DETECTION_FIX(DISABLED);
MAP_MULTIBINDING_DUPLICATE_DETECTION_FIX(DISABLED),

NULLABLE_TYPE_ANNOTATIONS;

final FeatureStatus defaultValue;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,4 +145,9 @@ public boolean ignoreProvisionKeyWildcards() {
public boolean mapMultibindingDuplicateDetectionFix() {
return false;
}

@Override
public boolean nullableTypeAnnotations() {
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ java_library(
"//dagger-compiler/main/java/dagger/internal/codegen/kotlin",
"//dagger-compiler/main/java/dagger/internal/codegen/model",
"//dagger-compiler/main/java/dagger/internal/codegen/xprocessing",
"//dagger-compiler/main/java/dagger/internal/codegen/xprocessing:nullability",
"//dagger-runtime/main/java/dagger:core",
"//dagger-spi",
"//third_party/java/auto:value",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ java_library(
"//dagger-compiler/main/java/dagger/internal/codegen/compileroption",
"//dagger-compiler/main/java/dagger/internal/codegen/model",
"//dagger-compiler/main/java/dagger/internal/codegen/xprocessing",
"//dagger-compiler/main/java/dagger/internal/codegen/xprocessing:nullability",
"//dagger-compiler/main/java/dagger/internal/codegen/xprocessing:xpoet",
"//dagger-runtime/main/java/dagger:core",
"//dagger-spi",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ load("//tools:bazel_compat.bzl", "compat_kt_jvm_library")

package(default_visibility = ["//dagger-compiler:internal"])

NULLABILITY_SRCS = [
"Nullability.java",
]

XPOET_SRCS = [
"Accessibility.java",
"NullableTypeNames.java",
Expand All @@ -33,10 +37,25 @@ XPOET_SRCS = [
"XTypeSpecs.java",
]

java_library(
name = "nullability",
srcs = NULLABILITY_SRCS,
deps = [
":xprocessing",
"//dagger-compiler/main/java/dagger/internal/codegen/compileroption",
"//dagger-spi",
"//third_party/java/auto:value",
"//third_party/java/guava/base",
"//third_party/java/guava/collect",
"//third_party/java/javapoet",
],
)

java_library(
name = "xpoet",
srcs = XPOET_SRCS,
deps = [
":nullability",
":xprocessing",
"//dagger-compiler/main/java/dagger/internal/codegen/compileroption",
"//dagger-spi",
Expand All @@ -57,7 +76,7 @@ compat_kt_jvm_library(
"*.java",
"*.kt",
],
exclude = XPOET_SRCS,
exclude = XPOET_SRCS + NULLABILITY_SRCS,
),
exports = [
":xprocessing-lib",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import static androidx.room3.compiler.processing.XElementKt.isMethod;
import static androidx.room3.compiler.processing.XElementKt.isVariableElement;
import static androidx.room3.compiler.processing.compat.XConverters.getProcessingEnv;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static dagger.internal.codegen.xprocessing.XElements.asMethod;
Expand All @@ -36,6 +37,7 @@
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import dagger.internal.codegen.compileroption.CompilerOptions;
import java.util.Optional;

/**
Expand All @@ -57,8 +59,12 @@ public abstract class Nullability {
public static Nullability of(XElement element) {
ImmutableSet<XClassName> nonTypeUseNullableAnnotations = getNullableAnnotations(element);
Optional<XType> type = getType(element);
ImmutableSet<XClassName> typeUseNullableAnnotations =
ImmutableSet.of();
ImmutableSet<XClassName> typeUseNullableAnnotations;
if (CompilerOptions.nullableTypeAnnotations(getProcessingEnv(element))) {
typeUseNullableAnnotations = type.map(Nullability::getNullableAnnotations).orElse(ImmutableSet.of());
} else {
typeUseNullableAnnotations = ImmutableSet.of();
}
boolean isKotlinTypeNullable =
// Note: Technically, it isn't possible for Java sources to have nullable types like in
// Kotlin sources, but for some reason KSP treats certain types as nullable if they have a
Expand Down
24 changes: 24 additions & 0 deletions javatests/dagger/functional/jdk8/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,27 @@ GenJavaTests(
"//third_party/java/truth",
],
)

GenJavaLibrary(
name = "type_use_nullability_classes",
srcs = ["TypeUseNullabilityClasses.java"],
javacopts = DOCLINT_HTML_AND_SYNTAX,
deps = [
"//third_party/java/dagger",
],
)

# TODO(b/203233586): Replace with GenJavaTest
GenJavaTests(
name = "TypeUseNullabilityTest",
srcs = ["TypeUseNullabilityTest.java"],
gen_library_deps = [":type_use_nullability_classes"],
javacopts = DOCLINT_HTML_AND_SYNTAX + ["-Adagger.nullableTypeAnnotations=ENABLED"],
deps = [
"//third_party/java/dagger",
"//third_party/java/guava/base",
"//third_party/java/guava/collect",
"//third_party/java/junit",
"//third_party/java/truth",
],
)
74 changes: 74 additions & 0 deletions javatests/dagger/functional/jdk8/TypeUseNullabilityClasses.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright (C) 2026 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package dagger.functional.jdk8;

import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Inject;

/**
* This class is compiled separately from the test in order to test nullability across compilation
* boundaries.
*/
final class TypeUseNullabilityClasses {

static final String EXPECTED_STRING = "foo";
static final Integer EXPECTED_INTEGER = 123;

static final class NullFoo {
final Integer nullableInteger;

@Inject
NullFoo(@TypeUse.Nullable Integer nullableInteger) {
this.nullableInteger = nullableInteger;
}

@Inject @TypeUse.Nullable Integer nullableIntegerField;

Integer nullableMethodInjectedField;

@Inject
void inject(@TypeUse.Nullable Integer nullableMethodInjectedField) {
this.nullableMethodInjectedField = nullableMethodInjectedField;
}
}

static final class GenericFoo<T> {
T t;

GenericFoo(T t) {
this.t = t;
}
}

static final class GenericBar<T> {
@Inject @TypeUse.Nullable T t;
}

static class TypeUse {
@Target(TYPE_USE)
@Retention(RUNTIME)
@interface Nullable {}

private TypeUse() {}
}

private TypeUseNullabilityClasses() {}
}
Loading
Loading