| 
24 | 24 | import static dagger.internal.codegen.binding.SourceFiles.bindingTypeElementTypeVariableNames;  | 
25 | 25 | import static dagger.internal.codegen.binding.SourceFiles.generateBindingFieldsForDependencies;  | 
26 | 26 | import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;  | 
 | 27 | +import static dagger.internal.codegen.binding.SourceFiles.generatedProxyMethodName;  | 
27 | 28 | import static dagger.internal.codegen.binding.SourceFiles.parameterizedGeneratedTypeNameForBinding;  | 
28 | 29 | import static dagger.internal.codegen.extension.DaggerStreams.presentValues;  | 
29 | 30 | import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;  | 
 | 
36 | 37 | import static dagger.internal.codegen.model.BindingKind.INJECTION;  | 
37 | 38 | import static dagger.internal.codegen.model.BindingKind.PROVISION;  | 
38 | 39 | import static dagger.internal.codegen.writing.GwtCompatibility.gwtIncompatibleAnnotation;  | 
 | 40 | +import static dagger.internal.codegen.writing.InjectionMethods.copyParameter;  | 
 | 41 | +import static dagger.internal.codegen.writing.InjectionMethods.copyParameters;  | 
 | 42 | +import static dagger.internal.codegen.xprocessing.XElements.asConstructor;  | 
 | 43 | +import static dagger.internal.codegen.xprocessing.XElements.asMethod;  | 
 | 44 | +import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;  | 
 | 45 | +import static dagger.internal.codegen.xprocessing.XTypeElements.typeVariableNames;  | 
39 | 46 | import static javax.lang.model.element.Modifier.FINAL;  | 
40 | 47 | import static javax.lang.model.element.Modifier.PRIVATE;  | 
41 | 48 | import static javax.lang.model.element.Modifier.PUBLIC;  | 
42 | 49 | import static javax.lang.model.element.Modifier.STATIC;  | 
43 | 50 | 
 
  | 
 | 51 | +import androidx.room.compiler.processing.XConstructorElement;  | 
44 | 52 | import androidx.room.compiler.processing.XElement;  | 
 | 53 | +import androidx.room.compiler.processing.XExecutableElement;  | 
45 | 54 | import androidx.room.compiler.processing.XExecutableParameterElement;  | 
46 | 55 | import androidx.room.compiler.processing.XFiler;  | 
 | 56 | +import androidx.room.compiler.processing.XMethodElement;  | 
47 | 57 | import androidx.room.compiler.processing.XProcessingEnv;  | 
 | 58 | +import androidx.room.compiler.processing.XType;  | 
 | 59 | +import androidx.room.compiler.processing.XTypeElement;  | 
48 | 60 | import com.google.common.collect.ImmutableList;  | 
49 | 61 | import com.google.common.collect.ImmutableMap;  | 
50 | 62 | import com.google.common.collect.ImmutableSet;  | 
 | 
56 | 68 | import com.squareup.javapoet.ParameterSpec;  | 
57 | 69 | import com.squareup.javapoet.TypeName;  | 
58 | 70 | import com.squareup.javapoet.TypeSpec;  | 
 | 71 | +import dagger.internal.Preconditions;  | 
59 | 72 | import dagger.internal.codegen.base.SourceFileGenerator;  | 
60 | 73 | import dagger.internal.codegen.base.UniqueNameSet;  | 
61 | 74 | import dagger.internal.codegen.binding.AssistedInjectionBinding;  | 
 | 
73 | 86 | import dagger.internal.codegen.model.Scope;  | 
74 | 87 | import dagger.internal.codegen.writing.InjectionMethods.InjectionSiteMethod;  | 
75 | 88 | import dagger.internal.codegen.writing.InjectionMethods.ProvisionMethod;  | 
 | 89 | +import dagger.internal.codegen.xprocessing.Nullability;  | 
76 | 90 | import java.util.Optional;  | 
77 | 91 | import java.util.stream.Stream;  | 
78 | 92 | import javax.inject.Inject;  | 
@@ -136,7 +150,7 @@ private TypeSpec.Builder factoryBuilder(ContributionBinding binding) {  | 
136 | 150 |     return factoryBuilder  | 
137 | 151 |         .addMethod(getMethod(binding, factoryFields))  | 
138 | 152 |         .addMethod(staticCreateMethod(binding, factoryFields))  | 
139 |  | -        .addMethod(staticProvisionMethod(binding));  | 
 | 153 | +        .addMethod(staticProxyMethod(binding));  | 
140 | 154 |   }  | 
141 | 155 | 
 
  | 
142 | 156 |   // private static final class InstanceHolder {  | 
@@ -298,17 +312,101 @@ private MethodSpec getMethod(ContributionBinding binding, FactoryFields factoryF  | 
298 | 312 |     return getMethod.build();  | 
299 | 313 |   }  | 
300 | 314 | 
 
  | 
301 |  | -  // Example 1: Provision binding  | 
302 |  | -  // public static Foo provideFoo(FooModule module, Bar bar, Baz baz) {  | 
303 |  | -  //   return Preconditions.checkNotNullFromProvides(module.provideFoo(bar, baz));  | 
304 |  | -  // }  | 
 | 315 | +  private MethodSpec staticProxyMethod(ContributionBinding binding) {  | 
 | 316 | +    switch (binding.kind()) {  | 
 | 317 | +      case INJECTION:  | 
 | 318 | +      case ASSISTED_INJECTION:  | 
 | 319 | +        return staticProxyMethodForInjection(binding);  | 
 | 320 | +      case PROVISION:  | 
 | 321 | +        return staticProxyMethodForProvision((ProvisionBinding) binding);  | 
 | 322 | +      default:  | 
 | 323 | +        throw new AssertionError("Unexpected binding kind: " + binding);  | 
 | 324 | +    }  | 
 | 325 | +  }  | 
 | 326 | + | 
 | 327 | +  // Example:  | 
305 | 328 |   //  | 
306 |  | -  // Example 2: Injection binding  | 
307 | 329 |   // public static Foo newInstance(Bar bar, Baz baz) {  | 
308 | 330 |   //   return new Foo(bar, baz);  | 
309 | 331 |   // }  | 
310 |  | -  private MethodSpec staticProvisionMethod(ContributionBinding binding) {  | 
311 |  | -    return ProvisionMethod.create(binding, compilerOptions);  | 
 | 332 | +  private static MethodSpec staticProxyMethodForInjection(ContributionBinding binding) {  | 
 | 333 | +    XConstructorElement constructor = asConstructor(binding.bindingElement().get());  | 
 | 334 | +    XTypeElement enclosingType = constructor.getEnclosingElement();  | 
 | 335 | +    MethodSpec.Builder builder =  | 
 | 336 | +        methodBuilder(generatedProxyMethodName(binding))  | 
 | 337 | +            .addModifiers(PUBLIC, STATIC)  | 
 | 338 | +            .varargs(constructor.isVarArgs())  | 
 | 339 | +            .returns(enclosingType.getType().getTypeName())  | 
 | 340 | +            .addTypeVariables(typeVariableNames(enclosingType))  | 
 | 341 | +            .addExceptions(getThrownTypes(constructor));  | 
 | 342 | +    CodeBlock arguments = copyParameters(builder, new UniqueNameSet(), constructor.getParameters());  | 
 | 343 | +    return builder  | 
 | 344 | +        .addStatement("return new $T($L)", enclosingType.getType().getTypeName(), arguments)  | 
 | 345 | +        .build();  | 
 | 346 | +  }  | 
 | 347 | + | 
 | 348 | +  // Example:  | 
 | 349 | +  //  | 
 | 350 | +  // public static Foo provideFoo(FooModule module, Bar bar, Baz baz) {  | 
 | 351 | +  //   return Preconditions.checkNotNullFromProvides(module.provideFoo(bar, baz));  | 
 | 352 | +  // }  | 
 | 353 | +  private MethodSpec staticProxyMethodForProvision(ProvisionBinding binding) {  | 
 | 354 | +    XMethodElement method = asMethod(binding.bindingElement().get());  | 
 | 355 | +    MethodSpec.Builder builder =  | 
 | 356 | +        methodBuilder(generatedProxyMethodName(binding))  | 
 | 357 | +            .addModifiers(PUBLIC, STATIC)  | 
 | 358 | +            .varargs(method.isVarArgs())  | 
 | 359 | +            .addExceptions(getThrownTypes(method));  | 
 | 360 | + | 
 | 361 | +    XTypeElement enclosingType = asTypeElement(method.getEnclosingElement());  | 
 | 362 | +    UniqueNameSet parameterNameSet = new UniqueNameSet();  | 
 | 363 | +    CodeBlock module;  | 
 | 364 | +    if (method.isStatic() || enclosingType.isCompanionObject()) {  | 
 | 365 | +      module = CodeBlock.of("$T", enclosingType.getClassName());  | 
 | 366 | +    } else if (enclosingType.isKotlinObject()) {  | 
 | 367 | +      // Call through the singleton instance.  | 
 | 368 | +      // See: https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#static-methods  | 
 | 369 | +      module = CodeBlock.of("$T.INSTANCE", enclosingType.getClassName());  | 
 | 370 | +    } else {  | 
 | 371 | +      builder.addTypeVariables(typeVariableNames(enclosingType));  | 
 | 372 | +      module = copyInstance(builder, parameterNameSet, enclosingType.getType());  | 
 | 373 | +    }  | 
 | 374 | +    CodeBlock arguments = copyParameters(builder, parameterNameSet, method.getParameters());  | 
 | 375 | +    CodeBlock invocation = CodeBlock.of("$L.$L($L)", module, method.getJvmName(), arguments);  | 
 | 376 | + | 
 | 377 | +    Nullability nullability = Nullability.of(method);  | 
 | 378 | +    nullability  | 
 | 379 | +        .nonTypeUseNullableAnnotations()  | 
 | 380 | +        .forEach(builder::addAnnotation);  | 
 | 381 | +    return builder  | 
 | 382 | +        .returns(  | 
 | 383 | +            method.getReturnType().getTypeName()  | 
 | 384 | +                .annotated(  | 
 | 385 | +                    nullability.typeUseNullableAnnotations().stream()  | 
 | 386 | +                        .map(annotation -> AnnotationSpec.builder(annotation).build())  | 
 | 387 | +                        .collect(toImmutableList())))  | 
 | 388 | +        .addStatement("return $L", maybeWrapInCheckForNull(binding, invocation))  | 
 | 389 | +        .build();  | 
 | 390 | +  }  | 
 | 391 | + | 
 | 392 | +  private CodeBlock maybeWrapInCheckForNull(ProvisionBinding binding, CodeBlock codeBlock) {  | 
 | 393 | +    return binding.shouldCheckForNull(compilerOptions)  | 
 | 394 | +        ? CodeBlock.of("$T.checkNotNullFromProvides($L)", Preconditions.class, codeBlock)  | 
 | 395 | +        : codeBlock;  | 
 | 396 | +  }  | 
 | 397 | + | 
 | 398 | +  private static CodeBlock copyInstance(  | 
 | 399 | +      MethodSpec.Builder methodBuilder, UniqueNameSet parameterNameSet, XType type) {  | 
 | 400 | +    return copyParameter(  | 
 | 401 | +        methodBuilder,  | 
 | 402 | +        type,  | 
 | 403 | +        parameterNameSet.getUniqueName("instance"),  | 
 | 404 | +        /* useObject= */ false,  | 
 | 405 | +        Nullability.NOT_NULLABLE);  | 
 | 406 | +  }  | 
 | 407 | + | 
 | 408 | +  private static ImmutableList<TypeName> getThrownTypes(XExecutableElement executable) {  | 
 | 409 | +    return executable.getThrownTypes().stream().map(XType::getTypeName).collect(toImmutableList());  | 
312 | 410 |   }  | 
313 | 411 | 
 
  | 
314 | 412 |   private AnnotationSpec scopeMetadataAnnotation(ContributionBinding binding) {  | 
 | 
0 commit comments