refactor: additional checks for ssa vars and registers

This commit is contained in:
Skylot
2019-11-24 20:33:55 +03:00
parent e4e6f37949
commit 87504dd2cc
38 changed files with 703 additions and 284 deletions
@@ -37,6 +37,7 @@ import jadx.core.dex.attributes.IAttributeNode;
import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.nodes.RootNode;
import jadx.core.utils.DebugChecks;
import jadx.core.utils.files.FileUtils;
import jadx.core.xmlgen.ResourceStorage;
import jadx.core.xmlgen.entry.ResourceEntry;
@@ -96,6 +97,9 @@ public abstract class IntegrationTest extends TestUtils {
AType.JADX_ERROR,
AType.JADX_WARN,
AType.COMMENTS));
// enable debug checks
DebugChecks.checksEnabled = true;
}
@BeforeEach
@@ -0,0 +1,17 @@
package jadx.tests.api.utils.assertj;
import org.assertj.core.api.Assertions;
import jadx.api.ICodeInfo;
import jadx.core.dex.nodes.ClassNode;
public class JadxAssertions extends Assertions {
public static JadxClassNodeAssertions assertThat(ClassNode actual) {
return new JadxClassNodeAssertions(actual);
}
public static JadxCodeAssertions assertThat(ICodeInfo actual) {
return new JadxCodeAssertions(actual.getCodeStr());
}
}
@@ -0,0 +1,21 @@
package jadx.tests.api.utils.assertj;
import org.assertj.core.api.AbstractAssert;
import jadx.api.ICodeInfo;
import jadx.core.dex.nodes.ClassNode;
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
public class JadxClassNodeAssertions extends AbstractAssert<JadxClassNodeAssertions, ClassNode> {
public JadxClassNodeAssertions(ClassNode cls) {
super(cls, JadxClassNodeAssertions.class);
}
public JadxCodeAssertions code() {
isNotNull();
ICodeInfo code = actual.getCode();
assertThat(code).isNotNull();
return new JadxCodeAssertions(code.getCodeStr());
}
}
@@ -0,0 +1,54 @@
package jadx.tests.api.utils.assertj;
import org.assertj.core.api.AbstractStringAssert;
import jadx.core.codegen.CodeWriter;
import jadx.tests.api.utils.TestUtils;
public class JadxCodeAssertions extends AbstractStringAssert<JadxCodeAssertions> {
public JadxCodeAssertions(String code) {
super(code, JadxCodeAssertions.class);
}
public JadxCodeAssertions countString(int count, String substring) {
isNotNull();
int actualCount = TestUtils.count(actual, substring);
if (actualCount != count) {
failWithMessage("Expected a substring <%s> count <%d> but was <%d>", substring, count, actualCount);
}
return this;
}
public JadxCodeAssertions notContainsLine(int indent, String line) {
return countLine(0, indent, line);
}
public JadxCodeAssertions containsLine(int indent, String line) {
return countLine(1, indent, line);
}
private JadxCodeAssertions countLine(int count, int indent, String line) {
String indentStr = TestUtils.indent(indent);
return countString(count, indentStr + line);
}
public JadxCodeAssertions containsLines(String... lines) {
return containsLines(0, lines);
}
public JadxCodeAssertions containsLines(int commonIndent, String... lines) {
if (lines.length == 1) {
return containsLine(commonIndent, lines[0]);
}
String indent = TestUtils.indent(commonIndent);
StringBuilder sb = new StringBuilder();
for (String line : lines) {
if (!line.isEmpty()) {
sb.append(indent);
sb.append(line);
}
sb.append(CodeWriter.NL);
}
return countString(1, sb.toString());
}
}
@@ -0,0 +1,52 @@
package jadx.tests.integration.inner;
import org.junit.jupiter.api.Test;
import jadx.NotYetImplemented;
import jadx.tests.api.IntegrationTest;
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
public class TestAnonymousClass3a extends IntegrationTest {
public static class TestCls {
public static class Inner {
private int f;
private int r;
public void test() {
new Runnable() {
@Override
public void run() {
int a = --Inner.this.f;
p(a);
}
public void p(int a) {
Inner.this.r = a;
}
}.run();
}
}
public void check() {
Inner inner = new Inner();
inner.f = 2;
inner.test();
assertThat(inner.f).isEqualTo(1);
assertThat(inner.r).isEqualTo(1);
}
}
@Test
@NotYetImplemented
public void test() {
assertThat(getClassNode(TestCls.class))
.code()
.doesNotContain("synthetic")
.doesNotContain("AnonymousClass_")
.doesNotContain("unused = ")
.containsLine(4, "public void run() {")
.containsLine(3, "}.run();");
}
}
@@ -6,6 +6,7 @@ import java.util.Map;
import org.junit.jupiter.api.Test;
import jadx.NotYetImplemented;
import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.IntegrationTest;
@@ -72,6 +73,7 @@ public class TestAnonymousClass5 extends IntegrationTest {
}
@Test
@NotYetImplemented
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
@@ -5,16 +5,13 @@ import java.util.List;
import org.junit.jupiter.api.Test;
import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.IntegrationTest;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
public class TestVariablesUsageWithLoops extends IntegrationTest {
public static class TestEnhancedFor {
public void test() {
List<Object> list;
synchronized (this) {
@@ -28,14 +25,13 @@ public class TestVariablesUsageWithLoops extends IntegrationTest {
@Test
public void testEnhancedFor() {
ClassNode cls = getClassNode(TestEnhancedFor.class);
String code = cls.getCode().toString();
assertThat(code, containsString(" list = new ArrayList<>"));
assertThat(getClassNode(TestEnhancedFor.class))
.code()
.containsLine(2, "synchronized (this) {")
.containsLine(3, "list = new ArrayList<>");
}
public static class TestForLoop {
@SuppressWarnings("rawtypes")
public void test() {
List<Object> list;
@@ -50,9 +46,9 @@ public class TestVariablesUsageWithLoops extends IntegrationTest {
@Test
public void testForLoop() {
ClassNode cls = getClassNode(TestForLoop.class);
String code = cls.getCode().toString();
assertThat(code, containsString(" list = new ArrayList<>"));
assertThat(getClassNode(TestEnhancedFor.class))
.code()
.containsLine(2, "synchronized (this) {")
.containsLine(3, "list = new ArrayList<>");
}
}