core: fix inner class handling in classpath and signature parser
This commit is contained in:
@@ -5,6 +5,7 @@ import jadx.core.utils.exceptions.DecodeException;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -44,35 +45,47 @@ public class ClspGraph {
|
||||
throw new JadxRuntimeException("Classpath must be loaded first");
|
||||
}
|
||||
int size = classes.size();
|
||||
for (ClassNode cls : classes) {
|
||||
size += cls.getInnerClasses().size();
|
||||
}
|
||||
NClass[] nClasses = new NClass[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
ClassNode cls = classes.get(i);
|
||||
NClass nClass = new NClass(cls.getRawName(), -1);
|
||||
nClasses[i] = nClass;
|
||||
nameMap.put(cls.getRawName(), nClass);
|
||||
int k = 0;
|
||||
for (ClassNode cls : classes) {
|
||||
nClasses[k++] = addClass(cls);
|
||||
for (ClassNode inner : cls.getInnerClasses()) {
|
||||
nClasses[k++] = addClass(inner);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < size; i++) {
|
||||
nClasses[i].setParents(ClsSet.makeParentsArray(classes.get(i), nameMap));
|
||||
}
|
||||
}
|
||||
|
||||
private NClass addClass(ClassNode cls) {
|
||||
NClass nClass = new NClass(cls.getRawName(), -1);
|
||||
nameMap.put(cls.getRawName(), nClass);
|
||||
return nClass;
|
||||
}
|
||||
|
||||
public boolean isImplements(String clsName, String implClsName) {
|
||||
Set<String> anc = getAncestors(clsName);
|
||||
return anc.contains(implClsName);
|
||||
}
|
||||
|
||||
public String getCommonAncestor(String clsName, String implClsName) {
|
||||
if (isImplements(clsName, implClsName)) {
|
||||
return implClsName;
|
||||
if (clsName.equals(implClsName)) {
|
||||
return clsName;
|
||||
}
|
||||
Set<String> anc = getAncestors(clsName);
|
||||
NClass cls = nameMap.get(implClsName);
|
||||
if (cls != null) {
|
||||
if (isImplements(clsName, implClsName)) {
|
||||
return implClsName;
|
||||
}
|
||||
Set<String> anc = getAncestors(clsName);
|
||||
return searchCommonParent(anc, cls);
|
||||
} else {
|
||||
LOG.debug("Missing class: {}", implClsName);
|
||||
return null;
|
||||
}
|
||||
LOG.debug("Missing class: {}", implClsName);
|
||||
return null;
|
||||
}
|
||||
|
||||
private String searchCommonParent(Set<String> anc, NClass cls) {
|
||||
@@ -92,17 +105,21 @@ public class ClspGraph {
|
||||
|
||||
private Set<String> getAncestors(String clsName) {
|
||||
Set<String> result = ancestorCache.get(clsName);
|
||||
if (result == null) {
|
||||
result = new HashSet<String>();
|
||||
ancestorCache.put(clsName, result);
|
||||
NClass cls = nameMap.get(clsName);
|
||||
if (cls != null) {
|
||||
addAncestorsNames(cls, result);
|
||||
} else {
|
||||
LOG.debug("Missing class: {}", clsName);
|
||||
}
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
NClass cls = nameMap.get(clsName);
|
||||
if (cls != null) {
|
||||
result = new HashSet<String>();
|
||||
addAncestorsNames(cls, result);
|
||||
if (result.isEmpty()) {
|
||||
result = Collections.emptySet();
|
||||
}
|
||||
ancestorCache.put(clsName, result);
|
||||
return result;
|
||||
}
|
||||
LOG.debug("Missing class: {}", clsName);
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
private void addAncestorsNames(NClass cls, Set<String> result) {
|
||||
|
||||
@@ -72,7 +72,7 @@ public final class ClassInfo {
|
||||
|
||||
int sep = clsName.lastIndexOf('$');
|
||||
if (canBeInner && sep > 0 && sep != clsName.length() - 1) {
|
||||
String parClsName = pkg + '.' + clsName.substring(0, sep);
|
||||
String parClsName = pkg + "." + clsName.substring(0, sep);
|
||||
parentClass = fromName(parClsName);
|
||||
clsName = clsName.substring(sep + 1);
|
||||
} else {
|
||||
|
||||
@@ -179,6 +179,11 @@ public abstract class ArgType {
|
||||
this.bounds = bound;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGeneric() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgType getWildcardType() {
|
||||
return type;
|
||||
@@ -224,13 +229,18 @@ public abstract class ArgType {
|
||||
}
|
||||
|
||||
public GenericObject(GenericObject outerType, String innerName, ArgType[] generics) {
|
||||
super(outerType.getObject() + "." + innerName);
|
||||
super(outerType.getObject() + "$" + innerName);
|
||||
this.outerType = outerType;
|
||||
this.generics = generics;
|
||||
this.hash = outerType.hashCode() + 31 * innerName.hashCode()
|
||||
+ 31 * 31 * Arrays.hashCode(generics);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGeneric() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgType[] getGenericTypes() {
|
||||
return generics;
|
||||
@@ -370,6 +380,10 @@ public abstract class ArgType {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isGeneric() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isGenericType() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@ package jadx.core.dex.instructions.args;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.utils.InsnUtils;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.android.dx.io.instructions.DecodedInstruction;
|
||||
|
||||
/**
|
||||
@@ -11,6 +14,8 @@ import com.android.dx.io.instructions.DecodedInstruction;
|
||||
*/
|
||||
public abstract class InsnArg extends Typed {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(InsnArg.class);
|
||||
|
||||
protected InsnNode parentInsn;
|
||||
|
||||
public static RegisterArg reg(int regNum, ArgType type) {
|
||||
@@ -72,7 +77,10 @@ public abstract class InsnArg extends Typed {
|
||||
if (parent == null) {
|
||||
return null;
|
||||
}
|
||||
assert parent != insn : "Can't wrap instruction info itself";
|
||||
if (parent == insn) {
|
||||
LOG.debug("Can't wrap instruction info itself: " + insn);
|
||||
return null;
|
||||
}
|
||||
int count = parent.getArgsCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (parent.getArg(i) == this) {
|
||||
|
||||
@@ -6,8 +6,13 @@ import jadx.core.dex.instructions.args.TypedVar;
|
||||
import jadx.core.dex.nodes.DexNode;
|
||||
import jadx.core.utils.InsnUtils;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
final class LocalVar extends RegisterArg {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(LocalVar.class);
|
||||
|
||||
private boolean isEnd;
|
||||
|
||||
private int startAddr;
|
||||
@@ -29,13 +34,32 @@ final class LocalVar extends RegisterArg {
|
||||
|
||||
private void init(String name, ArgType type, String sign) {
|
||||
if (sign != null) {
|
||||
type = ArgType.generic(sign);
|
||||
ArgType gType = ArgType.generic(sign);
|
||||
if (checkSignature(type, sign, gType)) {
|
||||
type = gType;
|
||||
}
|
||||
}
|
||||
TypedVar tv = new TypedVar(type);
|
||||
tv.setName(name);
|
||||
forceSetTypedVar(tv);
|
||||
}
|
||||
|
||||
private boolean checkSignature(ArgType type, String sign, ArgType gType) {
|
||||
boolean apply = false;
|
||||
ArgType el = gType.getArrayRootElement();
|
||||
if (el.isGeneric()) {
|
||||
if (!type.getObject().equals(el.getObject())) {
|
||||
LOG.warn("Generic type in debug info not equals: {} != {}", type, gType);
|
||||
}
|
||||
apply = true;
|
||||
} else if (el.isGenericType()) {
|
||||
apply = true;
|
||||
} else {
|
||||
LOG.debug("Local var signature from debug info not generic: {}, parsed: {}", sign, gType);
|
||||
}
|
||||
return apply;
|
||||
}
|
||||
|
||||
public void start(int addr, int line) {
|
||||
this.isEnd = false;
|
||||
this.startAddr = addr;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package jadx.core.dex.visitors.regions;
|
||||
|
||||
import jadx.core.dex.attributes.AttributeFlag;
|
||||
import jadx.core.dex.attributes.AttributeType;
|
||||
import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.IBlock;
|
||||
import jadx.core.dex.nodes.IRegion;
|
||||
@@ -21,7 +22,9 @@ public class CheckRegions extends AbstractVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(MethodNode mth) throws JadxException {
|
||||
if (mth.isNoCode() || mth.getBasicBlocks().isEmpty()) {
|
||||
if (mth.isNoCode()
|
||||
|| mth.getBasicBlocks().isEmpty()
|
||||
|| mth.getAttributes().contains(AttributeType.JADX_ERROR)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.io.StringWriter;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class Utils {
|
||||
|
||||
|
||||
private Utils() {
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ public class TestSignatureParser {
|
||||
"c", new ArgType[]{ArgType.genericType("V")}));
|
||||
|
||||
assertEquals(p("La<TV;>.LinkedHashIterator<Lb$c<Ls;TV;>;>;").consumeType().getObject(),
|
||||
"a.LinkedHashIterator");
|
||||
"a$LinkedHashIterator");
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user