Skip to content

Commit e027858

Browse files
committed
transformer: Properly handle abstract methods in ParameterAdder
Previously abstract methods would always crash, even if no parameters were added to them. A test case was also added to check for this.
1 parent 2535b3b commit e027858

File tree

7 files changed

+78
-5
lines changed

7 files changed

+78
-5
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ plugins {
1010

1111
group 'io.github.notstirred'
1212
archivesBaseName = "dasm"
13-
version '2.2.0'
13+
version '2.2.1'
1414

1515
ext.ossrhUsername = project.findProperty("ossrhUsername") ?: "" // Enter in ~/.gradle/gradle.properties, not here.
1616
ext.ossrhPassword = project.findProperty("ossrhPassword") ?: "" // Enter in ~/.gradle/gradle.properties, not here.

src/main/java/io/github/notstirred/dasm/annotation/parse/RedirectSetImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ public static RedirectSetImpl parse(ClassNode redirectSetClassNode, ClassNodePro
133133
// Verify that there are no non-static members
134134
boolean nonStaticMembersExist = innerClassNode.methods.stream()
135135
// filter the default constructor, it's not a valid redirect anyway.
136-
.filter(methodNode -> !(methodNode.name.equals("<init>") && methodNode.desc.equals("()V")))
136+
.filter(methodNode -> !((methodNode.name.equals("<init>") || methodNode.name.equals("<clinit>")) && methodNode.desc.equals("()V")))
137137
.anyMatch(method -> (method.access & ACC_STATIC) == 0) |
138138
innerClassNode.fields.stream().anyMatch(field -> (field.access & ACC_STATIC) == 0);
139139
if (nonStaticMembersExist) {
@@ -174,7 +174,7 @@ private static void parseMethods(ClassNode innerClassNode, Type srcType, Type ds
174174
Set<MethodRedirectImpl> methodRedirects, Set<FieldToMethodRedirectImpl> fieldToMethodRedirects,
175175
Set<ConstructorToFactoryRedirectImpl> constructorToFactoryRedirects, DasmClassExceptions exceptions) {
176176
for (MethodNode methodNode : innerClassNode.methods) {
177-
if (methodNode.name.equals("<init>") && (methodNode.signature == null || methodNode.signature.equals("()V"))) {
177+
if ((methodNode.name.equals("<init>") || methodNode.name.equals("<clinit>")) && (methodNode.signature == null || methodNode.signature.equals("()V"))) {
178178
continue; // Skip default empty constructor
179179
}
180180

src/main/java/io/github/notstirred/dasm/transformer/ParameterAdder.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,12 @@ public void visitMaxs(int maxStack, int maxLocals) {
111111

112112
@Override
113113
public void visitEnd() {
114-
super.visitMaxs(this.maxStack, this.maxLocals + this.addedParameterTypeSize);
114+
// endLabel is only null if there is no code (an abstract method), in which case nothing else has been called
115+
if (this.endLabel != null) {
116+
super.visitMaxs(this.maxStack, this.maxLocals + this.addedParameterTypeSize);
115117

116-
super.visitLabel(this.endLabel);
118+
super.visitLabel(this.endLabel);
119+
}
117120
super.visitEnd();
118121
}
119122
}

src/test/java/io/github/notstirred/dasm/test/TestHarness.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import java.io.IOException;
2121
import java.io.InputStream;
22+
import java.lang.reflect.AccessFlag;
2223
import java.lang.reflect.InvocationTargetException;
2324
import java.lang.reflect.Method;
2425
import java.nio.file.Files;
@@ -230,6 +231,10 @@ private static void callAllMethodsWithDummies(Class<?> actualClass, Class<?> exp
230231
// Create instances of test classes
231232
Object actualInstance;
232233
try {
234+
// Can't test abstract classes
235+
if (actualClassLoaded.accessFlags().contains(AccessFlag.ABSTRACT)) {
236+
return;
237+
}
233238
actualInstance = actualClassLoaded.getConstructor().newInstance();
234239
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
235240
throw new RuntimeException("Failed to create transformed class instance for " + actualClassLoaded.getName(), e);
@@ -251,6 +256,10 @@ private static void callAllMethodsWithDummies(Class<?> actualClass, Class<?> exp
251256
try {
252257
actualMethod = actualClassLoaded.getDeclaredMethod(expectedMethod.getName(), expectedMethod.getParameterTypes());
253258
actualMethod.setAccessible(true);
259+
// Can't test abstract methods
260+
if (actualMethod.accessFlags().contains(AccessFlag.ABSTRACT)) {
261+
continue;
262+
}
254263
} catch (NoSuchMethodException e) {
255264
throw new RuntimeException("Transformed class missing expected method `" + expectedMethod + "`", e);
256265
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package io.github.notstirred.dasm.test.tests.add_parameter_no_code_case;
2+
3+
import io.github.notstirred.dasm.test.targets.A;
4+
5+
public abstract class AddParameterAbstractInput {
6+
public abstract void method1();
7+
8+
public abstract void method2(A foo);
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package io.github.notstirred.dasm.test.tests.add_parameter_no_code_case;
2+
3+
import io.github.notstirred.dasm.test.targets.A;
4+
import io.github.notstirred.dasm.test.targets.B;
5+
import io.github.notstirred.dasm.test.targets.C;
6+
7+
public abstract class AddParameterAbstractOutput {
8+
public abstract void method1();
9+
10+
public abstract void method1out();
11+
12+
public abstract void method2(A foo);
13+
14+
public abstract void method2out(B foo, C foo2);
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package io.github.notstirred.dasm.test.tests.add_parameter_no_code_case;
2+
3+
import io.github.notstirred.dasm.api.annotations.Dasm;
4+
import io.github.notstirred.dasm.api.annotations.redirect.redirects.TypeRedirect;
5+
import io.github.notstirred.dasm.api.annotations.redirect.sets.RedirectSet;
6+
import io.github.notstirred.dasm.api.annotations.selector.MethodSig;
7+
import io.github.notstirred.dasm.api.annotations.selector.Ref;
8+
import io.github.notstirred.dasm.api.annotations.transform.AddUnusedParam;
9+
import io.github.notstirred.dasm.api.annotations.transform.TransformFromMethod;
10+
import io.github.notstirred.dasm.test.targets.A;
11+
import io.github.notstirred.dasm.test.targets.B;
12+
import io.github.notstirred.dasm.test.targets.C;
13+
import io.github.notstirred.dasm.test.tests.BaseMethodTest;
14+
15+
import static io.github.notstirred.dasm.test.tests.TestData.single;
16+
17+
@Dasm(TestAddParameterAbstract.Set.class)
18+
public class TestAddParameterAbstract extends BaseMethodTest {
19+
public TestAddParameterAbstract() {
20+
super(single(AddParameterAbstractInput.class, AddParameterAbstractOutput.class, TestAddParameterAbstract.class));
21+
}
22+
23+
// Error case for https://discord.com/channels/316679487955927050/317206370359443458/1343090582087532544
24+
// An abstract method without an added parameter.
25+
@TransformFromMethod(value = @MethodSig("method1()V"))
26+
public native void method1out1();
27+
28+
@TransformFromMethod(value = @MethodSig("method2(Lio/github/notstirred/dasm/test/targets/A;)V"))
29+
public native void method2out(B foo, @AddUnusedParam C foo2);
30+
31+
@RedirectSet
32+
public interface Set {
33+
@TypeRedirect(from = @Ref(A.class), to = @Ref(B.class))
34+
abstract class A_to_B {
35+
}
36+
}
37+
}

0 commit comments

Comments
 (0)