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/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..9fb494a25 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
@@ -323,7 +323,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..61156928f 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());
@@ -134,6 +135,7 @@ public class DexNode implements IDexNode {
 		return null;
 	}
 
+	@Deprecated
 	@Nullable
 	public FieldNode resolveField(FieldInfo field) {
 		ClassNode cls = resolveClass(field.getDeclClass());
@@ -143,6 +145,35 @@ 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;
+		ArgType superClass = cls.getSuperClass();
+		if (superClass != null) {
+			ClassNode superNode = resolveClass(superClass);
+			if (superNode != null) {
+				found = deepResolveField(superNode, fieldInfo);
+				if (found != null) {
+					return found;
+				}
+			}
+		}
+		for (ArgType iFaceType : cls.getInterfaces()) {
+			ClassNode iFaceNode = resolveClass(iFaceType);
+			if (iFaceNode != null) {
+				found = deepResolveField(iFaceNode, 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..84e38e6b1 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;
@@ -84,12 +86,9 @@ public class RootNode {
 		}
 		ResTableParser parser = new ResTableParser();
 		try {
-			ResourcesLoader.decodeStream(arsc, new ResourcesLoader.ResourceDecoder() {
-				@Override
-				public ResContainer decode(long size, InputStream is) throws IOException {
-					parser.decode(is);
-					return null;
-				}
+			ResourcesLoader.decodeStream(arsc, (size, is) -> {
+				parser.decode(is);
+				return null;
 			});
 		} catch (JadxException e) {
 			LOG.error("Failed to parse '.arsc' file", e);
@@ -184,6 +183,15 @@ public class RootNode {
 		return cls.dex().deepResolveMethod(cls, mth.makeSignature(false));
 	}
 
+	@Nullable
+	public FieldNode deepResolveField(@NotNull FieldInfo field) {
+		ClassNode cls = resolveClass(field.getDeclClass());
+		if (cls == null) {
+			return null;
+		}
+		return cls.dex().deepResolveField(cls, field);
+	}
+
 	public List getDexNodes() {
 		return dexNodes;
 	}
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;