skylot / jadx

Dex to Java decompiler
Apache License 2.0
41.82k stars 4.89k forks source link

Jadx fails to retain generic parameters in generic classes[core] #2002

Open xxh160 opened 1 year ago

xxh160 commented 1 year ago

Issue details

In certain scenarios, the generic parameters of a generic class are lost. This leads to a compilation error when inheriting from a generic class that has final methods.

Relevant log output or stacktrace

./out/sources/defpackage/T1.java:10: error: incompatible types: Object cannot be converted to Character
        return new T1().foo(1);
                           ^
Note: ./out/sources/defpackage/T1.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
1 error

Provide sample and class/method full name

The example code is as follows:

class T2<H, R extends Integer> {
  public final H foo(R r) { return null; }
}

class T1<NEVER_USED> extends T2<Character, Integer> {
  public Character cc() {
    Character c = new T1<Integer>().foo(1);
    return c;
  }
}

The decompiled code is as follows:

=== T1_decompiled.java ===
package defpackage;
/* compiled from: Demo.java */
/* renamed from: T1  reason: default package */
/* loaded from: /home/xiayi/Mine/workspace/gradup-b/statistic/demo/jadx/11/de/classes.dex */
class T1<NEVER_USED> extends T2<Character, Integer> {
    T1() {
    }

    public Character cc() {
        return new T1().foo(1);
    }
}

=== T2_decompiled.java ===
package defpackage;

import java.lang.Integer;
/* compiled from: Demo.java */
/* renamed from: T2  reason: default package */
/* loaded from: /home/xiayi/Mine/workspace/gradup-b/statistic/demo/jadx/11/de/classes.dex */
class T2<H, R extends Integer> {
    public final H foo(R r) {
        return null;
    }
}

Jadx version

1.4.7

xxh160 commented 9 months ago

@skylot I'd like to provide an additional example:

class T1<M> {
    public M foo() {
        return null;
    }
}

class T2<W> extends T1<Double> {
}

public class Demo2 {
    public static double d = new T2<String>().foo();
}

After decompilation with Jadx 1.4.7, the output is transformed as follows:

class T1<M> {
    public M foo() {
        return null;
    }
}

class T2<W> extends T1<Double> {
}

public class Demo2 {
    public static double d = new T2().foo().doubleValue();
}

In this case, the generic parameter of T2 in Demo2 is lost, leading to the foo() method's return value being conservatively judged as Object, which ultimately results in a compilation error:

./out/sources/defpackage/Demo2.java:5: error: cannot find symbol
    public static double d = new T2().foo().doubleValue();
                                           ^
  symbol:   method doubleValue()
  location: class Object
1 error

I hope this will be helpful!