3232import org .openrewrite .java .tree .Statement ;
3333
3434import java .util .ArrayList ;
35+ import java .util .Collections ;
3536import java .util .HashMap ;
3637import java .util .HashSet ;
3738import java .util .List ;
@@ -71,20 +72,25 @@ public J visitNewClass(J.NewClass newClass, ExecutionContext ctx) {
7172
7273 // Prose-pattern: see if visitBlock (above us on the cursor) decided this
7374 // initializer should be wrapped with `new ArrayList<>(List.of(..))`.
74- Map <UUID , List <Expression >> rewrites = getCursor ().getNearestMessage (PROSE_REWRITES_KEY );
75+ Map <UUID , List <J . MethodInvocation >> rewrites = getCursor ().getNearestMessage (PROSE_REWRITES_KEY );
7576 if (rewrites != null ) {
76- List <Expression > proseArgs = rewrites .get (n .getId ());
77- if (proseArgs != null ) {
77+ List <J .MethodInvocation > adds = rewrites .get (n .getId ());
78+ if (adds != null ) {
79+ List <Expression > args = new ArrayList <>();
7880 StringJoiner joiner = new StringJoiner (", " , "new ArrayList<>(List.of(" , "))" );
79- for (int k = 0 ; k < proseArgs .size (); k ++) {
81+ for (J .MethodInvocation add : adds ) {
82+ args .add (add .getArguments ().get (0 ));
8083 joiner .add ("#{any()}" );
8184 }
8285 maybeAddImport ("java.util.List" );
83- return JavaTemplate .builder (joiner .toString ())
86+ J applied = JavaTemplate .builder (joiner .toString ())
8487 .contextSensitive ()
8588 .imports ("java.util.ArrayList" , "java.util.List" )
8689 .build ()
87- .apply (updateCursor (n ), n .getCoordinates ().replace (), proseArgs .toArray ());
90+ .apply (updateCursor (n ), n .getCoordinates ().replace (), args .toArray ());
91+ // Reattach each add's prefix so the elements land one-per-line and any
92+ // leading comments survive, then autoformat to nest the indentation.
93+ return autoFormat (reattachElementPrefixes (applied , adds ), ctx );
8894 }
8995 }
9096
@@ -120,14 +126,36 @@ public J visitNewClass(J.NewClass newClass, ExecutionContext ctx) {
120126 return n ;
121127 }
122128
129+ /**
130+ * Re-applies the absorbed add statements' prefixes to the generated
131+ * {@code new ArrayList<>(List.of(..))} so each element keeps its own line and any
132+ * leading comments. {@code adds} holds one invocation per element, in order.
133+ */
134+ private J reattachElementPrefixes (J applied , List <J .MethodInvocation > adds ) {
135+ if (!(applied instanceof J .NewClass )) {
136+ return applied ;
137+ }
138+ J .NewClass nc = (J .NewClass ) applied ;
139+ if (nc .getArguments ().size () != 1 || !(nc .getArguments ().get (0 ) instanceof J .MethodInvocation )) {
140+ return applied ;
141+ }
142+ J .MethodInvocation listCall = (J .MethodInvocation ) nc .getArguments ().get (0 );
143+ List <Expression > listArgs = listCall .getArguments ();
144+ List <Expression > withPrefixes = new ArrayList <>(listArgs .size ());
145+ for (int i = 0 ; i < listArgs .size (); i ++) {
146+ withPrefixes .add (listArgs .get (i ).withPrefix (adds .get (i ).getPrefix ()));
147+ }
148+ return nc .withArguments (Collections .singletonList (listCall .withArguments (withPrefixes )));
149+ }
150+
123151 @ Override
124152 public J visitBlock (J .Block block , ExecutionContext ctx ) {
125153 // Pre-pass: scan the ORIGINAL block to identify which initializers to
126154 // rewrite and which `add(..)` statements to absorb. UUIDs are stable
127155 // through super.visitBlock unless a child visitor rebuilds the node,
128156 // and nothing else in this recipe touches the targeted initializers
129157 // before visitNewClass fires.
130- Map <UUID , List <Expression >> rewrites = new HashMap <>();
158+ Map <UUID , List <J . MethodInvocation >> rewrites = new HashMap <>();
131159 Set <UUID > absorbedAddIds = new HashSet <>();
132160 identifyProseRewrites (block , rewrites , absorbedAddIds );
133161
@@ -150,12 +178,12 @@ public J visitBlock(J.Block block, ExecutionContext ctx) {
150178 * ...
151179 * </pre>
152180 * For each such sequence with at least two adds, record
153- * (initializer UUID, [args]) in {@code rewrites} and the absorbed add
154- * statement UUIDs in {@code absorbedAddIds}.
181+ * (initializer UUID, the absorbed {@code add(..)} invocations in order) in
182+ * {@code rewrites} and the absorbed add statement UUIDs in {@code absorbedAddIds}.
155183 */
156184 private void identifyProseRewrites (
157185 J .Block block ,
158- Map <UUID , List <Expression >> rewrites ,
186+ Map <UUID , List <J . MethodInvocation >> rewrites ,
159187 Set <UUID > absorbedAddIds ) {
160188 List <Statement > stmts = block .getStatements ();
161189 int i = 0 ;
@@ -174,7 +202,7 @@ private void identifyProseRewrites(
174202 J .NewClass initializer = (J .NewClass ) decl .getVariables ().get (0 ).getInitializer ();
175203 // (matchingTargetName already verified the initializer is a J.NewClass)
176204
177- List <Expression > args = new ArrayList <>();
205+ List <J . MethodInvocation > adds = new ArrayList <>();
178206 List <UUID > absorbedHere = new ArrayList <>();
179207 int j = i + 1 ;
180208 while (j < stmts .size ()) {
@@ -183,12 +211,12 @@ private void identifyProseRewrites(
183211 if (arg == null || expressionReferences (arg , targetName )) {
184212 break ;
185213 }
186- args .add (arg );
214+ adds .add (( J . MethodInvocation ) next );
187215 absorbedHere .add (next .getId ());
188216 j ++;
189217 }
190- if (args .size () >= 2 && initializer != null ) {
191- rewrites .put (initializer .getId (), args );
218+ if (adds .size () >= 2 && initializer != null ) {
219+ rewrites .put (initializer .getId (), adds );
192220 absorbedAddIds .addAll (absorbedHere );
193221 i = j ;
194222 } else {
0 commit comments