Skip to content

Commit 5791bc8

Browse files
committed
Fix interfaces being injected after permits clause
The clause order is extends/implements first, then permits. So if the class does not have an implements clause but it has a permits clause, we must ensure we insert the implements clause before the permits clause
1 parent 4a0cbe8 commit 5791bc8

5 files changed

Lines changed: 30 additions & 2 deletions

File tree

interfaceinjection/src/main/java/net/neoforged/jst/interfaceinjection/InjectInterfacesVisitor.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,16 +86,20 @@ private void inject(PsiClass psiClass, Collection<String> targets) {
8686
if (implementsList.getChildren().length == 0) {
8787
StringBuilder text = new StringBuilder();
8888

89+
// The clause order is extends/implements first, then permits. So if the class does not have an implements clause
90+
// but it has a permits clause, we must ensure we insert the implements clause before the permits clause
91+
PsiElement nextClause = psiClass.getPermitsList() == null ? psiClass.getLBrace() : psiClass.getPermitsList();
92+
8993
// `public class Cls{}` is valid, but we cannot inject the implements exactly next to the class name, so we need
9094
// to make sure that we have spacing
91-
if (!(psiClass.getLBrace().getPrevSibling() instanceof PsiWhiteSpace)) {
95+
if (!(nextClause.getPrevSibling() instanceof PsiWhiteSpace)) {
9296
text.append(' ');
9397
}
9498
text.append(psiClass.isInterface() ? "extends" : "implements").append(' ');
9599
text.append(interfaceImplementation);
96100
text.append(' ');
97101

98-
replacements.insertBefore(psiClass.getLBrace(), text.toString());
102+
replacements.insertBefore(nextClause, text.toString());
99103
} else {
100104
replacements.insertAfter(implementsList.getLastChild(), ", " + interfaceImplementation);
101105
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.example;
2+
3+
import com.example.InjectedInterface;
4+
5+
class Example implements InjectedInterface permits Permitted {
6+
7+
}
8+
9+
final class Permitted extends Example {}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"com/example/Example": "com/example/InjectedInterface"
3+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.example;
2+
3+
class Example permits Permitted {
4+
5+
}
6+
7+
final class Permitted extends Example {}

tests/src/test/java/net/neoforged/jst/tests/EmbeddedTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,11 @@ void testAdditiveInjection() throws Exception {
330330
runInterfaceInjectionTest("additive_injection", tempDir);
331331
}
332332

333+
@Test
334+
void testClauseOrder() throws Exception {
335+
runInterfaceInjectionTest("clause_order", tempDir);
336+
}
337+
333338
@Test
334339
void testInterfaceTarget() throws Exception {
335340
runInterfaceInjectionTest("interface_target", tempDir);

0 commit comments

Comments
 (0)