Skip to content

Commit

Permalink
Understand @module bindings defined in a Kotlin Object.
Browse files Browse the repository at this point in the history
Treat all of the binding methods of a @module annotated Kotlin Object
class as static provision methods that require no module instance.

This allows Kotlin users to no longer need to use @JvmStatic to help
Dagger understand such providers.

RELNOTES=Understand @module bindings defined in a Kotlin Object. Users
whose workaround included defining a Component builder method that
received an instance of the object class must now remove such builder
method.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=269576656
  • Loading branch information
danysantiago authored and netdpb committed Sep 23, 2019
1 parent 044a79b commit 0da2180
Show file tree
Hide file tree
Showing 21 changed files with 247 additions and 125 deletions.
Expand Up @@ -50,6 +50,7 @@
import dagger.internal.codegen.binding.ComponentRequirement;
import dagger.internal.codegen.binding.ComponentRequirement.NullPolicy;
import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
import dagger.internal.codegen.writing.ComponentCreatorImplementation;
Expand All @@ -68,11 +69,14 @@ public final class ComponentCreatorImplementationFactory {

private final DaggerElements elements;
private final DaggerTypes types;
private final KotlinMetadataUtil metadataUtil;

@Inject
ComponentCreatorImplementationFactory(DaggerElements elements, DaggerTypes types) {
ComponentCreatorImplementationFactory(
DaggerElements elements, DaggerTypes types, KotlinMetadataUtil metadataUtil) {
this.elements = elements;
this.types = types;
this.metadataUtil = metadataUtil;
}

/** Returns a new creator implementation for the given component, if necessary. */
Expand Down Expand Up @@ -218,7 +222,7 @@ private MethodSpec normalSetterMethod(ComponentRequirement requirement) {
method.addStatement(
"this.$N = $L",
fields.get(requirement),
requirement.nullPolicy(elements, types).equals(NullPolicy.ALLOW)
requirement.nullPolicy(elements, types, metadataUtil).equals(NullPolicy.ALLOW)
? CodeBlock.of("$N", parameter)
: CodeBlock.of("$T.checkNotNull($N)", Preconditions.class, parameter));
return maybeReturnThis(method);
Expand Down Expand Up @@ -291,7 +295,7 @@ MethodSpec factoryMethod() {

private void addNullHandlingForField(
ComponentRequirement requirement, FieldSpec field, MethodSpec.Builder factoryMethod) {
switch (requirement.nullPolicy(elements, types)) {
switch (requirement.nullPolicy(elements, types, metadataUtil)) {
case NEW:
checkState(requirement.kind().isModule());
factoryMethod
Expand All @@ -315,7 +319,7 @@ private void addNullHandlingForField(

private void addNullHandlingForParameter(
ComponentRequirement requirement, String parameter, MethodSpec.Builder factoryMethod) {
if (!requirement.nullPolicy(elements, types).equals(NullPolicy.ALLOW)) {
if (!requirement.nullPolicy(elements, types, metadataUtil).equals(NullPolicy.ALLOW)) {
// Factory method parameters are always required unless they are a nullable
// binds-instance (i.e. ALLOW)
factoryMethod.addStatement("$T.checkNotNull($L)", Preconditions.class, parameter);
Expand Down
10 changes: 8 additions & 2 deletions java/dagger/internal/codegen/ComponentHjarProcessingStep.java
Expand Up @@ -49,6 +49,7 @@
import dagger.internal.codegen.binding.ComponentDescriptorFactory;
import dagger.internal.codegen.binding.ComponentRequirement;
import dagger.internal.codegen.binding.MethodSignature;
import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
import dagger.internal.codegen.validation.ComponentValidator;
Expand Down Expand Up @@ -89,6 +90,7 @@ final class ComponentHjarProcessingStep extends TypeCheckingProcessingStep<TypeE
private final Messager messager;
private final ComponentValidator componentValidator;
private final ComponentDescriptorFactory componentDescriptorFactory;
private final KotlinMetadataUtil metadataUtil;

@Inject
ComponentHjarProcessingStep(
Expand All @@ -98,7 +100,8 @@ final class ComponentHjarProcessingStep extends TypeCheckingProcessingStep<TypeE
Filer filer,
Messager messager,
ComponentValidator componentValidator,
ComponentDescriptorFactory componentDescriptorFactory) {
ComponentDescriptorFactory componentDescriptorFactory,
KotlinMetadataUtil metadataUtil) {
super(MoreElements::asType);
this.sourceVersion = sourceVersion;
this.elements = elements;
Expand All @@ -107,6 +110,7 @@ final class ComponentHjarProcessingStep extends TypeCheckingProcessingStep<TypeE
this.messager = messager;
this.componentValidator = componentValidator;
this.componentDescriptorFactory = componentDescriptorFactory;
this.metadataUtil = metadataUtil;
}

@Override
Expand Down Expand Up @@ -194,7 +198,9 @@ public Optional<TypeSpec.Builder> write(
if (noArgFactoryMethod
&& !hasBindsInstanceMethods(componentDescriptor)
&& componentRequirements(componentDescriptor)
.noneMatch(requirement -> requirement.requiresAPassedInstance(elements, types))) {
.noneMatch(
requirement ->
requirement.requiresAPassedInstance(elements, types, metadataUtil))) {
generatedComponent.addMethod(createMethod(componentDescriptor));
}

Expand Down
Expand Up @@ -63,6 +63,7 @@
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.javapoet.AnnotationSpecs;
import dagger.internal.codegen.javapoet.CodeBlocks;
import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
import dagger.internal.codegen.writing.ComponentBindingExpressions;
Expand Down Expand Up @@ -106,6 +107,7 @@ abstract class ComponentImplementationBuilder {
@Inject CompilerOptions compilerOptions;
@Inject ComponentImplementationFactory componentImplementationFactory;
@Inject TopLevelImplementationComponent topLevelImplementationComponent;
@Inject KotlinMetadataUtil metadataUtil;
private boolean done;

/**
Expand Down Expand Up @@ -462,7 +464,7 @@ private Optional<ComponentCreatorDescriptor> creatorDescriptor() {
private boolean canInstantiateAllRequirements() {
return !Iterables.any(
graph.componentRequirements(),
dependency -> dependency.requiresAPassedInstance(elements, types));
dependency -> dependency.requiresAPassedInstance(elements, types, metadataUtil));
}

private ClassName componentCreatorName() {
Expand Down
62 changes: 1 addition & 61 deletions java/dagger/internal/codegen/base/Util.java
Expand Up @@ -16,71 +16,11 @@

package dagger.internal.codegen.base;

import static javax.lang.model.element.ElementKind.CONSTRUCTOR;
import static javax.lang.model.element.Modifier.ABSTRACT;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.STATIC;

import java.util.Map;
import java.util.function.Function;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;

/**
* Utilities for handling types in annotation processors
*/
/** General utilities for the annotation processor. */
public final class Util {
/**
* Returns true if and only if a component can instantiate new instances (typically of a module)
* rather than requiring that they be passed.
*/
public static boolean componentCanMakeNewInstances(TypeElement typeElement) {
switch (typeElement.getKind()) {
case CLASS:
break;
case ENUM:
case ANNOTATION_TYPE:
case INTERFACE:
return false;
default:
throw new AssertionError("TypeElement cannot have kind: " + typeElement.getKind());
}

if (typeElement.getModifiers().contains(ABSTRACT)) {
return false;
}

if (requiresEnclosingInstance(typeElement)) {
return false;
}

for (Element enclosed : typeElement.getEnclosedElements()) {
if (enclosed.getKind().equals(CONSTRUCTOR)
&& ((ExecutableElement) enclosed).getParameters().isEmpty()
&& !enclosed.getModifiers().contains(PRIVATE)) {
return true;
}
}

// TODO(gak): still need checks for visibility

return false;
}

private static boolean requiresEnclosingInstance(TypeElement typeElement) {
switch (typeElement.getNestingKind()) {
case TOP_LEVEL:
return false;
case MEMBER:
return !typeElement.getModifiers().contains(STATIC);
case ANONYMOUS:
case LOCAL:
return true;
}
throw new AssertionError(
"TypeElement cannot have nesting kind: " + typeElement.getNestingKind());
}

/**
* A version of {@link Map#computeIfAbsent(Object, Function)} that allows {@code mappingFunction}
Expand Down
9 changes: 8 additions & 1 deletion java/dagger/internal/codegen/binding/BindingFactory.java
Expand Up @@ -56,6 +56,7 @@
import dagger.internal.codegen.base.SetType;
import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
import dagger.internal.codegen.binding.ProductionBinding.ProductionKind;
import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
import dagger.model.DependencyRequest;
Expand Down Expand Up @@ -83,6 +84,7 @@ public final class BindingFactory {
private final InjectionSiteFactory injectionSiteFactory;
private final DaggerElements elements;
private final InjectionAnnotations injectionAnnotations;
private final KotlinMetadataUtil metadataUtil;

@Inject
BindingFactory(
Expand All @@ -91,13 +93,15 @@ public final class BindingFactory {
KeyFactory keyFactory,
DependencyRequestFactory dependencyRequestFactory,
InjectionSiteFactory injectionSiteFactory,
InjectionAnnotations injectionAnnotations) {
InjectionAnnotations injectionAnnotations,
KotlinMetadataUtil metadataUtil) {
this.types = types;
this.elements = elements;
this.keyFactory = keyFactory;
this.dependencyRequestFactory = dependencyRequestFactory;
this.injectionSiteFactory = injectionSiteFactory;
this.injectionAnnotations = injectionAnnotations;
this.metadataUtil = metadataUtil;
}

/**
Expand Down Expand Up @@ -214,6 +218,7 @@ B setMethodBindingProperties(
.contributionType(ContributionType.fromBindingElement(method))
.bindingElement(method)
.contributingModule(contributedBy)
.isModuleKotlinObject(metadataUtil.isObjectClass(contributedBy))
.key(key)
.dependencies(
dependencyRequestFactory.forRequiredResolvedVariables(
Expand Down Expand Up @@ -419,6 +424,8 @@ private ContributionBinding buildDelegateBinding(
.contributionType(delegateDeclaration.contributionType())
.bindingElement(delegateDeclaration.bindingElement().get())
.contributingModule(delegateDeclaration.contributingModule().get())
.isModuleKotlinObject(
metadataUtil.isObjectClass(delegateDeclaration.contributingModule().get()))
.key(keyFactory.forDelegateBinding(delegateDeclaration, frameworkType))
.dependencies(delegateDeclaration.delegateRequest())
.wrappedMapKeyAnnotation(delegateDeclaration.wrappedMapKey())
Expand Down

0 comments on commit 0da2180

Please sign in to comment.