diff --git a/jadx-core/src/main/java/jadx/api/JadxDecompiler.java b/jadx-core/src/main/java/jadx/api/JadxDecompiler.java index d1cccf062..1b242b6ba 100644 --- a/jadx-core/src/main/java/jadx/api/JadxDecompiler.java +++ b/jadx-core/src/main/java/jadx/api/JadxDecompiler.java @@ -42,7 +42,7 @@ import jadx.core.xmlgen.ResourcesSaver; * jadx.load(); * jadx.save(); * - *

+ * * Instead of 'save()' you can iterate over decompiled classes: *


  *  for(JavaClass cls : jadx.getClasses()) {
diff --git a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
index d81906d09..f68d4679f 100644
--- a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
+++ b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
@@ -137,13 +137,7 @@ public class InsnGen {
 
 	private void instanceField(CodeWriter code, FieldInfo field, InsnArg arg) throws CodegenException {
 		ClassNode pCls = mth.getParentClass();
-		FieldNode fieldNode = pCls.searchField(field);
-		while (fieldNode == null
-				&& pCls.getParentClass() != pCls
-				&& pCls.getParentClass() != null) {
-			pCls = pCls.getParentClass();
-			fieldNode = pCls.searchField(field);
-		}
+		FieldNode fieldNode = pCls.dex().root().deepResolveField(field);
 		if (fieldNode != null) {
 			FieldReplaceAttr replace = fieldNode.get(AType.FIELD_REPLACE);
 			if (replace != null) {
@@ -163,7 +157,11 @@ public class InsnGen {
 		if (fieldNode != null) {
 			code.attachAnnotation(fieldNode);
 		}
-		code.add(field.getAlias());
+		if (fieldNode == null) {
+			code.add(field.getAlias());
+		} else {
+			code.add(fieldNode.getAlias());
+		}
 	}
 
 	public static void makeStaticFieldAccess(CodeWriter code, FieldInfo field, ClassGen clsGen) {
@@ -176,11 +174,15 @@ public class InsnGen {
 			}
 			code.add('.');
 		}
-		FieldNode fieldNode = clsGen.getClassNode().dex().resolveField(field);
+		FieldNode fieldNode = clsGen.getClassNode().dex().root().deepResolveField(field);
 		if (fieldNode != null) {
 			code.attachAnnotation(fieldNode);
 		}
-		code.add(field.getAlias());
+		if (fieldNode == null) {
+			code.add(field.getAlias());
+		} else {
+			code.add(fieldNode.getAlias());
+		}
 	}
 
 	protected void staticField(CodeWriter code, FieldInfo field) {
diff --git a/jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java b/jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java
index 9480ee147..6dcfaecb5 100644
--- a/jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java
+++ b/jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java
@@ -201,17 +201,13 @@ public class Deobfuscator {
 	private void collectClassHierarchy(ClassNode cls, Set collected) {
 		boolean added = collected.add(cls);
 		if (added) {
-			ArgType superClass = cls.getSuperClass();
+			ClassNode superClass = cls.getSuperClassNode();
 			if (superClass != null) {
-				ClassNode superNode = cls.dex().resolveClass(superClass);
-				if (superNode != null) {
-					collectClassHierarchy(superNode, collected);
-				}
+				collectClassHierarchy(superClass, collected);
 			}
 
-			for (ArgType argType : cls.getInterfaces()) {
-				ClassNode interfaceNode = cls.dex().resolveClass(argType);
-				if (interfaceNode != null) {
+			for (ClassNode interfaceNode : cls.getInterfaceNodes()) {
+				if(interfaceNode != null) {
 					collectClassHierarchy(interfaceNode, collected);
 				}
 			}
diff --git a/jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java b/jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java
index 6d4844f70..acb8feeef 100644
--- a/jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java
+++ b/jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java
@@ -2,9 +2,13 @@ package jadx.core.dex.info;
 
 import com.android.dex.FieldId;
 
+import com.android.dx.io.instructions.DecodedInstruction;
 import jadx.core.codegen.TypeGen;
 import jadx.core.dex.instructions.args.ArgType;
+import jadx.core.dex.nodes.ClassNode;
 import jadx.core.dex.nodes.DexNode;
+import jadx.core.dex.nodes.FieldNode;
+import jadx.core.dex.nodes.MethodNode;
 
 public final class FieldInfo {
 
diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/InsnDecoder.java b/jadx-core/src/main/java/jadx/core/dex/instructions/InsnDecoder.java
index 920802d99..0baed6ea1 100644
--- a/jadx-core/src/main/java/jadx/core/dex/instructions/InsnDecoder.java
+++ b/jadx-core/src/main/java/jadx/core/dex/instructions/InsnDecoder.java
@@ -2,7 +2,9 @@ package jadx.core.dex.instructions;
 
 import java.io.EOFException;
 
+import com.android.dex.ClassData;
 import com.android.dex.Code;
+import com.android.dex.FieldId;
 import com.android.dx.io.OpcodeInfo;
 import com.android.dx.io.Opcodes;
 import com.android.dx.io.instructions.DecodedInstruction;
@@ -10,6 +12,9 @@ import com.android.dx.io.instructions.FillArrayDataPayloadDecodedInstruction;
 import com.android.dx.io.instructions.PackedSwitchPayloadDecodedInstruction;
 import com.android.dx.io.instructions.ShortArrayCodeInput;
 import com.android.dx.io.instructions.SparseSwitchPayloadDecodedInstruction;
+import jadx.core.dex.info.ClassInfo;
+import jadx.core.dex.nodes.ClassNode;
+import jadx.core.dex.nodes.FieldNode;
 import org.jetbrains.annotations.NotNull;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
index 327a738d6..02d167257 100644
--- a/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
+++ b/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
@@ -48,7 +48,9 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
 	private final ClassInfo clsInfo;
 	private final AccessInfo accessFlags;
 	private ArgType superClass;
+	private ClassNode superClassNode;
 	private List interfaces;
+	private List interfaceNodes; //some element is null whose declaration is out of the dex files
 	private Map> genericMap;
 
 	private final List methods;
@@ -72,12 +74,17 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
 		try {
 			if (cls.getSupertypeIndex() == DexNode.NO_INDEX) {
 				this.superClass = null;
+				this.superClassNode = null;
 			} else {
 				this.superClass = dex.getType(cls.getSupertypeIndex());
+				this.superClassNode = dex.resolveClass(ClassInfo.fromType(dex.root(), superClass));
 			}
 			this.interfaces = new ArrayList<>(cls.getInterfaces().length);
+			this.interfaceNodes = new ArrayList<>(cls.getInterfaces().length);
 			for (short interfaceIdx : cls.getInterfaces()) {
-				this.interfaces.add(dex.getType(interfaceIdx));
+				ArgType intf = dex.getType(interfaceIdx);
+				this.interfaces.add(intf);
+				this.interfaceNodes.add(dex.resolveClass(intf));
 			}
 			if (cls.getClassDataOffset() != 0) {
 				ClassData clsData = dex.readClassData(cls);
@@ -138,6 +145,7 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
 		this.dex = dex;
 		this.clsInfo = clsInfo;
 		this.interfaces = Collections.emptyList();
+		this.interfaceNodes = Collections.emptyList();
 		this.methods = Collections.emptyList();
 		this.fields = Collections.emptyList();
 		this.accessFlags = new AccessInfo(AccessFlags.ACC_PUBLIC | AccessFlags.ACC_SYNTHETIC, AFType.CLASS);
@@ -280,10 +288,19 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
 		return superClass;
 	}
 
+	@Nullable
+	public ClassNode getSuperClassNode() {
+		return superClassNode;
+	}
+
 	public List getInterfaces() {
 		return interfaces;
 	}
 
+	public List getInterfaceNodes() {
+		return interfaceNodes;
+	}
+
 	public Map> getGenericMap() {
 		return genericMap;
 	}
@@ -323,7 +340,6 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
 		return null;
 	}
 
-	@TestOnly
 	public FieldNode searchFieldByName(String name) {
 		for (FieldNode f : fields) {
 			if (f.getName().equals(name)) {
diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/DexNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/DexNode.java
index bc653d8ef..b6f4008cc 100644
--- a/jadx-core/src/main/java/jadx/core/dex/nodes/DexNode.java
+++ b/jadx-core/src/main/java/jadx/core/dex/nodes/DexNode.java
@@ -95,6 +95,7 @@ public class DexNode implements IDexNode {
 		return resolveClass(ClassInfo.fromType(root, type));
 	}
 
+	@Deprecated
 	@Nullable
 	public MethodNode resolveMethod(@NotNull MethodInfo mth) {
 		ClassNode cls = resolveClass(mth.getDeclClass());
@@ -105,27 +106,23 @@ public class DexNode implements IDexNode {
 	}
 
 	@Nullable
-	MethodNode deepResolveMethod(@NotNull ClassNode cls, String signature) {
-		for (MethodNode m : cls.getMethods()) {
-			if (m.getMethodInfo().getShortId().startsWith(signature)) {
-				return m;
-			}
+	MethodNode deepResolveMethod(@NotNull ClassNode cls, MethodInfo methodInfo) {
+		MethodNode field = cls.searchMethodByName(methodInfo.getShortId());
+		if (field != null) {
+			return field;
 		}
+
 		MethodNode found;
-		ArgType superClass = cls.getSuperClass();
-		if (superClass != null) {
-			ClassNode superNode = resolveClass(superClass);
-			if (superNode != null) {
-				found = deepResolveMethod(superNode, signature);
-				if (found != null) {
-					return found;
-				}
+		ClassNode superNode = cls.getSuperClassNode();
+		if (superNode != null) {
+			found = deepResolveMethod(superNode, methodInfo);
+			if (found != null) {
+				return found;
 			}
 		}
-		for (ArgType iFaceType : cls.getInterfaces()) {
-			ClassNode iFaceNode = resolveClass(iFaceType);
-			if (iFaceNode != null) {
-				found = deepResolveMethod(iFaceNode, signature);
+		for (ClassNode interfaceNode : cls.getInterfaceNodes()) {
+			if(interfaceNode != null) {
+				found = deepResolveMethod(interfaceNode, methodInfo);
 				if (found != null) {
 					return found;
 				}
@@ -134,6 +131,7 @@ public class DexNode implements IDexNode {
 		return null;
 	}
 
+	@Deprecated
 	@Nullable
 	public FieldNode resolveField(FieldInfo field) {
 		ClassNode cls = resolveClass(field.getDeclClass());
@@ -143,6 +141,32 @@ public class DexNode implements IDexNode {
 		return null;
 	}
 
+	@Nullable
+	FieldNode deepResolveField(@NotNull ClassNode cls, FieldInfo fieldInfo) {
+		FieldNode field = cls.searchFieldByName(fieldInfo.getName());
+		if (field != null) {
+			return field;
+		}
+
+		FieldNode found;
+		ClassNode superNode = cls.getSuperClassNode();
+		if (superNode != null) {
+			found = deepResolveField(superNode, fieldInfo);
+			if (found != null) {
+				return found;
+			}
+		}
+		for (ClassNode interfaceNode : cls.getInterfaceNodes()) {
+			if(interfaceNode != null) {
+				found = deepResolveField(interfaceNode, fieldInfo);
+				if (found != null) {
+					return found;
+				}
+			}
+		}
+		return null;
+	}
+
 	public DexFile getDexFile() {
 		return file;
 	}
diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
index e4fc3115a..6207e00e5 100644
--- a/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
+++ b/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
@@ -5,6 +5,8 @@ import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
 
+import com.android.dex.Dex;
+import jadx.core.dex.info.FieldInfo;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
@@ -181,7 +183,50 @@ public class RootNode {
 		if (cls == null) {
 			return null;
 		}
-		return cls.dex().deepResolveMethod(cls, mth.makeSignature(false));
+		MethodNode resolved;
+
+		//most of the time, the method node could be found in current dex.
+		DexNode declDex = cls.dex();
+		resolved = declDex.deepResolveMethod(cls, mth);
+		if (resolved != null){
+			return resolved;
+		}
+		for (DexNode dexNode : dexNodes) {
+			if(dexNodes == declDex) {
+				continue;
+			}
+			resolved = dexNode.deepResolveMethod(cls, mth);
+			if (resolved != null){
+				return resolved;
+			}
+		}
+		return null;
+	}
+
+	@Nullable
+	public FieldNode deepResolveField(@NotNull FieldInfo field) {
+		ClassNode cls = resolveClass(field.getDeclClass());
+		if (cls == null) {
+			return null;
+		}
+		FieldNode resolved;
+
+		//most of the time, the field node could be found in current dex.
+		DexNode declDex = cls.dex();
+		resolved = declDex.deepResolveField(cls, field);
+		if (resolved != null){
+			return resolved;
+		}
+		for (DexNode dexNode : dexNodes) {
+			if(dexNodes == declDex) {
+				continue;
+			}
+			resolved = dexNode.deepResolveField(cls, field);
+			if (resolved != null){
+				return resolved;
+			}
+		}
+		return null;
 	}
 
 	public List getDexNodes() {
diff --git a/jadx-core/src/main/java/jadx/core/utils/InsnUtils.java b/jadx-core/src/main/java/jadx/core/utils/InsnUtils.java
index 4d9494964..51d2c1199 100644
--- a/jadx-core/src/main/java/jadx/core/utils/InsnUtils.java
+++ b/jadx-core/src/main/java/jadx/core/utils/InsnUtils.java
@@ -78,7 +78,7 @@ public class InsnUtils {
 				return ((ConstClassNode) insn).getClsType();
 			case SGET:
 				FieldInfo f = (FieldInfo) ((IndexInsnNode) insn).getIndex();
-				FieldNode fieldNode = dex.resolveField(f);
+				FieldNode fieldNode = dex.root().deepResolveField(f);
 				if (fieldNode == null) {
 					LOG.warn("Field {} not found in dex {}", f, dex);
 					return null;