fix: use super instead this when super member is shadowed (PR #878)

* Added failing test for super member shadowing.
* Fixed new test containing incorrect variable names.
* Implemented marking super fields used in a subclass with super keyword.
* Renamed member variable in the example to reflect smali and test.
* Fixed formatting and imports.
This commit is contained in:
Bendegúz Ács
2020-03-07 17:52:21 +01:00
committed by GitHub
parent 89dbae8f8e
commit 3c7be5e9be
8 changed files with 160 additions and 22 deletions
+2 -22
View File
@@ -11,28 +11,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jadx.api.JadxArgs;
import jadx.core.dex.visitors.AttachMethodDetails;
import jadx.core.dex.visitors.ClassModifier;
import jadx.core.dex.visitors.ConstInlineVisitor;
import jadx.core.dex.visitors.ConstructorVisitor;
import jadx.core.dex.visitors.DeboxingVisitor;
import jadx.core.dex.visitors.DependencyCollector;
import jadx.core.dex.visitors.DotGraphVisitor;
import jadx.core.dex.visitors.EnumVisitor;
import jadx.core.dex.visitors.ExtractFieldInit;
import jadx.core.dex.visitors.FallbackModeVisitor;
import jadx.core.dex.visitors.FixAccessModifiers;
import jadx.core.dex.visitors.IDexTreeVisitor;
import jadx.core.dex.visitors.InitCodeVariables;
import jadx.core.dex.visitors.MarkFinallyVisitor;
import jadx.core.dex.visitors.MethodInlineVisitor;
import jadx.core.dex.visitors.MethodInvokeVisitor;
import jadx.core.dex.visitors.ModVisitor;
import jadx.core.dex.visitors.PrepareForCodeGen;
import jadx.core.dex.visitors.ProcessAnonymous;
import jadx.core.dex.visitors.ReSugarCode;
import jadx.core.dex.visitors.RenameVisitor;
import jadx.core.dex.visitors.SimplifyVisitor;
import jadx.core.dex.visitors.*;
import jadx.core.dex.visitors.blocksmaker.BlockExceptionHandler;
import jadx.core.dex.visitors.blocksmaker.BlockFinish;
import jadx.core.dex.visitors.blocksmaker.BlockProcessor;
@@ -71,6 +50,7 @@ public class Jadx {
passes.add(new DebugInfoParseVisitor());
}
passes.add(new FindSuperUsageVisitor());
passes.add(new BlockSplitter());
if (args.isRawCFGOutput()) {
passes.add(DotGraphVisitor.dumpRaw());
@@ -33,6 +33,7 @@ public enum AFlag {
ANONYMOUS_CLASS,
THIS,
SUPER,
/**
* RegisterArg attribute for method arguments
@@ -11,6 +11,7 @@ import jadx.core.utils.exceptions.JadxRuntimeException;
public class RegisterArg extends InsnArg implements Named {
public static final String THIS_ARG_NAME = "this";
public static final String SUPER_ARG_NAME = "super";
protected final int regNum;
// not null after SSATransform pass
@@ -87,6 +88,9 @@ public class RegisterArg extends InsnArg implements Named {
@Override
public String getName() {
if (isSuper()) {
return SUPER_ARG_NAME;
}
if (isThis()) {
return THIS_ARG_NAME;
}
@@ -96,6 +100,10 @@ public class RegisterArg extends InsnArg implements Named {
return sVar.getName();
}
private boolean isSuper() {
return contains(AFlag.SUPER);
}
@Override
public void setName(String name) {
if (sVar != null && name != null) {
@@ -0,0 +1,49 @@
package jadx.core.dex.visitors;
import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.instructions.args.RegisterArg;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.visitors.blocksmaker.BlockSplitter;
import jadx.core.utils.exceptions.JadxException;
@JadxVisitor(
name = "FindSuperUsageVisitor",
desc = "Finds variables where a member of the super class is used and marks them.",
runBefore = BlockSplitter.class
)
public class FindSuperUsageVisitor extends AbstractVisitor {
@Override
public void visit(MethodNode mth) throws JadxException {
if (mth.isNoCode()) {
return;
}
process(mth);
}
private static void process(MethodNode methodNode) {
ArgType superClass = methodNode.getParentClass().getSuperClass();
if (superClass == null) {
return;
}
String superClassName = superClass.getObject();
if (superClassName.equals("java.lang.Object")) {
return;
}
for (InsnNode instruction : methodNode.getInstructions()) {
if (instruction != null) {
for (InsnArg argument : instruction.getArguments()) {
if (argument.isRegister()) {
ArgType argumentType = ((RegisterArg) argument).getInitType();
if (argumentType.isObject() && argumentType.getObject().equals(superClassName)) {
argument.add(AFlag.SUPER);
}
}
}
}
}
}
}
@@ -0,0 +1,47 @@
package jadx.tests.integration.others;
import org.junit.jupiter.api.Test;
import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.SmaliTest;
import static jadx.tests.api.utils.JadxMatchers.containsOne;
import static org.hamcrest.MatcherAssert.assertThat;
public class TestShadowingSuperMember extends SmaliTest {
// @formatter:off
/*
public class C {
public C(String s) {
}
}
public class A {
public int A00;
public A(String s) {
}
}
public class B extends A {
public C A00;
public B(String str) {
super(str);
}
public int add(int b) {
return super.A00 + b;
}
}
*/
// @formatter:on
@Test
public void test() {
allowWarnInCode();
ClassNode cls = getClassNodeFromSmaliFiles("B");
String code = cls.getCode().toString();
assertThat(code, containsOne("return super.A00 + "));
}
}
@@ -0,0 +1,16 @@
.class public Lothers/A;
.super Ljava/lang/Object;
# instance fields
.field public A00:I
# direct methods
.method public constructor <init>(Ljava/lang/String;)V
.registers 3
.prologue
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
@@ -0,0 +1,25 @@
.class public Lothers/B;
.super Lothers/A;
.field public A00:Lothers/C;
# direct methods
.method public constructor <init>(Ljava/lang/String;)V
.registers 3
.prologue
invoke-direct {p0, p1}, Lothers/A;-><init>(Ljava/lang/String;)V
return-void
.end method
.method public add(I)I
.registers 3
iget v1, p0, Lothers/A;->A00:I
add-int/2addr v1, p1
return v1
.end method
@@ -0,0 +1,12 @@
.class public Lothers/C;
.super Ljava/lang/Object;
.method public constructor <init>(Ljava/lang/String;)V
.registers 3
.prologue
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method