Issue details
I recompiled this game https://fruit-cut-mania.apk.gold/ and I had some compilation issues due to missing generics types e.g.
class com.mobaxe.fruitcut.screens.GameScreen
private void playAgain() {
/* this.adIsShowed = false; */ // remove ads
this.healthScore = 3;
this.score = 0;
this.drawChopper = true;
this.fadeTimeAlpha = 0.0f;
this.fadeTimeAlphaHealth = 0.0f;
this.fadeTimeAlphaBG = 0.0f;
this.fadeTimeAlphaBlood = 0.0f;
this.docPerScreen = 0;
if (this.dragPos.size() != 0) {
this.dragPos.clear();
}
this.swipeSound.resume();
this.throwSound.resume();
this.meatSliceSound.resume();
this.chopperSound.resume();
Iterator i$ = this.stage.getActors().iterator(); // should be 'Iterator<Actor> i$ = this.stage.getActors().iterator();
while (i$.hasNext()) {
Actor actor = i$.next();
actor.setVisible(false);
}
gameState = GameState.RUNNING;
/* if (FruitCut.actionResolver != null) { // remove ads
FruitCut.actionResolver.showAds(1);
} */
}
I tracked the issue down and indeed in smali the generics type for Iterator i$ was missing. To reproduce this error I created a minimal sample:
package generics;
import java.util.Iterator;
public class TestMissingGenericsTypes2<T> implements Iterable<T> {
@Override
public Iterator<T> iterator() {
return null;
}
public void test(TestMissingGenericsTypes2<String> l) {
Iterator<String> i = l.iterator(); // <-- This generics type was removed in smali
while (i.hasNext()) {
String s = i.next();
doSomething(s);
}
}
private void doSomething(String s) {
}
}
and I edited the class in smali:
.class public Lgenerics/TestMissingGenericsTypes2;
.super Ljava/lang/Object;
.source "TestMissingGenericsTypes2.java"
# interfaces
.implements Ljava/lang/Iterable;
# annotations
.annotation system Ldalvik/annotation/Signature;
value = {
"<T:",
"Ljava/lang/Object;",
">",
"Ljava/lang/Object;",
"Ljava/lang/Iterable<",
"TT;>;"
}
.end annotation
# direct methods
.method public constructor <init>()V
.registers 1
.local p0, "this":Lgenerics/TestMissingGenericsTypes2;, "Lgenerics/TestMissingGenericsTypes2<TT;>;"
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
.method private doSomething(Ljava/lang/String;)V
.registers 2
.param p1, "s" # Ljava/lang/String;
.local p0, "this":Lgenerics/TestMissingGenericsTypes2;, "Lgenerics/TestMissingGenericsTypes2<TT;>;"
return-void
.end method
# virtual methods
.method public iterator()Ljava/util/Iterator;
.registers 2
.annotation system Ldalvik/annotation/Signature;
value = {
"()",
"Ljava/util/Iterator<",
"TT;>;"
}
.end annotation
.local p0, "this":Lgenerics/TestMissingGenericsTypes2;, "Lgenerics/TestMissingGenericsTypes2<TT;>;"
const/4 v0, 0x0
return-object v0
.end method
.method public test(Lgenerics/TestMissingGenericsTypes2;)V
.registers 4
.annotation system Ldalvik/annotation/Signature;
value = {
"(",
"Lgenerics/TestMissingGenericsTypes2<",
"Ljava/lang/String;",
">;)V"
}
.end annotation
.local p0, "this":Lgenerics/TestMissingGenericsTypes2;, "Lgenerics/TestMissingGenericsTypes2<TT;>;"
.local p1, "l":Lgenerics/TestMissingGenericsTypes2;, "Lgenerics/TestMissingGenericsTypes2<Ljava/lang/String;>;"
invoke-virtual {p1}, Lgenerics/TestMissingGenericsTypes2;->iterator()Ljava/util/Iterator;
move-result-object v0
.local v0, "i":Ljava/util/Iterator; # comment out generics type: , "Ljava/util/Iterator<Ljava/lang/String;>;"
:goto_4
invoke-interface {v0}, Ljava/util/Iterator;->hasNext()Z
move-result v1
if-eqz v1, :cond_14
invoke-interface {v0}, Ljava/util/Iterator;->next()Ljava/lang/Object;
move-result-object v1
check-cast v1, Ljava/lang/String;
.local v1, "s":Ljava/lang/String;
invoke-direct {p0, v1}, Lgenerics/TestMissingGenericsTypes2;->doSomething(Ljava/lang/String;)V
.end local v1 # "s":Ljava/lang/String;
goto :goto_4
:cond_14
return-void
.end method
I have some questions here:
- What is the expected decompilation result? Should this Iterator-sample decompile to a for-each loop or should it be decompiled to its original code with restored generics types? With a one line change in LoopRegionVisitor I could ignore missing generics by generating for-each loops. I would prepare a PR for this solution, is this is the expected result. See here: nitram84@86eb7a7
The missing generics type should be restored anyway. I don't have a fix for this:
public void test(TestMissingGenericsTypes2<String> l) {
Iterator<String> i = l.iterator(); // <-- Remove this generics type in smali
if (i.hasNext()) {
String s = i.next();
doSomething(s);
}
}
-
Which visitor/pass should validate types and check and restore missing generics types? Is there already a suitable visitor for type validation or should a new one be created? Can you give me a hint here?
-
Just an idea: This is a libGDX based app and there are a lot of libGDX based app out there. I found the recompilation success rate with jadx is high for libGDX based apps. I think it would be possible to write a jadx-plugin to assist recompiling libGDX based apps. Dependencies and versions are easy to detect. One issue would be the gradle template. Normally libGDX generates its own gradle files. I'm using my own libGDX gradle template based on jadx. Following features would be nice for an extended plugin api:
- provide gradle templates for export by plugins
- (or) add contributions to gradle files
- ability to collect dependencies
Relevant log output or stacktrace
Provide sample and class/method full name
see above
Jadx version
latest git, 1.5.3
Issue details
I recompiled this game https://fruit-cut-mania.apk.gold/ and I had some compilation issues due to missing generics types e.g.
class com.mobaxe.fruitcut.screens.GameScreenI tracked the issue down and indeed in smali the generics type for
Iterator i$was missing. To reproduce this error I created a minimal sample:and I edited the class in smali:
I have some questions here:
The missing generics type should be restored anyway. I don't have a fix for this:
Which visitor/pass should validate types and check and restore missing generics types? Is there already a suitable visitor for type validation or should a new one be created? Can you give me a hint here?
Just an idea: This is a libGDX based app and there are a lot of libGDX based app out there. I found the recompilation success rate with jadx is high for libGDX based apps. I think it would be possible to write a jadx-plugin to assist recompiling libGDX based apps. Dependencies and versions are easy to detect. One issue would be the gradle template. Normally libGDX generates its own gradle files. I'm using my own libGDX gradle template based on jadx. Following features would be nice for an extended plugin api:
Relevant log output or stacktrace
Provide sample and class/method full name
see above
Jadx version
latest git, 1.5.3