Commit 476b2c37 authored by Skylot's avatar Skylot

core: fix inner class handling in classpath and signature parser

parent 5258c836
......@@ -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) {
if (result != null) {
return result;
}
NClass cls = nameMap.get(clsName);
if (cls != 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);
addAncestorsNames(cls, result);
if (result.isEmpty()) {
result = Collections.emptySet();
}
ancestorCache.put(clsName, result);
return 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 {
......
......@@ -180,6 +180,11 @@ public abstract class ArgType {
}
@Override
public boolean isGeneric() {
return true;
}
@Override
public ArgType getWildcardType() {
return type;
}
......@@ -224,7 +229,7 @@ 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()
......@@ -232,6 +237,11 @@ public abstract class ArgType {
}
@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;
......
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");
}
......
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