Skip to content

Commit

Permalink
fix: Crashes when records contain static fields (#6095)
Browse files Browse the repository at this point in the history
Spoon tried to remove the field to prevent record field duplication.
This fails for static fields, which do not exist (yet). For these, spoon
passed null to the remove method, which failed with an exception. We now
check for the modifier and null explicitly.
  • Loading branch information
I-Al-Istannen authored Dec 11, 2024
1 parent 2cf9fb2 commit f57bf23
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 2 deletions.
7 changes: 5 additions & 2 deletions src/main/java/spoon/support/compiler/jdt/ParentExiter.java
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,11 @@ public <T> void scanCtType(CtType<T> type) {
} else if (child instanceof CtField<?> field) {
// We add the field in addRecordComponent. Afterward, however, JDT visits the Field itself -> Duplication.
// To combat this, we delete the existing field and trust JDTs version.
if (type instanceof CtRecord record) {
record.removeField(record.getField(field.getSimpleName()));
if (type instanceof CtRecord record && !field.isStatic()) {
CtField<?> existing = record.getField(field.getSimpleName());
if (existing != null) {
record.removeField(existing);
}
}
type.addField(field);
return;
Expand Down
16 changes: 16 additions & 0 deletions src/test/java/spoon/test/record/CtRecordTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import spoon.reflect.code.CtReturn;
import spoon.reflect.code.CtStatement;
import spoon.reflect.declaration.CtAnonymousExecutable;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtConstructor;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtField;
Expand Down Expand Up @@ -315,6 +316,21 @@ void testProperReturnInRecordAccessor(Factory factory) {
}
}

@Test
void testRecordWithStaticField() {
// contract: Static fields in records do not cause crashes
CtClass<?> parsed = Launcher.parseClass("""
public record User(int id, String name) {
private static String ADMIN_NAME = "admin";
}
""");
assertThat(parsed).isInstanceOf(CtRecord.class);
assertThat(parsed).getFields().hasSize(3);
assertThat(parsed.getFields()).anySatisfy(it -> assertThat(it.getSimpleName()).isEqualTo("id"));
assertThat(parsed.getFields()).anySatisfy(it -> assertThat(it.getSimpleName()).isEqualTo("name"));
assertThat(parsed.getFields()).anySatisfy(it -> assertThat(it.getSimpleName()).isEqualTo("ADMIN_NAME"));
}

private <T> T head(Collection<T> collection) {
return collection.iterator().next();
}
Expand Down

0 comments on commit f57bf23

Please sign in to comment.