Skip to content
Merged
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 @@ -42,6 +42,7 @@
import static dagger.internal.codegen.xprocessing.XElements.asMethod;
import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
import static dagger.internal.codegen.xprocessing.XFunSpecs.constructorBuilder;
import static dagger.internal.codegen.xprocessing.XFunSpecs.getMethodReferenceName;
import static dagger.internal.codegen.xprocessing.XFunSpecs.methodBuilder;
import static dagger.internal.codegen.xprocessing.XTypeElements.typeVariableNames;
import static dagger.internal.codegen.xprocessing.XTypeNames.factoryOf;
Expand Down Expand Up @@ -409,7 +410,8 @@ private XFunSpec staticProxyMethodForProvision(ProvisionBinding binding) {
}
XCodeBlock arguments =
copyParameters(builder, parameterNameSet, method.getParameters(), compilerOptions);
XCodeBlock invocation = XCodeBlock.of("%L.%N(%L)", module, referenceName(method), arguments);
XCodeBlock invocation =
XCodeBlock.of("%L.%N(%L)", module, getMethodReferenceName(method), arguments);

Nullability nullability = Nullability.of(method);
return builder
Expand All @@ -419,24 +421,6 @@ private XFunSpec staticProxyMethodForProvision(ProvisionBinding binding) {
.build();
}

/**
* Returns the name that should be used to reference the given binding method.
*
* <p>To ensure we properly handle internal visibility, we handle the reference differently
* depending on whether we're generating Java or Kotlin.
*
* <p>When generating Java, we use the (mangled) JVM name rather than the source name because Java
* sources do not have access to the source name of an internal element (even if they're in the
* same build unit).
*
* <p>When generating Kotlin, we use the source name rather than the JVM name because Kotlin
* sources do not have access to the (mangled) JVM name of an internal element, which should be
* fine since the generated factory should always be in the same build unit as the binding method.
*/
private String referenceName(XMethodElement method) {
return method.getJvmName();
}

private XCodeBlock maybeWrapInCheckForNull(ProvisionBinding binding, XCodeBlock codeBlock) {
return binding.shouldCheckForNull(compilerOptions)
? XCodeBlock.of(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ private static XCodeBlock copyParameterInternal(
nullability,
compilerOptions));
return isTypeNameAccessible
? XCodeBlock.of("%L", name)
: XCodeBlock.ofCast(typeName, XCodeBlock.of("%L", name));
? XCodeBlock.of("%N", name)
: XCodeBlock.ofCast(typeName, XCodeBlock.of("%N", name));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
import static dagger.internal.codegen.xprocessing.XFunSpecs.constructorBuilder;
import static dagger.internal.codegen.xprocessing.XFunSpecs.getMethodReferenceName;
import static dagger.internal.codegen.xprocessing.XFunSpecs.methodBuilder;
import static dagger.internal.codegen.xprocessing.XTypeElements.typeVariableNames;
import static dagger.internal.codegen.xprocessing.XTypeNames.membersInjectorOf;
Expand Down Expand Up @@ -181,7 +182,9 @@ private XFunSpec methodInjectionMethod(XMethodElement method, String methodName)
XCodeBlock instance = copyInstance(builder, parameterNameSet, enclosingType.getType());
XCodeBlock arguments =
copyParameters(builder, parameterNameSet, method.getParameters(), compilerOptions);
return builder.addStatement("%L.%N(%L)", instance, method.getJvmName(), arguments).build();
return builder
.addStatement("%L.%N(%L)", instance, getMethodReferenceName(method), arguments)
.build();
}

// Example:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,20 @@
// TODO(bcorso): Consider moving these methods into XProcessing library.
/** A utility class for {@link XFunSpec} helper methods. */
public final class XFunSpecs {
/**
* Returns the name to use when referencing the given method based on the language of the
* generated code.
*
* <p>When referencing a method from a generated Java source, the method's JVM name is used. When
* referencing a method from a generated Kotlin source, the method's source name is used. This is
* particularly important for cases when a Kotlin method is annotated with {@code @JvmName} or has
* internal visibility since the source name won't be available to Java and the JVM name won't be
* available to Kotlin.
*/
@SuppressWarnings("deprecation")
public static String getMethodReferenceName(XMethodElement method) {
return method.getJvmName();
}

/** Returns a {@link Builder} that overrides the given method. */
public static Builder overriding(
Expand Down
16 changes: 11 additions & 5 deletions java/dagger/testing/compile/CompilerTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,17 @@ public static Source.JavaSource javaSource(String fileName, String... srcLines)
/** Returns a new {@link Source} with the content transformed by the given function. */
public static Source transformContent(
Source source, Function<String, String> contentTransformer) {
return Source.Companion.java(
// Remove the extension from the file name so that the file name.
source.getRelativePath()
.substring(0, source.getRelativePath().lastIndexOf('.')),
contentTransformer.apply(source.getContents()));
if (source instanceof Source.KotlinSource) {
return Source.Companion.kotlin(
source.getRelativePath(),
contentTransformer.apply(source.getContents()));
} else if (source instanceof Source.JavaSource) {
return Source.Companion.java(
((Source.JavaSource) source).getQName(),
contentTransformer.apply(source.getContents()));
} else {
throw new AssertionError("Unexpected source type.");
}
}

/** Returns a {@link Compiler} instance with the given sources. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@ class AGrandchild : BChild() {
this.aGrandchildMethod = aGrandchildMethod
}

// Note: In the Java source version of this code we use protected; however, in the Kotlin source
// version we use public since Kotlin protected wouldn't allow access to the generated code.
@Inject
protected override fun aParentMethod(aParentMethod: APublicObject) {
override fun aParentMethod(aParentMethod: APublicObject) {
super.aParentMethod(aParentMethod)
}

protected override fun aChildMethod(aChildMethod: APublicObject) {
override fun aChildMethod(aChildMethod: APublicObject) {
super.aChildMethod(aChildMethod)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ open class AParent {
@Inject internal lateinit var aParentField: AInternalObject
private var aParentMethod: APublicObject? = null

// Note: In the Java source version of this code we use protected; however, in the Kotlin source
// version we use public since Kotlin protected wouldn't allow access to the generated code.
@Inject
protected open fun aParentMethod(aParentMethod: APublicObject) {
open fun aParentMethod(aParentMethod: APublicObject) {
this.aParentMethod = aParentMethod
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@ open class BChild : AParent() {
@Inject internal lateinit var aChildField: BInternalObject
private var aChildMethod: APublicObject? = null

// Note: In the Java source version of this code we use protected; however, in the Kotlin source
// version we use public since Kotlin protected wouldn't allow access to the generated code.
@Inject
protected open fun aChildMethod(aChildMethod: APublicObject) {
open fun aChildMethod(aChildMethod: APublicObject) {
this.aChildMethod = aChildMethod
}

protected override fun aParentMethod(aParentMethod: APublicObject) {
override fun aParentMethod(aParentMethod: APublicObject) {
super.aParentMethod(aParentMethod)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* 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.membersinject;

import java.util.List;
import javax.inject.Inject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

// TODO: b/477601223 - Remove this test once this bug is fixed, as it should already be covered by
// MembersInjectionTest#membersInjectorSuperTypeWithInaccessibleTypeArgument().
@SuppressWarnings("unused") // This test is just used to check that the code compiles.
@RunWith(JUnit4.class)
public class MembersInjectTypeParameterWithVarianceTest {
public static class Foo<T> {
@Inject T t;
@Inject List<T> listT;
@Inject List<? extends T> listExtendsT;
@Inject List<? extends T>[] arrayListExtendsT;

@Inject
void method(
T t,
List<T> listT,
List<? extends T> listExtendsT,
List<? extends T>[] arrayListExtendsT) {}
}

@Test
public void testBuild() {
// If this compiles, then this test is WAI.
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1479,7 +1479,8 @@ public void unprocessedMembersInjectorNotes() {
subject.hasWarningCount(0);

String generatedFileTemplate =
"dagger/internal/codegen/ComponentProcessorTestClasses_%s_MembersInjector.java";
"dagger/internal/codegen/ComponentProcessorTestClasses_%s_MembersInjector"
+ (compilerMode.isKotlinCodegenEnabled() ? ".kt" : ".java");
String noteTemplate =
"Generating a MembersInjector for "
+ "dagger.internal.codegen.ComponentProcessorTestClasses.%s.";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1778,8 +1778,7 @@ public void testQualifierMetadata() throws Exception {
subject -> {
subject.hasErrorCount(0);
assertSourceMatchesGolden(subject, "test/SomeBinding_Factory");
subject.generatedSource(
goldenFileRule.goldenSource("test/SomeBinding_MembersInjector"));
assertSourceMatchesGolden(subject, "test/SomeBinding_MembersInjector");
});
}

Expand Down Expand Up @@ -1854,8 +1853,7 @@ public void testComplexQualifierMetadata() throws Exception {
subject -> {
subject.hasErrorCount(0);
assertSourceMatchesGolden(subject, "test/SomeBinding_Factory");
subject.generatedSource(
goldenFileRule.goldenSource("test/SomeBinding_MembersInjector"));
assertSourceMatchesGolden(subject, "test/SomeBinding_MembersInjector");
});
}

Expand Down Expand Up @@ -1962,9 +1960,9 @@ public void testBaseClassQualifierMetadata() throws Exception {
subject -> {
subject.hasErrorCount(0);
assertSourceMatchesGolden(subject, "test/Foo_Factory");
subject.generatedSource(goldenFileRule.goldenSource("test/Foo_MembersInjector"));
assertSourceMatchesGolden(subject, "test/Foo_MembersInjector");
assertSourceMatchesGolden(subject, "test/FooBase_Factory");
subject.generatedSource(goldenFileRule.goldenSource("test/FooBase_MembersInjector"));
assertSourceMatchesGolden(subject, "test/FooBase_MembersInjector");
});
}

Expand Down
Loading
Loading