Skip to content

Commit fb47e11

Browse files
Chang-EricDagger Team
authored andcommitted
This is a rollforward with fixes.
Add a flag -Adagger.strictMultibindingValidation that will enforce that map binding contributions bound in a parent component cannot access bindings from child components. This fixes other bugs that may result from this unintentionally previously supported behavior. This flag is default off but will become the default in the future. RELNOTES=Add -Adagger.strictMultibindingValidation to fix map binding contributions that depend on subcomponent bindings. PiperOrigin-RevId: 330633408
1 parent 1ddc41f commit fb47e11

File tree

5 files changed

+385
-7
lines changed

5 files changed

+385
-7
lines changed

java/dagger/internal/codegen/binding/BindingGraphFactory.java

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,10 @@
4646
import dagger.MembersInjector;
4747
import dagger.Reusable;
4848
import dagger.internal.codegen.base.ClearableCache;
49+
import dagger.internal.codegen.base.ContributionType;
4950
import dagger.internal.codegen.base.MapType;
5051
import dagger.internal.codegen.base.OptionalType;
52+
import dagger.internal.codegen.compileroption.CompilerOptions;
5153
import dagger.internal.codegen.langmodel.DaggerElements;
5254
import dagger.model.DependencyRequest;
5355
import dagger.model.Key;
@@ -84,6 +86,7 @@ public final class BindingGraphFactory implements ClearableCache {
8486
private final ModuleDescriptor.Factory moduleDescriptorFactory;
8587
private final BindingGraphConverter bindingGraphConverter;
8688
private final Map<Key, ImmutableSet<Key>> keysMatchingRequestCache = new HashMap<>();
89+
private final CompilerOptions compilerOptions;
8790

8891
@Inject
8992
BindingGraphFactory(
@@ -92,13 +95,15 @@ public final class BindingGraphFactory implements ClearableCache {
9295
KeyFactory keyFactory,
9396
BindingFactory bindingFactory,
9497
ModuleDescriptor.Factory moduleDescriptorFactory,
95-
BindingGraphConverter bindingGraphConverter) {
98+
BindingGraphConverter bindingGraphConverter,
99+
CompilerOptions compilerOptions) {
96100
this.elements = elements;
97101
this.injectBindingRegistry = injectBindingRegistry;
98102
this.keyFactory = keyFactory;
99103
this.bindingFactory = bindingFactory;
100104
this.moduleDescriptorFactory = moduleDescriptorFactory;
101105
this.bindingGraphConverter = bindingGraphConverter;
106+
this.compilerOptions = compilerOptions;
102107
}
103108

104109
/**
@@ -702,12 +707,25 @@ private boolean containsExplicitBinding(ContributionBinding binding) {
702707

703708
/** Returns true if {@code binding} was installed in a module in this resolver's component. */
704709
private boolean resolverContainsDelegateDeclarationForBinding(ContributionBinding binding) {
705-
return binding.kind().equals(DELEGATE)
706-
&& delegateDeclarations.get(binding.key()).stream()
707-
.anyMatch(
708-
declaration ->
709-
declaration.contributingModule().equals(binding.contributingModule())
710-
&& declaration.bindingElement().equals(binding.bindingElement()));
710+
if (!binding.kind().equals(DELEGATE)) {
711+
return false;
712+
}
713+
714+
// Map multibinding key values are wrapped with a framework type. This needs to be undone
715+
// to look it up in the delegate declarations map.
716+
// TODO(erichang): See if we can standardize the way map keys are used in these data
717+
// structures, either always wrapped or unwrapped to be consistent and less errorprone.
718+
Key bindingKey = binding.key();
719+
if (compilerOptions.strictMultibindingValidation()
720+
&& binding.contributionType().equals(ContributionType.MAP)) {
721+
bindingKey = keyFactory.unwrapMapValueType(bindingKey);
722+
}
723+
724+
return delegateDeclarations.get(bindingKey).stream()
725+
.anyMatch(
726+
declaration ->
727+
declaration.contributingModule().equals(binding.contributingModule())
728+
&& declaration.bindingElement().equals(binding.bindingElement()));
711729
}
712730

713731
/** Returns the resolver lineage from parent to child. */

java/dagger/internal/codegen/compileroption/CompilerOptions.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,11 @@ public final boolean doCheckForNulls() {
9595
public int keysPerComponentShard(TypeElement component) {
9696
return 3500;
9797
}
98+
99+
/**
100+
* This option enables a fix to an issue where Dagger previously would erroneously allow
101+
* multibinding contributions in a component to have dependencies on child components. This will
102+
* eventually become the default and enforced.
103+
*/
104+
public abstract boolean strictMultibindingValidation();
98105
}

java/dagger/internal/codegen/compileroption/JavacPluginCompilerOptions.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,4 +113,9 @@ public ValidationType explicitBindingConflictsWithInjectValidationType() {
113113
public boolean experimentalDaggerErrorMessages() {
114114
return false;
115115
}
116+
117+
@Override
118+
public boolean strictMultibindingValidation() {
119+
return false;
120+
}
116121
}

java/dagger/internal/codegen/compileroption/ProcessingEnvironmentCompilerOptions.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.FORMAT_GENERATED_SOURCE;
3131
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.IGNORE_PRIVATE_AND_STATIC_INJECTION_FOR_COMPONENT;
3232
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.PLUGINS_VISIT_FULL_BINDING_GRAPHS;
33+
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.STRICT_MULTIBINDING_VALIDATION;
3334
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.VALIDATE_TRANSITIVE_COMPONENT_DEPENDENCIES;
3435
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.WARN_IF_INJECTION_FACTORY_NOT_GENERATED_UPSTREAM;
3536
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.WRITE_PRODUCER_NAME_IN_TOKEN;
@@ -174,6 +175,11 @@ public boolean experimentalDaggerErrorMessages() {
174175
return isEnabled(EXPERIMENTAL_DAGGER_ERROR_MESSAGES);
175176
}
176177

178+
@Override
179+
public boolean strictMultibindingValidation() {
180+
return isEnabled(STRICT_MULTIBINDING_VALIDATION);
181+
}
182+
177183
@Override
178184
public int keysPerComponentShard(TypeElement component) {
179185
if (processingEnvironment.getOptions().containsKey(KEYS_PER_COMPONENT_SHARD)) {
@@ -299,6 +305,8 @@ enum Feature implements EnumOption<FeatureStatus> {
299305

300306
EXPERIMENTAL_DAGGER_ERROR_MESSAGES,
301307

308+
STRICT_MULTIBINDING_VALIDATION,
309+
302310
VALIDATE_TRANSITIVE_COMPONENT_DEPENDENCIES(ENABLED)
303311
;
304312

0 commit comments

Comments
 (0)