package jadx.tests.functional;
import jadx.api.JadxArgs;
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 JadxArgs(), 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;
}
}