core: add jadx visitors annotation for describe dependencies
This commit is contained in:
@@ -22,6 +22,11 @@ import jadx.core.utils.exceptions.JadxException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@JadxVisitor(
|
||||
name = "ClassModifier",
|
||||
desc = "Remove synthetic classes, methods and fields",
|
||||
runAfter = ModVisitor.class
|
||||
)
|
||||
public class ClassModifier extends AbstractVisitor {
|
||||
|
||||
@Override
|
||||
@@ -129,6 +134,7 @@ public class ClassModifier extends AbstractVisitor {
|
||||
if (af.isBridge() && af.isSynthetic() && !isMethodUniq(cls, mth)) {
|
||||
// TODO add more checks before method deletion
|
||||
mth.add(AFlag.DONT_GENERATE);
|
||||
continue;
|
||||
}
|
||||
// remove synthetic constructor for inner non-static classes
|
||||
if (af.isSynthetic() && af.isConstructor() && mth.getBasicBlocks().size() == 2) {
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package jadx.core.dex.visitors;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation for describe dependencies of jadx visitors
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface JadxVisitor {
|
||||
/**
|
||||
* Visitor short name (identifier)
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* Detailed visitor description
|
||||
*/
|
||||
String desc() default "";
|
||||
|
||||
/**
|
||||
* This visitor must be run <b>after</b> listed visitors
|
||||
*/
|
||||
Class<? extends IDexTreeVisitor>[] runAfter() default {};
|
||||
|
||||
/**
|
||||
* This visitor must be run <b>before</b> listed visitors
|
||||
*/
|
||||
Class<? extends IDexTreeVisitor>[] runBefore() default {};
|
||||
}
|
||||
@@ -29,7 +29,13 @@ import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@JadxVisitor(
|
||||
name = "ReSugarCode",
|
||||
desc = "Simplify synthetic or verbose code",
|
||||
runAfter = CodeShrinker.class
|
||||
)
|
||||
public class ReSugarCode extends AbstractVisitor {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ReSugarCode.class);
|
||||
|
||||
@Override
|
||||
|
||||
@@ -12,6 +12,8 @@ import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.visitors.AbstractVisitor;
|
||||
import jadx.core.dex.visitors.JadxVisitor;
|
||||
import jadx.core.dex.visitors.blocksmaker.BlockFinish;
|
||||
import jadx.core.utils.InsnList;
|
||||
import jadx.core.utils.InstructionRemover;
|
||||
import jadx.core.utils.exceptions.JadxException;
|
||||
@@ -25,6 +27,11 @@ import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@JadxVisitor(
|
||||
name = "SSATransform",
|
||||
desc = "Calculate Single Side Assign (SSA) variables",
|
||||
runAfter = BlockFinish.class
|
||||
)
|
||||
public class SSATransform extends AbstractVisitor {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package jadx.tests.functional;
|
||||
|
||||
import jadx.api.DefaultJadxArgs;
|
||||
import jadx.core.Jadx;
|
||||
import jadx.core.dex.visitors.IDexTreeVisitor;
|
||||
import jadx.core.dex.visitors.JadxVisitor;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class JadxVisitorsOrderTest {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JadxVisitorsOrderTest.class);
|
||||
|
||||
@Test
|
||||
public void testOrder() {
|
||||
List<IDexTreeVisitor> passes = Jadx.getPassesList(new DefaultJadxArgs(), new File("out"));
|
||||
|
||||
List<String> errors = check(passes);
|
||||
for (String str : errors) {
|
||||
LOG.error(str);
|
||||
}
|
||||
assertThat(errors, empty());
|
||||
}
|
||||
|
||||
private static List<String> check(List<IDexTreeVisitor> passes) {
|
||||
List<Class> classList = new ArrayList<Class>(passes.size());
|
||||
for (IDexTreeVisitor pass : passes) {
|
||||
classList.add(pass.getClass());
|
||||
}
|
||||
List<String> errors = new ArrayList<String>();
|
||||
|
||||
Set<String> names = new HashSet<String>();
|
||||
for (int i = 0; i < passes.size(); i++) {
|
||||
IDexTreeVisitor pass = passes.get(i);
|
||||
JadxVisitor info = pass.getClass().getAnnotation(JadxVisitor.class);
|
||||
if (info == null) {
|
||||
LOG.warn("No JadxVisitor annotation for visitor: {}", pass.getClass().getName());
|
||||
continue;
|
||||
}
|
||||
String passName = pass.getClass().getSimpleName();
|
||||
if (!names.add(passName)) {
|
||||
errors.add("Visitor name conflict: " + passName + ", class: " + pass.getClass().getName());
|
||||
}
|
||||
for (Class<? extends IDexTreeVisitor> cls : info.runBefore()) {
|
||||
if (classList.indexOf(cls) < i) {
|
||||
errors.add("Pass " + passName + " must be before " + cls.getSimpleName());
|
||||
}
|
||||
}
|
||||
for (Class<? extends IDexTreeVisitor> cls : info.runAfter()) {
|
||||
if (classList.indexOf(cls) > i) {
|
||||
errors.add("Pass " + passName + " must be after " + cls.getSimpleName());
|
||||
}
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user