leibnitz27 / cfr

This is the public repository for the CFR Java decompiler
https://www.benf.org/other/cfr
MIT License
1.94k stars 249 forks source link

Casting to Object in generic function call causes type mismatch #232

Open rehwinkel opened 3 years ago

rehwinkel commented 3 years ago

CFR version

CFR 0.151

Compiler

javac 15.0.2

Description

Given is a class like this:

public class Extra <V> {
    public void test(V v) {
        System.out.println(v);
    }

    public static Extra<String> make() {
        return new Extra<String>();
    }
}

Decompiling the compiled code of the snippet Extra.make().test("."); when the class Extra isn't present at decompilation, CFR falsely decompiles the code snippet to Extra.make().test((Object)"."); which then causes a type mismatch error on when compiling that again (because Extra<String> doesn't have the method Extra#test(Object)).

It should be possible to fix this easily by not casting call parameters to Object or Object[]. Since any type (or corresponding array type) can be coerced to Object, it should work flawlessly.

leibnitz27 commented 3 years ago

This is the problem with type erasure - the problem here is knowledge - we just don't KNOW (provably) what's available on Extra, since it's not available. The method that actually gets called is a bridge method; it's possible that Extra ALSO has a string test method. If we have Extra available, it's possible to know this.

In this specific example, it's obvious (because you know where you want to get to), however there is a corresponding example where Extra is not generic, but has a clashing object and string method. (because the person who built it [probably me] is being an ass.)

rehwinkel commented 3 years ago

In my specific case I encountered this issue because the decompiled class was using apache commons (i think it was that. doesn't matter cause I have access to the other libraries that it could have been) but the library was not present during decompilation. Can I add decompilation dependencies? Essentially I want to use the information inside of the apache commons library without decompiling the library itself. Does CFR have the ability to do that?

leibnitz27 commented 3 years ago

In my specific case I encountered this issue because the decompiled class was using apache commons (i think it was that. doesn't matter cause I have access to the other libraries that it could have been) but the library was not present during decompilation. Can I add decompilation dependencies? Essentially I want to use the information inside of the apache commons library without decompiling the library itself. Does CFR have the ability to do that?

If the library you're using is on the classpath, it will be examined.

Because -jar and -cp don't play well together, cfr also has a --extraclasspath argument, which you can use to specify where "other jars that might help" are. Try using that to point to commons, that should be enough to let cfr find 'Extra'.