Skip to content

Commit

Permalink
fix: (Javac) Executable#getGenericParameterTypes is broken.
Browse files Browse the repository at this point in the history
  • Loading branch information
teletha committed Apr 23, 2024
1 parent 20347ff commit f576a0a
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 4 deletions.
8 changes: 5 additions & 3 deletions src/main/java/reincarnation/LocalVariables.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*/
package reincarnation;

import static reincarnation.OperandUtil.load;
import static reincarnation.OperandUtil.*;

import java.lang.reflect.Executable;
import java.lang.reflect.Parameter;
Expand All @@ -21,6 +21,7 @@
import java.util.Set;

import reincarnation.coder.Naming;
import reincarnation.util.Classes;

/**
* Local variable manager.
Expand Down Expand Up @@ -53,11 +54,12 @@ final class LocalVariables implements Naming {
int offset = 0;

if (isStatic == false) {
params.put(offset++, new OperandLocalVariable(clazz, 0, "this"));
params.put(offset, new OperandLocalVariable(clazz, offset, "this"));
offset++;
}

if (exe != null) {
Type[] types = exe.getGenericParameterTypes();
Type[] types = Classes.fixGenericParameterTypes(exe);
Parameter[] parameters = exe.getParameters();

for (int i = 0; i < types.length; i++) {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/reincarnation/coder/java/JavaCoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ private void writeLocalClass(Class clazz) {
*/
private Join buildParameter(Executable executable, Naming strategy) {
List<Ⅱ<Parameter, Type>> params = I.signal(executable.getParameters())
.combine(I.signal(executable.getGenericParameterTypes()))
.combine(I.signal(Classes.fixGenericParameterTypes(executable)))
.toList();

return Join.of(params)
Expand Down
32 changes: 32 additions & 0 deletions src/main/java/reincarnation/util/Classes.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
*/
package reincarnation.util;

import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;
Expand Down Expand Up @@ -201,4 +204,33 @@ public static boolean isWrapper(Method method) {
|| (type == Short.class && name.equals("valueOf")) // for short
|| (type == Character.class && name.equals("valueOf")); // for char
}

/**
* Calling Executable#getGenericParameterTypes in class files compiled with Javac and ECJ
* returns different results for some APIs. (Enum constructors only?).
*
* It seems to be caused by whether the parameter qualifier is Synthetic or Mandated, but I
* don't know the details.
*
* @param executable
* @return
*/
public static Type[] fixGenericParameterTypes(Executable executable) {
Class<?> clazz = executable.getDeclaringClass();
if (clazz.isEnum() && Constructor.class.isInstance(executable)) {
Type[] types = executable.getGenericParameterTypes();
Class<?>[] params = executable.getParameterTypes();

if (types.length < params.length) {
Type[] fixed = new Type[params.length];
System.arraycopy(types, 0, fixed, params.length - types.length, types.length);
fixed[0] = String.class; // enum name
fixed[1] = int.class; // enum ordinal

return fixed;
}
}

return executable.getGenericParameterTypes();
}
}

0 comments on commit f576a0a

Please sign in to comment.