Commit 4e982722 authored by Skylot's avatar Skylot

core: fix incorrect package for R class (#99)

parent 2b1f815c
...@@ -501,6 +501,10 @@ public class ClassGen { ...@@ -501,6 +501,10 @@ public class ClassGen {
if (searchCollision(cls.dex(), useCls, extClsInfo)) { if (searchCollision(cls.dex(), useCls, extClsInfo)) {
return fullName; return fullName;
} }
// ignore classes from default package
if (extClsInfo.isDefaultPackage()) {
return shortName;
}
if (extClsInfo.getPackage().equals(useCls.getPackage())) { if (extClsInfo.getPackage().equals(useCls.getPackage())) {
fullName = extClsInfo.getNameWithoutPackage(); fullName = extClsInfo.getNameWithoutPackage();
} }
......
...@@ -52,6 +52,8 @@ import org.jetbrains.annotations.Nullable; ...@@ -52,6 +52,8 @@ import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import static jadx.core.utils.android.AndroidResourcesUtils.handleAppResField;
public class InsnGen { public class InsnGen {
private static final Logger LOG = LoggerFactory.getLogger(InsnGen.class); private static final Logger LOG = LoggerFactory.getLogger(InsnGen.class);
...@@ -169,12 +171,7 @@ public class InsnGen { ...@@ -169,12 +171,7 @@ public class InsnGen {
boolean fieldFromThisClass = clsGen.getClassNode().getClassInfo().equals(declClass); boolean fieldFromThisClass = clsGen.getClassNode().getClassInfo().equals(declClass);
if (!fieldFromThisClass) { if (!fieldFromThisClass) {
// Android specific resources class handler // Android specific resources class handler
ClassInfo parentClass = declClass.getParentClass(); if (!handleAppResField(code, clsGen, declClass)) {
if (parentClass != null && parentClass.getShortName().equals("R")) {
clsGen.useClass(code, parentClass);
code.add('.');
code.add(declClass.getAlias().getShortName());
} else {
clsGen.useClass(code, declClass); clsGen.useClass(code, declClass);
} }
code.add('.'); code.add('.');
......
...@@ -125,6 +125,10 @@ public final class ClassInfo { ...@@ -125,6 +125,10 @@ public final class ClassInfo {
return pkg; return pkg;
} }
public boolean isDefaultPackage() {
return pkg.isEmpty();
}
public String getRawName() { public String getRawName() {
return type.getObject(); return type.getObject();
} }
......
...@@ -17,10 +17,8 @@ public class FieldNode extends LineAttrNode { ...@@ -17,10 +17,8 @@ public class FieldNode extends LineAttrNode {
private ArgType type; // store signature private ArgType type; // store signature
public FieldNode(ClassNode cls, Field field) { public FieldNode(ClassNode cls, Field field) {
this.parent = cls; this(cls, FieldInfo.fromDex(cls.dex(), field.getFieldIndex()),
this.fieldInfo = FieldInfo.fromDex(cls.dex(), field.getFieldIndex()); field.getAccessFlags());
this.type = fieldInfo.getType();
this.accFlags = new AccessInfo(field.getAccessFlags(), AFType.FIELD);
} }
public FieldNode(ClassNode cls, FieldInfo fieldInfo, int accessFlags) { public FieldNode(ClassNode cls, FieldInfo fieldInfo, int accessFlags) {
......
...@@ -9,6 +9,7 @@ import jadx.core.dex.info.ClassInfo; ...@@ -9,6 +9,7 @@ import jadx.core.dex.info.ClassInfo;
import jadx.core.dex.info.ConstStorage; import jadx.core.dex.info.ConstStorage;
import jadx.core.utils.ErrorsCounter; import jadx.core.utils.ErrorsCounter;
import jadx.core.utils.StringUtils; import jadx.core.utils.StringUtils;
import jadx.core.utils.android.AndroidResourcesUtils;
import jadx.core.utils.exceptions.DecodeException; import jadx.core.utils.exceptions.DecodeException;
import jadx.core.utils.exceptions.JadxException; import jadx.core.utils.exceptions.JadxException;
import jadx.core.utils.files.DexFile; import jadx.core.utils.files.DexFile;
...@@ -97,24 +98,7 @@ public class RootNode { ...@@ -97,24 +98,7 @@ public class RootNode {
} }
public void initAppResClass() { public void initAppResClass() {
ClassNode resCls; appResClass = AndroidResourcesUtils.searchAppResClass(this);
if (appPackage == null) {
appResClass = makeClass("R");
return;
}
String fullName = appPackage + ".R";
resCls = searchClassByName(fullName);
if (resCls != null) {
appResClass = resCls;
} else {
appResClass = makeClass(fullName);
}
}
private ClassNode makeClass(String clsName) {
DexNode firstDex = dexNodes.get(0);
ClassInfo r = ClassInfo.fromName(firstDex, clsName);
return new ClassNode(firstDex, r);
} }
public void initClassPath() throws DecodeException { public void initClassPath() throws DecodeException {
...@@ -169,6 +153,18 @@ public class RootNode { ...@@ -169,6 +153,18 @@ public class RootNode {
return null; return null;
} }
public List<ClassNode> searchClassByShortName(String shortName) {
List<ClassNode> list = new ArrayList<ClassNode>();
for (DexNode dexNode : dexNodes) {
for (ClassNode cls : dexNode.getClasses()) {
if (cls.getClassInfo().getShortName().equals(shortName)) {
list.add(cls);
}
}
}
return list;
}
public List<DexNode> getDexNodes() { public List<DexNode> getDexNodes() {
return dexNodes; return dexNodes;
} }
......
package jadx.core.utils.android;
import jadx.core.codegen.ClassGen;
import jadx.core.codegen.CodeWriter;
import jadx.core.dex.info.ClassInfo;
import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.DexNode;
import jadx.core.dex.nodes.RootNode;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Android resources specific handlers
*/
public class AndroidResourcesUtils {
private static final Logger LOG = LoggerFactory.getLogger(AndroidResourcesUtils.class);
public static ClassNode searchAppResClass(RootNode root) {
String appPackage = root.getAppPackage();
String fullName = appPackage != null ? appPackage + ".R" : "R";
ClassNode resCls = root.searchClassByName(fullName);
if (resCls != null) {
return resCls;
}
List<ClassNode> candidates = root.searchClassByShortName("R");
if (candidates.size() == 1) {
return candidates.get(0);
}
if (!candidates.isEmpty()) {
LOG.info("Found several 'R' class candidates: {}", candidates);
}
LOG.warn("Unknown 'R' class, create references to '{}'", fullName);
return makeClass(root, fullName);
}
public static boolean handleAppResField(CodeWriter code, ClassGen clsGen, ClassInfo declClass) {
ClassInfo parentClass = declClass.getParentClass();
if (parentClass != null && parentClass.getShortName().equals("R")) {
clsGen.useClass(code, parentClass);
code.add('.');
code.add(declClass.getAlias().getShortName());
return true;
}
return false;
}
private static ClassNode makeClass(RootNode root, String clsName) {
DexNode firstDex = root.getDexNodes().get(0);
ClassInfo r = ClassInfo.fromName(firstDex, clsName);
return new ClassNode(firstDex, r);
}
}
...@@ -9,6 +9,8 @@ import java.util.Map; ...@@ -9,6 +9,8 @@ import java.util.Map;
import org.junit.Test; import org.junit.Test;
import static jadx.tests.api.utils.JadxMatchers.containsOne; import static jadx.tests.api.utils.JadxMatchers.containsOne;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
public class TestRFieldRestore extends IntegrationTest { public class TestRFieldRestore extends IntegrationTest {
...@@ -31,5 +33,6 @@ public class TestRFieldRestore extends IntegrationTest { ...@@ -31,5 +33,6 @@ public class TestRFieldRestore extends IntegrationTest {
ClassNode cls = getClassNode(TestCls.class); ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString(); String code = cls.getCode().toString();
assertThat(code, containsOne("return R.id.Button;")); assertThat(code, containsOne("return R.id.Button;"));
assertThat(code, not(containsString("import R;")));
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment