Skip to content

Commit

Permalink
Internal changes
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 654840578
  • Loading branch information
bcorso authored and Dagger Team committed Jul 22, 2024
1 parent 140e201 commit 917c005
Show file tree
Hide file tree
Showing 3 changed files with 244 additions and 12 deletions.
23 changes: 12 additions & 11 deletions java/dagger/internal/codegen/binding/BindingGraphFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -278,18 +278,19 @@ ResolvedBindings lookUpBindings(Key requestKey) {
Set<SubcomponentDeclaration> subcomponentDeclarations = new LinkedHashSet<>();

// Gather all bindings, multibindings, optional, and subcomponent declarations/contributions.
ImmutableSet<Key> keysMatchingRequest = keysMatchingRequest(requestKey);
ImmutableSet<Key> multibindingKeysMatchingRequest =
multibindingKeysMatchingRequest(requestKey);
for (Resolver resolver : getResolverLineage()) {
bindings.addAll(resolver.getLocalExplicitBindings(requestKey));
subcomponentDeclarations.addAll(resolver.declarations.subcomponents(requestKey));
// The optional binding declarations are keyed by the unwrapped type.
keyFactory.unwrapOptional(requestKey)
.map(resolver.declarations::optionalBindings)
.ifPresent(optionalBindingDeclarations::addAll);

for (Key key : keysMatchingRequest) {
for (Key key : multibindingKeysMatchingRequest) {
multibindingContributions.addAll(resolver.getLocalMultibindingContributions(key));
multibindingDeclarations.addAll(resolver.declarations.multibindings(key));
subcomponentDeclarations.addAll(resolver.declarations.subcomponents(key));
// The optional binding declarations are keyed by the unwrapped type.
keyFactory.unwrapOptional(key)
.map(resolver.declarations::optionalBindings)
.ifPresent(optionalBindingDeclarations::addAll);
}
}

Expand Down Expand Up @@ -425,12 +426,12 @@ private void addSubcomponentToOwningResolver(ContributionBinding subcomponentCre
* javac users)
* </ul>
*/
private ImmutableSet<Key> keysMatchingRequest(Key requestKey) {
private ImmutableSet<Key> multibindingKeysMatchingRequest(Key requestKey) {
return keysMatchingRequestCache.computeIfAbsent(
requestKey, this::keysMatchingRequestUncached);
requestKey, this::multibindingKeysMatchingRequestUncached);
}

private ImmutableSet<Key> keysMatchingRequestUncached(Key requestKey) {
private ImmutableSet<Key> multibindingKeysMatchingRequestUncached(Key requestKey) {
ImmutableSet.Builder<Key> keys = ImmutableSet.builder();
keys.add(requestKey);
keyFactory.unwrapSetKey(requestKey, TypeNames.PRODUCED).ifPresent(keys::add);
Expand Down Expand Up @@ -867,7 +868,7 @@ private boolean hasLocalBindings(ResolvedBindings resolvedBindings) {
* this component's modules that matches the key.
*/
private boolean hasLocalMultibindingContributions(Key requestKey) {
return keysMatchingRequest(requestKey).stream()
return multibindingKeysMatchingRequest(requestKey).stream()
.anyMatch(
multibindingKey ->
!declarations.multibindingContributions(multibindingKey).isEmpty()
Expand Down
6 changes: 5 additions & 1 deletion java/dagger/internal/codegen/xprocessing/XTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,11 @@ public static boolean isRawParameterizedType(XType type) {
case JAVAC:
return isDeclared(type)
&& type.getTypeArguments().isEmpty()
&& !type.getTypeElement().getType().getTypeArguments().isEmpty();
// TODO(b/353979671): We previously called:
// type.getTypeElement().getType().getTypeArguments().isEmpty()
// which is a bit more symmetric to the call above, but that resulted in b/353979671, so
// we've switched to checking `XTypeElement#getTypeParameters()` until the bug is fixed.
&& !type.getTypeElement().getTypeParameters().isEmpty();
case KSP:
return isDeclared(type)
// TODO(b/245619245): Due to the bug in XProcessing, the logic used for Javac won't work
Expand Down
227 changes: 227 additions & 0 deletions javatests/dagger/internal/codegen/MultibindingTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package dagger.internal.codegen;

import androidx.room.compiler.processing.XProcessingEnv;
import androidx.room.compiler.processing.util.Source;
import dagger.testing.compile.CompilerTests;
import org.junit.Test;
Expand Down Expand Up @@ -299,4 +300,230 @@ public void provideExplicitSetInParent_AndMultibindingContributionInChild() {
.onLineContaining("interface Parent");
});
}

// Regression test for b/352142595.
@Test
public void testMultibindingMapWithKotlinSource() {
Source parent =
CompilerTests.kotlinSource(
"test.Parent.kt",
"package test",
"",
"import dagger.Component",
"",
"@Component(modules = [ParentModule::class])",
"interface Parent {",
" fun usage(): Usage",
"}");
Source usage =
CompilerTests.kotlinSource(
"test.Usage.kt",
"package test",
"",
"import javax.inject.Inject",
"",
"class Usage @Inject constructor(map: Map<String, MyInterface>)");
Source parentModule =
CompilerTests.kotlinSource(
"test.ParentModule.kt",
"@file:Suppress(\"INLINE_FROM_HIGHER_PLATFORM\")", // Required to use TODO()
"package test",
"",
"import dagger.Module",
"import dagger.Provides",
"import dagger.multibindings.IntoMap",
"import dagger.multibindings.StringKey",
"",
"@Module",
"class ParentModule {",
" @Provides",
" @IntoMap",
" @StringKey(\"key\")",
" fun provideMyInterface(): MyInterface = TODO()",
"}");
Source myInterface =
CompilerTests.kotlinSource(
"test.MyInterface.kt",
"package test",
"",
"interface MyInterface");

CompilerTests.daggerCompiler(parent, parentModule, myInterface, usage)
.compile(
subject -> {
// TODO(b/284207175): Due to a bug in our KSP implementation, KSP and Javac behave
// differently. Rather than cause a breaking change by fixing this bug directly, we've
// decided to wait until b/284207175 is implemented.
if (CompilerTests.backend(subject) == XProcessingEnv.Backend.KSP) {
subject.hasErrorCount(0);
} else {
subject.hasErrorCount(1);
subject.hasErrorContaining("Map<String,? extends MyInterface> cannot be provided");
}
});
}

// Regression test for b/352142595.
@Test
public void testMultibindingMapProviderWithKotlinSource() {
Source parent =
CompilerTests.kotlinSource(
"test.Parent.kt",
"package test",
"",
"import dagger.Component",
"",
"@Component(modules = [ParentModule::class])",
"interface Parent {",
" fun usage(): Usage",
"}");
Source usage =
CompilerTests.kotlinSource(
"test.Usage.kt",
"package test",
"",
"import javax.inject.Inject",
"import javax.inject.Provider",
"",
"class Usage @Inject constructor(map: Map<String, Provider<MyInterface>>)");
Source parentModule =
CompilerTests.kotlinSource(
"test.ParentModule.kt",
"@file:Suppress(\"INLINE_FROM_HIGHER_PLATFORM\")", // Required to use TODO()
"package test",
"",
"import dagger.Module",
"import dagger.Provides",
"import dagger.multibindings.IntoMap",
"import dagger.multibindings.StringKey",
"",
"@Module",
"class ParentModule {",
" @Provides",
" @IntoMap",
" @StringKey(\"key\")",
" fun provideMyInterface(): MyInterface = TODO()",
"}");
Source myInterface =
CompilerTests.kotlinSource(
"test.MyInterface.kt",
"package test",
"",
"interface MyInterface");

CompilerTests.daggerCompiler(parent, parentModule, myInterface, usage)
.compile(
subject -> {
subject.hasErrorCount(1);
subject.hasErrorContaining(
"Map<String,? extends Provider<MyInterface>> cannot be provided");
});
}

// Regression test for b/352142595.
@Test
public void testMultibindingSetWithKotlinSource() {
Source parent =
CompilerTests.kotlinSource(
"test.Parent.kt",
"package test",
"",
"import dagger.Component",
"",
"@Component(modules = [ParentModule::class])",
"interface Parent {",
" fun usage(): Usage",
"}");
Source usage =
CompilerTests.kotlinSource(
"test.Usage.kt",
"package test",
"",
"import javax.inject.Inject",
"",
"class Usage @Inject constructor(set: Set<MyInterface>)");
Source parentModule =
CompilerTests.kotlinSource(
"test.ParentModule.kt",
"@file:Suppress(\"INLINE_FROM_HIGHER_PLATFORM\")", // Required to use TODO()
"package test",
"",
"import dagger.Module",
"import dagger.Provides",
"import dagger.multibindings.IntoSet",
"",
"@Module",
"class ParentModule {",
" @Provides",
" @IntoSet",
" fun provideMyInterface(): MyInterface = TODO()",
"}");
Source myInterface =
CompilerTests.kotlinSource(
"test.MyInterface.kt",
"package test",
"",
"interface MyInterface");

CompilerTests.daggerCompiler(parent, parentModule, myInterface, usage)
.compile(
subject -> {
subject.hasErrorCount(1);
subject.hasErrorContaining("Set<? extends MyInterface> cannot be provided");
});
}

// Regression test for b/352142595.
@Test
public void testMultibindingSetProviderWithKotlinSource() {
Source parent =
CompilerTests.kotlinSource(
"test.Parent.kt",
"package test",
"",
"import dagger.Component",
"",
"@Component(modules = [ParentModule::class])",
"interface Parent {",
" fun usage(): Usage",
"}");
Source usage =
CompilerTests.kotlinSource(
"test.Usage.kt",
"package test",
"",
"import javax.inject.Inject",
"import javax.inject.Provider",
"",
"class Usage @Inject constructor(set: Set<Provider<MyInterface>>)");
Source parentModule =
CompilerTests.kotlinSource(
"test.ParentModule.kt",
"@file:Suppress(\"INLINE_FROM_HIGHER_PLATFORM\")", // Required to use TODO()
"package test",
"",
"import dagger.Module",
"import dagger.Provides",
"import dagger.multibindings.IntoSet",
"",
"@Module",
"class ParentModule {",
" @Provides",
" @IntoSet",
" fun provideMyInterface(): MyInterface = TODO()",
"}");
Source myInterface =
CompilerTests.kotlinSource(
"test.MyInterface.kt",
"package test",
"",
"interface MyInterface");

CompilerTests.daggerCompiler(parent, parentModule, myInterface, usage)
.compile(
subject -> {
subject.hasErrorCount(1);
subject.hasErrorContaining("Set<? extends Provider<MyInterface>> cannot be provided");
});
}
}

0 comments on commit 917c005

Please sign in to comment.