1616
1717package dagger .internal .codegen .writing ;
1818
19+ import static androidx .room .compiler .codegen .compat .XConverters .toJavaPoet ;
20+ import static androidx .room .compiler .codegen .compat .XConverters .toKotlinPoet ;
1921import static androidx .room .compiler .codegen .compat .XConverters .toXPoet ;
2022import static androidx .room .compiler .processing .XElementKt .isMethodParameter ;
2123import static dagger .internal .codegen .binding .AssistedInjectionAnnotations .isAssistedParameter ;
2729import static dagger .internal .codegen .extension .DaggerStreams .toImmutableMap ;
2830import static dagger .internal .codegen .xprocessing .Accessibility .isRawTypeAccessible ;
2931import static dagger .internal .codegen .xprocessing .Accessibility .isRawTypePubliclyAccessible ;
32+ import static dagger .internal .codegen .xprocessing .Accessibility .isTypePubliclyAccessible ;
3033import static dagger .internal .codegen .xprocessing .XCodeBlocks .makeParametersCodeBlock ;
3134import static dagger .internal .codegen .xprocessing .XCodeBlocks .toConcatenatedCodeBlock ;
3235import static dagger .internal .codegen .xprocessing .XCodeBlocks .toParametersCodeBlock ;
3336import static dagger .internal .codegen .xprocessing .XElements .asExecutable ;
3437import static dagger .internal .codegen .xprocessing .XElements .asMethodParameter ;
3538import static dagger .internal .codegen .xprocessing .XElements .getSimpleName ;
3639import static dagger .internal .codegen .xprocessing .XTypeNames .asClassName ;
40+ import static dagger .internal .codegen .xprocessing .XTypeNames .replaceTypeVariablesWithBounds ;
41+ import static dagger .internal .codegen .xprocessing .XTypes .asMemberOf ;
3742import static dagger .internal .codegen .xprocessing .XTypes .erasedTypeName ;
3843
3944import androidx .room .compiler .codegen .XClassName ;
4247import androidx .room .compiler .processing .XExecutableElement ;
4348import androidx .room .compiler .processing .XExecutableParameterElement ;
4449import androidx .room .compiler .processing .XType ;
50+ import androidx .room .compiler .processing .XTypeElement ;
4551import androidx .room .compiler .processing .XVariableElement ;
4652import com .google .common .collect .ImmutableList ;
4753import com .google .common .collect .ImmutableMap ;
4854import com .google .common .collect .ImmutableSet ;
55+ import com .google .common .collect .ImmutableSortedSet ;
4956import dagger .internal .codegen .base .UniqueNameSet ;
5057import dagger .internal .codegen .binding .AssistedInjectionBinding ;
58+ import dagger .internal .codegen .binding .Binding ;
5159import dagger .internal .codegen .binding .ContributionBinding ;
5260import dagger .internal .codegen .binding .InjectionBinding ;
61+ import dagger .internal .codegen .binding .MembersInjectionBinding ;
5362import dagger .internal .codegen .binding .MembersInjectionBinding .InjectionSite ;
5463import dagger .internal .codegen .binding .ProvisionBinding ;
5564import dagger .internal .codegen .compileroption .CompilerOptions ;
@@ -110,7 +119,12 @@ static XCodeBlock invoke(
110119
111120 XClassName enclosingClass = generatedClassNameForBinding (binding );
112121 String methodName = generatedProxyMethodName (binding );
113- return invokeMethod (methodName , arguments .build (), enclosingClass , requestingClass );
122+ return invokeMethod (
123+ methodName ,
124+ methodTypeArguments (binding , compilerOptions ),
125+ arguments .build (),
126+ enclosingClass ,
127+ requestingClass );
114128 }
115129
116130 static ImmutableList <XCodeBlock > invokeArguments (
@@ -180,12 +194,13 @@ static final class InjectionSiteMethod {
180194 * @param instanceType the type of the {@code instance} parameter
181195 */
182196 static XCodeBlock invokeAll (
183- ImmutableSet < InjectionSite > injectionSites ,
197+ Binding binding ,
184198 XClassName generatedTypeName ,
185199 XCodeBlock instanceCodeBlock ,
186200 XType instanceType ,
187- Function <DependencyRequest , XCodeBlock > dependencyUsage ) {
188- return injectionSites .stream ()
201+ Function <DependencyRequest , XCodeBlock > dependencyUsage ,
202+ CompilerOptions compilerOptions ) {
203+ return injectionSites (binding ).stream ()
189204 .map (
190205 injectionSite -> {
191206 XType injectSiteType = injectionSite .enclosingTypeElement ().getType ();
@@ -204,7 +219,13 @@ && isRawTypeAccessible(
204219 : instanceCodeBlock ;
205220 return XCodeBlock .of (
206221 "%L;" ,
207- invoke (injectionSite , generatedTypeName , maybeCastedInstance , dependencyUsage ));
222+ invoke (
223+ binding ,
224+ injectionSite ,
225+ generatedTypeName ,
226+ maybeCastedInstance ,
227+ dependencyUsage ,
228+ compilerOptions ));
208229 })
209230 .collect (toConcatenatedCodeBlock ());
210231 }
@@ -214,10 +235,12 @@ && isRawTypeAccessible(
214235 * using the {@code dependencyUsage} function.
215236 */
216237 private static XCodeBlock invoke (
238+ Binding binding ,
217239 InjectionSite injectionSite ,
218240 XClassName generatedTypeName ,
219241 XCodeBlock instanceCodeBlock ,
220- Function <DependencyRequest , XCodeBlock > dependencyUsage ) {
242+ Function <DependencyRequest , XCodeBlock > dependencyUsage ,
243+ CompilerOptions compilerOptions ) {
221244 ImmutableList <XCodeBlock > arguments =
222245 ImmutableList .<XCodeBlock >builder ()
223246 .add (instanceCodeBlock )
@@ -226,21 +249,106 @@ private static XCodeBlock invoke(
226249 .map (dependencyUsage )
227250 .collect (toImmutableList ()))
228251 .build ();
229- XClassName enclosingClass = membersInjectorNameForType (injectionSite .enclosingTypeElement ());
252+ XTypeElement enclosingTypeElement = injectionSite .enclosingTypeElement ();
253+ XClassName enclosingClass = membersInjectorNameForType (enclosingTypeElement );
230254 String methodName = membersInjectorMethodName (injectionSite );
231- return invokeMethod (methodName , arguments , enclosingClass , generatedTypeName );
255+ return invokeMethod (
256+ methodName ,
257+ methodTypeArguments (binding , injectionSite , compilerOptions ),
258+ arguments ,
259+ enclosingClass ,
260+ generatedTypeName );
261+ }
262+
263+ private static ImmutableSortedSet <InjectionSite > injectionSites (Binding binding ) {
264+ switch (binding .kind ()) {
265+ case INJECTION :
266+ return ((InjectionBinding ) binding ).injectionSites ();
267+ case ASSISTED_INJECTION :
268+ return ((AssistedInjectionBinding ) binding ).injectionSites ();
269+ case MEMBERS_INJECTION :
270+ return ((MembersInjectionBinding ) binding ).injectionSites ();
271+ default :
272+ throw new AssertionError ("Unexpected binding kind: " + binding .kind ());
273+ }
274+ }
275+ }
276+
277+ private static ImmutableList <XTypeName > methodTypeArguments (
278+ Binding binding , CompilerOptions compilerOptions ) {
279+ return methodTypeArguments (binding , Optional .empty (), compilerOptions );
280+ }
281+
282+ private static ImmutableList <XTypeName > methodTypeArguments (
283+ Binding binding , InjectionSite injectionSite , CompilerOptions compilerOptions ) {
284+ return methodTypeArguments (binding , Optional .of (injectionSite ), compilerOptions );
285+ }
286+
287+ private static ImmutableList <XTypeName > methodTypeArguments (
288+ Binding binding , Optional <InjectionSite > injectionSite , CompilerOptions compilerOptions ) {
289+ if (!requiresMethodTypeArguments (binding , compilerOptions )) {
290+ return ImmutableList .of ();
291+ }
292+ XTypeElement enclosingTypeElement =
293+ injectionSite .map (InjectionSite ::enclosingTypeElement )
294+ .orElse (binding .bindingTypeElement ().get ());
295+ if (enclosingTypeElement .getTypeParameters ().isEmpty ()) {
296+ return ImmutableList .of ();
232297 }
298+ XType unresolvedType = enclosingTypeElement .getType ();
299+ XType resolvedType =
300+ asMemberOf (
301+ enclosingTypeElement ,
302+ binding .contributingModule ().isPresent ()
303+ ? binding .contributingModule ().get ().getType ()
304+ : binding .key ().type ().xprocessing ());
305+ ImmutableList .Builder <XTypeName > builder = ImmutableList .builder ();
306+ for (int i = 0 ; i < resolvedType .getTypeArguments ().size (); i ++) {
307+ XType typeArgument = resolvedType .getTypeArguments ().get (i );
308+ // If the type argument is publicly accessible, we can use it directly. Otherwise, we try to
309+ // use the bounds of the type variables. If neither of these are possible, we should have
310+ // failed earlier during the binding graph validation stage.
311+ if (isTypePubliclyAccessible (typeArgument )) {
312+ builder .add (typeArgument .asTypeName ());
313+ } else {
314+ XType unresolvedTypeArgument = unresolvedType .getTypeArguments ().get (i );
315+ builder .add (replaceTypeVariablesWithBounds (unresolvedTypeArgument .asTypeName ()));
316+ }
317+ }
318+ return builder .build ();
319+ }
320+
321+ private static boolean requiresMethodTypeArguments (
322+ Binding binding , CompilerOptions compilerOptions ) {
323+ return false ;
233324 }
234325
235326 private static XCodeBlock invokeMethod (
236327 String methodName ,
328+ ImmutableList <XTypeName > typeArguments ,
237329 ImmutableList <XCodeBlock > parameters ,
238330 XClassName enclosingClass ,
239331 XClassName requestingClass ) {
240- XCodeBlock parameterBlock = makeParametersCodeBlock (parameters );
241- return enclosingClass .equals (requestingClass )
242- ? XCodeBlock .of ("%L(%L)" , methodName , parameterBlock )
243- : XCodeBlock .of ("%T.%L(%L)" , enclosingClass , methodName , parameterBlock );
332+ XCodeBlock .Builder builder = XCodeBlock .builder ();
333+ if (!enclosingClass .equals (requestingClass )) {
334+ builder .add ("%T." , enclosingClass );
335+ } else if (!typeArguments .isEmpty ()) {
336+ // In Java, if the method requires type arguments we also need to add the enclosing class. For
337+ // example, "<Bar>create(bar)" is invalid but "Foo_Factory.<Bar>create(bar)" is valid.
338+ toJavaPoet (builder ).add ("$T." , toJavaPoet (enclosingClass ));
339+ }
340+ if (typeArguments .isEmpty ()) {
341+ builder .add ("%N" , methodName );
342+ } else {
343+ XCodeBlock typeParametersCodeBlock =
344+ typeArguments .stream ()
345+ .map (typeParameter -> XCodeBlock .of ("%T" , typeParameter ))
346+ .collect (toParametersCodeBlock ());
347+ toJavaPoet (builder ).add ("<$L>$N" , toJavaPoet (typeParametersCodeBlock ), methodName );
348+ toKotlinPoet (builder ).add ("%N<%L>" , methodName , toKotlinPoet (typeParametersCodeBlock ));
349+ }
350+ builder .add ("(%L)" , makeParametersCodeBlock (parameters ));
351+ return builder .build ();
244352 }
245353
246354 static XCodeBlock copyParameters (
@@ -287,7 +395,7 @@ static XCodeBlock copyParameter(
287395 name ,
288396 typeName ,
289397 isTypeNameAccessible ,
290- XTypeName .ANY_OBJECT ,
398+ XTypeName .ANY_OBJECT . copy ( /* nullable= */ true ) ,
291399 nullability ,
292400 compilerOptions );
293401 }
0 commit comments