Skip to content

Commit bcbb2e9

Browse files
authored
Move comments along with their dependency when sorting Gradle dependencies (#7517)
The Gradle parser stores line-comments preceding a statement on that statement's prefix. The previous implementation overwrote each sorted statement's prefix with the prefix at its new position, causing comments to remain in place while dependencies moved around them. Now each statement keeps its own prefix, and only the leading whitespace of the new first statement is harmonized to preserve block-opening formatting. Fixes #7516
1 parent aef30f5 commit bcbb2e9

2 files changed

Lines changed: 145 additions & 4 deletions

File tree

rewrite-gradle/src/main/java/org/openrewrite/gradle/SortDependencies.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.openrewrite.java.MethodMatcher;
2828
import org.openrewrite.java.tree.Expression;
2929
import org.openrewrite.java.tree.J;
30+
import org.openrewrite.java.tree.Space;
3031
import org.openrewrite.java.tree.Statement;
3132
import org.openrewrite.maven.tree.Dependency;
3233
import org.openrewrite.maven.tree.DependencyNotation;
@@ -78,7 +79,6 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu
7879
return m;
7980
}
8081

81-
// Separate dependency statements from non-dependency statements (comments are whitespace in Gradle AST)
8282
List<Statement> sorted = new ArrayList<>(statements);
8383
sorted.sort(dependencyComparator);
8484

@@ -95,9 +95,20 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu
9595
return m;
9696
}
9797

98-
// Preserve original whitespace prefixes
99-
for (int i = 0; i < sorted.size(); i++) {
100-
sorted.set(i, sorted.get(i).withPrefix(statements.get(i).getPrefix()));
98+
// Keep each statement's prefix with the statement itself so that any preceding comments
99+
// (which the parser stores on the next statement's prefix) move along with the dependency.
100+
// Swap only the leading whitespace of the new first statement with the original first
101+
// statement's leading whitespace, to keep the block opening formatting consistent.
102+
Space originalFirstPrefix = statements.get(0).getPrefix();
103+
Space newFirstPrefix = sorted.get(0).getPrefix();
104+
sorted.set(0, sorted.get(0).withPrefix(newFirstPrefix.withWhitespace(originalFirstPrefix.getWhitespace())));
105+
// Apply the displaced leading whitespace to whichever sorted statement now follows the
106+
// original first statement, to preserve the block-internal blank-line layout.
107+
int originalFirstIndex = sorted.indexOf(statements.get(0));
108+
if (originalFirstIndex > 0) {
109+
Space displacedPrefix = sorted.get(originalFirstIndex).getPrefix();
110+
sorted.set(originalFirstIndex, sorted.get(originalFirstIndex)
111+
.withPrefix(displacedPrefix.withWhitespace(newFirstPrefix.getWhitespace())));
101112
}
102113

103114
body = body.withStatements(sorted);

rewrite-gradle/src/test/java/org/openrewrite/gradle/SortDependenciesTest.java

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,4 +220,134 @@ void configurationGroupingTakesPrecedence() {
220220
)
221221
);
222222
}
223+
224+
@Test
225+
void preservesCommentsAttachedToDependencies() {
226+
rewriteRun(
227+
buildGradle(
228+
"""
229+
plugins {
230+
id 'java-library'
231+
}
232+
233+
repositories {
234+
mavenCentral()
235+
}
236+
237+
dependencies {
238+
// Spring web for the controllers
239+
implementation "org.springframework:spring-web:5.3.23"
240+
// Guava for collection helpers
241+
api "com.google.guava:guava:31.1-jre"
242+
}
243+
""",
244+
"""
245+
plugins {
246+
id 'java-library'
247+
}
248+
249+
repositories {
250+
mavenCentral()
251+
}
252+
253+
dependencies {
254+
// Guava for collection helpers
255+
api "com.google.guava:guava:31.1-jre"
256+
// Spring web for the controllers
257+
implementation "org.springframework:spring-web:5.3.23"
258+
}
259+
"""
260+
)
261+
);
262+
}
263+
264+
@Test
265+
void preservesCommentsAttachedToDependenciesKotlinDsl() {
266+
rewriteRun(
267+
buildGradleKts(
268+
"""
269+
plugins {
270+
`java-library`
271+
}
272+
273+
repositories {
274+
mavenCentral()
275+
}
276+
277+
dependencies {
278+
// Spring web for the controllers
279+
implementation("org.springframework:spring-web:5.3.23")
280+
281+
// Guava for collection helpers
282+
api("com.google.guava:guava:31.1-jre")
283+
}
284+
""",
285+
"""
286+
plugins {
287+
`java-library`
288+
}
289+
290+
repositories {
291+
mavenCentral()
292+
}
293+
294+
dependencies {
295+
// Guava for collection helpers
296+
api("com.google.guava:guava:31.1-jre")
297+
298+
// Spring web for the controllers
299+
implementation("org.springframework:spring-web:5.3.23")
300+
}
301+
"""
302+
)
303+
);
304+
}
305+
306+
@Test
307+
void preservesCommentsBlocksWithBlankLines() {
308+
rewriteRun(
309+
buildGradle(
310+
"""
311+
plugins {
312+
id 'java-library'
313+
}
314+
315+
repositories {
316+
mavenCentral()
317+
}
318+
319+
dependencies {
320+
// Enable the Swing console
321+
implementation "org.springframework:spring-web:5.3.23"
322+
323+
// Enable Guava
324+
api "com.google.guava:guava:31.1-jre"
325+
326+
// Enable JUnit
327+
testImplementation "org.junit.jupiter:junit-jupiter-api:5.9.1"
328+
}
329+
""",
330+
"""
331+
plugins {
332+
id 'java-library'
333+
}
334+
335+
repositories {
336+
mavenCentral()
337+
}
338+
339+
dependencies {
340+
// Enable Guava
341+
api "com.google.guava:guava:31.1-jre"
342+
343+
// Enable the Swing console
344+
implementation "org.springframework:spring-web:5.3.23"
345+
346+
// Enable JUnit
347+
testImplementation "org.junit.jupiter:junit-jupiter-api:5.9.1"
348+
}
349+
"""
350+
)
351+
);
352+
}
223353
}

0 commit comments

Comments
 (0)