Skip to content

Commit 1806c44

Browse files
committed
respect order when includes are set
1 parent 882f436 commit 1806c44

File tree

4 files changed

+138
-8
lines changed

4 files changed

+138
-8
lines changed

framework/codemodder-base/src/main/java/io/codemodder/CodemodLoader.java

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,26 @@ public CodemodLoader(
4343
// sort the codemods according to their priority
4444
List<Class<? extends CodeChanger>> orderedCodemodTypes = new ArrayList<>(unorderedCodemodTypes);
4545

46-
// sort according to the codemod execution priority of each codemod type
47-
orderedCodemodTypes.sort(
48-
(c1, c2) -> {
49-
CodemodExecutionPriority p1 = c1.getAnnotation(Codemod.class).executionPriority();
50-
CodemodExecutionPriority p2 = c2.getAnnotation(Codemod.class).executionPriority();
51-
return CodemodExecutionPriority.priorityOrderComparator.compare(p1, p2);
52-
});
46+
// if there's an order from --codemod-includes, honor that
47+
Optional<List<String>> desiredOrder = codemodRegulator.desiredCodemodIdOrder();
48+
if (desiredOrder.isPresent()) {
49+
orderedCodemodTypes.sort(
50+
(c1, c2) -> {
51+
String id1 = c1.getAnnotation(Codemod.class).id();
52+
String id2 = c2.getAnnotation(Codemod.class).id();
53+
int index1 = desiredOrder.get().indexOf(id1);
54+
int index2 = desiredOrder.get().indexOf(id2);
55+
return Integer.compare(index1, index2);
56+
});
57+
} else {
58+
// sort according to the codemod execution priority of each codemod type
59+
orderedCodemodTypes.sort(
60+
(c1, c2) -> {
61+
CodemodExecutionPriority p1 = c1.getAnnotation(Codemod.class).executionPriority();
62+
CodemodExecutionPriority p2 = c2.getAnnotation(Codemod.class).executionPriority();
63+
return CodemodExecutionPriority.priorityOrderComparator.compare(p1, p2);
64+
});
65+
}
5366

5467
// get all the injectable parameters
5568
Set<String> packagesScanned = new HashSet<>();
@@ -127,7 +140,6 @@ public CodemodLoader(
127140
codemods.add(new CodemodIdPair(codemodId, codeChanger));
128141
}
129142
}
130-
131143
this.codemods = Collections.unmodifiableList(codemods);
132144
}
133145

framework/codemodder-base/src/main/java/io/codemodder/CodemodRegulator.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.List;
44
import java.util.Objects;
5+
import java.util.Optional;
56

67
/** A type that is relied on to inform our in-flight analysis on whether codemods are allowed. */
78
public interface CodemodRegulator {
@@ -14,15 +15,23 @@ public interface CodemodRegulator {
1415
*/
1516
boolean isAllowed(String codemodId);
1617

18+
Optional<List<String>> desiredCodemodIdOrder();
19+
1720
class DefaultCodemodRegulator implements CodemodRegulator {
1821

1922
private final DefaultRuleSetting setting;
2023
private final List<String> exceptions;
24+
private final List<String> desiredOrder;
2125

2226
DefaultCodemodRegulator(
2327
final DefaultRuleSetting defaultCodemodSetting, final List<String> codemodExceptions) {
2428
this.setting = Objects.requireNonNull(defaultCodemodSetting);
2529
this.exceptions = Objects.requireNonNull(codemodExceptions);
30+
if (DefaultRuleSetting.ENABLED.equals(defaultCodemodSetting)) {
31+
this.desiredOrder = null;
32+
} else {
33+
this.desiredOrder = codemodExceptions;
34+
}
2635
}
2736

2837
@Override
@@ -32,6 +41,11 @@ public boolean isAllowed(final String codemodId) {
3241
}
3342
return exceptions.contains(codemodId);
3443
}
44+
45+
@Override
46+
public Optional<List<String>> desiredCodemodIdOrder() {
47+
return Optional.ofNullable(desiredOrder);
48+
}
3549
}
3650

3751
static CodemodRegulator of(

framework/codemodder-base/src/test/java/io/codemodder/CodemodLoaderTest.java

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import static io.codemodder.CodemodLoader.isValidCodemodId;
44
import static org.hamcrest.CoreMatchers.equalTo;
55
import static org.hamcrest.MatcherAssert.assertThat;
6+
import static org.hamcrest.Matchers.hasSize;
67
import static org.junit.jupiter.api.Assertions.assertThrows;
78

89
import com.github.javaparser.JavaParser;
@@ -216,6 +217,81 @@ public boolean supports(Path file) {
216217
}
217218
}
218219

220+
/** Confirm the codemods respect the order of the regulator. */
221+
@Test
222+
void it_handles_codemod_orders(final @TempDir Path tmpDir) throws IOException {
223+
224+
// create an ordered list of codemods
225+
List<Class<? extends CodeChanger>> codemodTypes =
226+
List.of(
227+
// test:java/changes-file
228+
ChangesFile.class,
229+
230+
// test:java/changes-file-again
231+
ChangesFileAgain.class,
232+
233+
// test:java/changes-file-yet-again
234+
ChangesFileYetAgain.class);
235+
236+
CodemodLoader loader = createLoader(codemodTypes, tmpDir);
237+
List<CodemodIdPair> codemods = loader.getCodemods();
238+
assertThat(codemods.get(0).getId(), equalTo("test:java/changes-file"));
239+
assertThat(codemods.get(1).getId(), equalTo("test:java/changes-file-again"));
240+
assertThat(codemods.get(2).getId(), equalTo("test:java/changes-file-yet-again"));
241+
242+
// now we specify a --codemod-includes order to be in backwards order
243+
CodemodRegulator regulator =
244+
CodemodRegulator.of(
245+
DefaultRuleSetting.DISABLED,
246+
List.of(
247+
"test:java/changes-file-yet-again",
248+
"test:java/changes-file-again",
249+
"test:java/changes-file"));
250+
loader =
251+
new CodemodLoader(
252+
codemodTypes,
253+
regulator,
254+
tmpDir,
255+
List.of("**"),
256+
List.of(),
257+
Files.list(tmpDir).toList(),
258+
Map.of(),
259+
List.of(),
260+
List.of(),
261+
null,
262+
null,
263+
null);
264+
265+
codemods = loader.getCodemods();
266+
assertThat(codemods.get(0).getId(), equalTo("test:java/changes-file-yet-again"));
267+
assertThat(codemods.get(1).getId(), equalTo("test:java/changes-file-again"));
268+
assertThat(codemods.get(2).getId(), equalTo("test:java/changes-file"));
269+
270+
// now do it again, with only the B and C codemods
271+
regulator =
272+
CodemodRegulator.of(
273+
DefaultRuleSetting.ENABLED,
274+
List.of("test:java/changes-file-again", "test:java/changes-file"));
275+
loader =
276+
new CodemodLoader(
277+
codemodTypes,
278+
regulator,
279+
tmpDir,
280+
List.of("**"),
281+
List.of(),
282+
Files.list(tmpDir).toList(),
283+
Map.of(),
284+
List.of(),
285+
List.of(),
286+
null,
287+
null,
288+
null);
289+
290+
codemods = loader.getCodemods();
291+
assertThat(codemods, hasSize(1));
292+
assertThat(codemods.get(0).getId(), equalTo("test:java/changes-file-yet-again"));
293+
}
294+
219295
/**
220296
* We create a file, and then run two codemods on it. The first codemod adds a line, the second
221297
* adds another. This will ensure that the codemods are run in the order they are provided and
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package io.codemodder;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import java.util.List;
6+
import java.util.Optional;
7+
import org.junit.jupiter.api.Test;
8+
9+
final class CodemodRegulatorTest {
10+
11+
@Test
12+
void it_respects_order_on_includes() {
13+
CodemodRegulator regulator =
14+
CodemodRegulator.of(DefaultRuleSetting.DISABLED, List.of("c", "a", "b"));
15+
Optional<List<String>> desiredCodemodIdOrder = regulator.desiredCodemodIdOrder();
16+
assertThat(desiredCodemodIdOrder).isPresent();
17+
List<String> includeOrder = desiredCodemodIdOrder.get();
18+
assertThat(includeOrder).containsExactly("c", "a", "b");
19+
}
20+
21+
@Test
22+
void it_doesnt_opine_on_order_when_excludes() {
23+
CodemodRegulator regulator =
24+
CodemodRegulator.of(DefaultRuleSetting.ENABLED, List.of("c", "a", "b"));
25+
Optional<List<String>> desiredCodemodIdOrder = regulator.desiredCodemodIdOrder();
26+
assertThat(desiredCodemodIdOrder).isEmpty();
27+
}
28+
}

0 commit comments

Comments
 (0)