Skip to content

Commit

Permalink
Support calling required super() in expression compiler generated code
Browse files Browse the repository at this point in the history
  • Loading branch information
Col-E committed Jan 17, 2024
1 parent 00b74cc commit 38d3c80
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,12 @@ private String generateClass(@Nonnull String expression) throws ExpressionCompil

// Method structure to house the expression
int parameterVarIndex = 0;
if (AccessFlag.isPublic(methodFlags))
code.append("public ");
else if (AccessFlag.isProtected(methodFlags))
code.append("protected ");
else if (AccessFlag.isPrivate(methodFlags))
code.append("private ");
if (AccessFlag.isStatic(methodFlags))
code.append("static ");
else
Expand Down Expand Up @@ -317,7 +323,10 @@ private String generateClass(@Nonnull String expression) throws ExpressionCompil
for (MethodMember method : methods) {
// Skip stubbing of illegally named methods.
String name = method.getName();
if (!isSafeName(name))
boolean isCtor = false;
if (name.equals("<init>"))
isCtor = true;
else if (!isSafeName(name))
continue;

// Skip stubbing the method if it is the one we're assembling the expression within.
Expand Down Expand Up @@ -345,9 +354,19 @@ private String generateClass(@Nonnull String expression) throws ExpressionCompil
continue;

// Stub the method
if (method.hasPublicModifier())
code.append("public ");
else if (method.hasProtectedModifier())
code.append("protected ");
else if (method.hasPrivateModifier())
code.append("private ");
if (method.hasStaticModifier())
code.append("static ");
code.append(returnInfo.className).append(' ').append(returnInfo.name).append('(');

if (isCtor)
code.append(StringUtil.shortenPath(className)).append('(');
else
code.append(returnInfo.className).append(' ').append(returnInfo.name).append('(');
List<ClassType> methodParameterTypes = localMethodType.parameterTypes();
parameterCount = methodParameterTypes.size();
for (int i = 0; i < parameterCount; i++) {
Expand All @@ -356,7 +375,18 @@ private String generateClass(@Nonnull String expression) throws ExpressionCompil
code.append(paramInfo.className).append(' ').append(paramInfo.name);
if (i < parameterCount - 1) code.append(", ");
}
code.append(") { throw new RuntimeException(); }\n");
code.append(") { ");
if (isCtor) {
code.append("super(");
for (int i = 0; i < parameterCount; i++) {
code.append('p').append(i);
if (i < parameterCount - 1) code.append(", ");
}
code.append(");");
} else {
code.append("throw new RuntimeException();");
}
code.append(" }\n");
}

// Done with the class
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import software.coley.recaf.test.TestBase;
import software.coley.recaf.test.TestClassUtils;
import software.coley.recaf.test.dummy.ClassWithFieldsAndMethods;
import software.coley.recaf.test.dummy.ClassWithRequiredConstructor;
import software.coley.recaf.test.dummy.DummyEnum;
import software.coley.recaf.workspace.model.Workspace;

Expand All @@ -24,14 +25,16 @@ class ExpressionCompilerTest extends TestBase {
static ExpressionCompiler assembler;
static Workspace workspace;
static JvmClassInfo targetClass;
static JvmClassInfo targetCtorClass;
static JvmClassInfo targetEnum;

@BeforeAll
static void setup() throws IOException {
assembler = recaf.get(ExpressionCompiler.class);
targetClass = TestClassUtils.fromRuntimeClass(ClassWithFieldsAndMethods.class);
targetCtorClass = TestClassUtils.fromRuntimeClass(ClassWithRequiredConstructor.class);
targetEnum = TestClassUtils.fromRuntimeClass(DummyEnum.class);
workspace = TestClassUtils.fromBundle(TestClassUtils.fromClasses(targetClass, targetEnum));
workspace = TestClassUtils.fromBundle(TestClassUtils.fromClasses(targetClass, targetCtorClass, targetEnum));
workspaceManager.setCurrent(workspace);
}

Expand Down Expand Up @@ -69,6 +72,13 @@ void classContext() {
assertSuccess(result);
}

@Test
void classContextWithRequiredCtor() {
assembler.setClassContext(targetCtorClass);
ExpressionResult result = compile("");
assertSuccess(result);
}

@Test
void enumContext() {
assembler.setClassContext(targetEnum);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ public int plusTwo() {
return finalInt + 2;
}

private int minusOne() {
return finalInt - 1;
}

public static int getConstInt() {
return CONST_INT;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package software.coley.recaf.test.dummy;

import jakarta.annotation.Nonnull;
import software.coley.collections.delegate.DelegatingSortedSet;

import java.util.SortedSet;

/**
* Dummy class which has a constructor it must implement from its parent type.
*/
public class ClassWithRequiredConstructor extends DelegatingSortedSet<Object> {
public ClassWithRequiredConstructor(@Nonnull SortedSet<Object> delegate) {
super(delegate);
}
}

0 comments on commit 38d3c80

Please sign in to comment.