Skip to content

Commit

Permalink
fix: convert inner enums and fix inner classes reference (#719)
Browse files Browse the repository at this point in the history
  • Loading branch information
skylot committed Jul 30, 2019
1 parent 068234f commit 4629043
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 7 deletions.
29 changes: 27 additions & 2 deletions jadx-core/src/main/java/jadx/core/codegen/ClassGen.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package jadx.core.codegen;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import com.android.dx.rop.code.AccessFlags;
Expand Down Expand Up @@ -148,7 +150,7 @@ public void addClassDeclaration(CodeWriter clsCode) {
ArgType sup = cls.getSuperClass();
if (sup != null
&& !sup.equals(ArgType.OBJECT)
&& !sup.getObject().equals(ArgType.ENUM.getObject())) {
&& !cls.isEnum()) {
clsCode.add("extends ");
useClass(clsCode, sup);
clsCode.add(' ');
Expand Down Expand Up @@ -513,6 +515,9 @@ private String useClassInternal(ClassInfo useCls, ClassInfo extClsInfo) {
if (isClassInnerFor(useCls, extClsInfo)) {
return shortName;
}
if (extClsInfo.isInner()) {
return expandInnerClassName(useCls, extClsInfo);
}
if (isBothClassesInOneTopClass(useCls, extClsInfo)) {
return shortName;
}
Expand Down Expand Up @@ -550,6 +555,26 @@ private String useClassInternal(ClassInfo useCls, ClassInfo extClsInfo) {
return shortName;
}

private String expandInnerClassName(ClassInfo useCls, ClassInfo extClsInfo) {
List<ClassInfo> clsList = new ArrayList<>();
clsList.add(extClsInfo);
ClassInfo parentCls = extClsInfo.getParentClass();
boolean addImport = true;
while (parentCls != null) {
if (parentCls == useCls || isClassInnerFor(useCls, parentCls)) {
addImport = false;
break;
}
clsList.add(parentCls);
parentCls = parentCls.getParentClass();
}
Collections.reverse(clsList);
if (addImport) {
addImport(clsList.get(0));
}
return Utils.listToString(clsList, ".", ClassInfo::getAliasShortName);
}

private void addImport(ClassInfo classInfo) {
if (parentGen != null) {
parentGen.addImport(classInfo);
Expand Down Expand Up @@ -579,7 +604,7 @@ private static boolean isBothClassesInOneTopClass(ClassInfo useCls, ClassInfo ex
private static boolean isClassInnerFor(ClassInfo inner, ClassInfo parent) {
if (inner.isInner()) {
ClassInfo p = inner.getParentClass();
return p.equals(parent) || isClassInnerFor(p, parent);
return Objects.equals(p, parent) || isClassInnerFor(p, parent);
}
return false;
}
Expand Down
16 changes: 11 additions & 5 deletions jadx-core/src/main/java/jadx/core/dex/visitors/EnumVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,19 @@ public class EnumVisitor extends AbstractVisitor {

@Override
public boolean visit(ClassNode cls) throws JadxException {
if (!cls.isEnum()) {
if (!convertToEnum(cls)) {
AccessInfo accessFlags = cls.getAccessFlags();
if (accessFlags.isEnum()) {
cls.setAccessFlags(accessFlags.remove(AccessFlags.ACC_ENUM));
cls.addAttr(AType.COMMENTS, "'enum' access flag removed");
cls.addAttr(AType.COMMENTS, "'enum' modifier removed");
}
return true;
}
return true;
}

private boolean convertToEnum(ClassNode cls) {
if (!cls.isEnum()) {
return false;
}
// search class init method
MethodNode staticMethod = null;
Expand All @@ -63,7 +69,7 @@ public boolean visit(ClassNode cls) throws JadxException {
}
if (staticMethod == null) {
ErrorsCounter.classWarn(cls, "Enum class init method not found");
return true;
return false;
}

ArgType clsType = cls.getClassInfo().getType();
Expand Down Expand Up @@ -167,7 +173,7 @@ public boolean visit(ClassNode cls) throws JadxException {
}
}
}
return false;
return true;
}

private static void processEnumInnerCls(ConstructorInsn co, EnumField field, ClassNode innerCls) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package jadx.tests.integration.enums;

import org.junit.jupiter.api.Test;

import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.IntegrationTest;

import static jadx.tests.api.utils.JadxMatchers.containsOne;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class TestInnerEnums extends IntegrationTest {

public static class TestCls {

public enum Numbers {
ONE(1, NumString.ONE), TWO(2, NumString.TWO);

private final int num;
private final NumString str;

public enum NumString {
ONE("one"), TWO("two");

private final String name;

NumString(String name) {
this.name = name;
}

public String getName() {
return name;
}
}

Numbers(int n, NumString str) {
this.num = n;
this.str = str;
}

public int getNum() {
return num;
}

public NumString getNumStr() {
return str;
}

public String getName() {
return str.getName();
}
}

public void check() {
assertEquals(1, Numbers.ONE.getNum());
assertEquals(Numbers.NumString.ONE, Numbers.ONE.getNumStr());
assertEquals("one", Numbers.ONE.getName());
}
}

@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();

assertThat(code, containsOne("ONE(1, NumString.ONE)"));
assertThat(code, containsOne("ONE(\"one\")"));
}
}

0 comments on commit 4629043

Please sign in to comment.