1515 */
1616package org .openrewrite .java .migrate .lang .var ;
1717
18+ import org .jspecify .annotations .Nullable ;
1819import org .openrewrite .ExecutionContext ;
1920import org .openrewrite .Preconditions ;
2021import org .openrewrite .Recipe ;
2122import org .openrewrite .TreeVisitor ;
23+ import org .openrewrite .internal .ListUtils ;
2224import org .openrewrite .java .JavaIsoVisitor ;
2325import org .openrewrite .java .search .UsesJavaVersion ;
2426import org .openrewrite .java .tree .Expression ;
2527import org .openrewrite .java .tree .J ;
2628import org .openrewrite .java .tree .JavaType ;
29+ import org .openrewrite .java .tree .TypeTree ;
30+
31+ import java .util .List ;
32+
33+ import static java .util .Objects .requireNonNull ;
2734
2835public class UseVarForGenericMethodInvocations extends Recipe {
2936 @ Override
@@ -36,7 +43,7 @@ public String getDisplayName() {
3643 public String getDescription () {
3744 //language=markdown
3845 return "Apply `var` to variables initialized by invocations of generic methods. " +
39- "This recipe ignores generic factory methods without parameters, because open rewrite cannot handle them correctly ATM." ;
46+ "This recipe ignores generic factory methods without parameters, because open rewrite cannot handle them correctly ATM." ;
4047 }
4148
4249 @ Override
@@ -82,16 +89,53 @@ public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations v
8289 maybeRemoveImport ((JavaType .FullyQualified ) vd .getType ());
8390 }
8491
85- return DeclarationCheck .transformToVar (vd );
86- // TODO implement to support cases like `var strs = List.<String>of();`
87- /*J.VariableDeclarations finalVd = vd;
88- return DeclarationCheck.<J.MethodInvocation>transformToVar(vd, it -> {
89- // If left has generics but right has not, copy types parameters
90- if (finalVd.getTypeExpression() instanceof J.ParameterizedType && !((J.ParameterizedType) finalVd.getTypeExpression()).getTypeParameters().isEmpty() && it.getTypeParameters() == null) {
91- return it.withTypeParameters(((J.ParameterizedType) finalVd.getTypeExpression()).getPadding().getTypeParameters());
92+ // Make nested generic types explicit before converting to var
93+ J .VariableDeclarations finalVd = vd ;
94+ return DeclarationCheck .transformToVar (vd , (J .MethodInvocation mi ) -> makeNestedGenericsExplicit (mi , finalVd ));
95+ }
96+
97+ /**
98+ * Makes nested generic types explicit by replacing diamond operators in constructor calls
99+ * with explicit type parameters based on the variable declaration type.
100+ */
101+ private J .MethodInvocation makeNestedGenericsExplicit (J .MethodInvocation mi , J .VariableDeclarations vd ) {
102+ // Extract type parameters from the variable declaration
103+ if (!(vd .getTypeExpression () instanceof J .ParameterizedType )) {
104+ return mi ;
105+ }
106+
107+ List <Expression > leftTypeParams = ((J .ParameterizedType ) vd .getTypeExpression ()).getTypeParameters ();
108+ if (leftTypeParams == null || leftTypeParams .isEmpty ()) {
109+ return mi ;
110+ }
111+
112+ // Visit arguments and replace diamond operators with explicit type parameters
113+ return mi .withArguments (ListUtils .map (mi .getArguments (), arg -> {
114+ if (arg instanceof J .NewClass ) {
115+ J .NewClass newClass = (J .NewClass ) arg ;
116+ // Check if using diamond operator (rightTypeParams is empty)
117+ if (!hasTypeParams (newClass .getClazz ())) {
118+ // Copy type parameters from left side to right side
119+ J .ParameterizedType rightType = (J .ParameterizedType ) newClass .getClazz ();
120+ return newClass .withClazz (requireNonNull (rightType ).withTypeParameters (leftTypeParams ));
121+ }
122+ }
123+ return arg ;
124+ }));
125+ }
126+
127+ private static boolean hasTypeParams (@ Nullable TypeTree clazz ) {
128+ if (clazz instanceof J .ParameterizedType ) {
129+ List <Expression > typeParameters = ((J .ParameterizedType ) clazz ).getTypeParameters ();
130+ if (typeParameters != null ) {
131+ for (Expression curType : typeParameters ) {
132+ if (curType .getType () != null ) {
133+ return true ;
134+ }
135+ }
92136 }
93- return it;
94- });*/
137+ }
138+ return false ;
95139 }
96140
97141 private static boolean allArgumentsEmpty (J .MethodInvocation invocation ) {
0 commit comments