diff --git a/build.gradle b/build.gradle index 358719c9f..5d6365ad1 100644 --- a/build.gradle +++ b/build.gradle @@ -38,7 +38,6 @@ allprojects { testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' - testImplementation 'org.eclipse.jdt.core.compiler:ecj:4.6.1' testCompileOnly 'org.jetbrains:annotations:23.0.0' } diff --git a/jadx-core/build.gradle b/jadx-core/build.gradle index 953229a64..de70b0366 100644 --- a/jadx-core/build.gradle +++ b/jadx-core/build.gradle @@ -20,7 +20,8 @@ dependencies { testRuntimeOnly(project(':jadx-plugins:jadx-java-input')) testRuntimeOnly(project(':jadx-plugins:jadx-raung-input')) - testImplementation('tools.profiler:async-profiler:1.8.3') + testImplementation 'org.eclipse.jdt:ecj:3.28.0' + testImplementation 'tools.profiler:async-profiler:1.8.3' } test { diff --git a/jadx-core/src/test/java/jadx/tests/api/IntegrationTest.java b/jadx-core/src/test/java/jadx/tests/api/IntegrationTest.java index bda2c326e..19ca91a34 100644 --- a/jadx-core/src/test/java/jadx/tests/api/IntegrationTest.java +++ b/jadx-core/src/test/java/jadx/tests/api/IntegrationTest.java @@ -65,7 +65,6 @@ import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; public abstract class IntegrationTest extends TestUtils { @@ -436,9 +435,10 @@ public abstract class IntegrationTest extends TestUtils { return; } try { + // TODO: eclipse uses files or compilation units providers added in Java 9 + compilerOptions.setUseEclipseCompiler(false); decompiledCompiler = new TestCompiler(compilerOptions); - boolean result = decompiledCompiler.compileNodes(clsList); - assertTrue(result, "Compilation failed"); + decompiledCompiler.compileNodes(clsList); System.out.println("Compilation: PASSED"); } catch (Exception e) { fail(e); @@ -514,7 +514,8 @@ public abstract class IntegrationTest extends TestUtils { this.compilerOptions.setIncludeDebugInfo(false); } - protected void useEclipseCompiler() { + public void useEclipseCompiler() { + Assumptions.assumeTrue(JavaUtils.checkJavaVersion(11), "eclipse compiler library using Java 11"); this.compilerOptions.setUseEclipseCompiler(true); } diff --git a/jadx-core/src/test/java/jadx/tests/api/compiler/EclipseCompilerUtils.java b/jadx-core/src/test/java/jadx/tests/api/compiler/EclipseCompilerUtils.java new file mode 100644 index 000000000..75f1e667f --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/api/compiler/EclipseCompilerUtils.java @@ -0,0 +1,18 @@ +package jadx.tests.api.compiler; + +import javax.tools.JavaCompiler; + +public class EclipseCompilerUtils { + + public static JavaCompiler newInstance() { + if (!JavaUtils.checkJavaVersion(11)) { + throw new IllegalArgumentException("Eclipse compiler build with Java 11"); + } + try { + Class ecjCls = Class.forName("org.eclipse.jdt.internal.compiler.tool.EclipseCompiler"); + return (JavaCompiler) ecjCls.getConstructor().newInstance(); + } catch (Exception e) { + throw new RuntimeException("Failed to init Eclipse compiler", e); + } + } +} diff --git a/jadx-core/src/test/java/jadx/tests/api/compiler/TestCompiler.java b/jadx-core/src/test/java/jadx/tests/api/compiler/TestCompiler.java index 0b2547607..e480edef9 100644 --- a/jadx-core/src/test/java/jadx/tests/api/compiler/TestCompiler.java +++ b/jadx-core/src/test/java/jadx/tests/api/compiler/TestCompiler.java @@ -3,20 +3,22 @@ package jadx.tests.api.compiler; import java.io.Closeable; import java.io.File; import java.io.IOException; +import java.io.PrintWriter; +import java.io.Writer; import java.lang.reflect.Method; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; +import java.util.Locale; +import javax.tools.DiagnosticListener; import javax.tools.JavaCompiler; import javax.tools.JavaCompiler.CompilationTask; import javax.tools.JavaFileObject; import javax.tools.ToolProvider; -import org.eclipse.jdt.internal.compiler.tool.EclipseCompiler; import org.jetbrains.annotations.NotNull; import jadx.core.dex.nodes.ClassNode; @@ -38,7 +40,7 @@ public class TestCompiler implements Closeable { + "current: " + JavaUtils.JAVA_VERSION_INT + ", required: " + javaVersion); } if (options.isUseEclipseCompiler()) { - compiler = new EclipseCompiler(); + compiler = EclipseCompilerUtils.newInstance(); } else { compiler = ToolProvider.getSystemJavaCompiler(); if (compiler == null) { @@ -49,11 +51,7 @@ public class TestCompiler implements Closeable { } public List compileFiles(List sourceFiles, Path outTmp) throws IOException { - List jfObjects = fileManager.getJavaFileObjectsFromFiles(sourceFiles); - boolean success = compile(jfObjects); - if (!success) { - return Collections.emptyList(); - } + compile(fileManager.getJavaFileObjectsFromFiles(sourceFiles)); List files = new ArrayList<>(); for (JavaClassObject classObject : fileManager.getClassLoader().getClassObjects()) { Path path = outTmp.resolve(classObject.getName().replace('.', '/') + ".class"); @@ -64,15 +62,15 @@ public class TestCompiler implements Closeable { return files; } - public boolean compileNodes(List clsNodeList) { + public void compileNodes(List clsNodeList) { List jfObjects = new ArrayList<>(clsNodeList.size()); for (ClassNode clsNode : clsNodeList) { jfObjects.add(new StringJavaFileObject(clsNode.getFullName(), clsNode.getCode().getCodeStr())); } - return compile(jfObjects); + compile(jfObjects); } - private boolean compile(List jfObjects) { + private void compile(List jfObjects) { List arguments = new ArrayList<>(); arguments.add(options.isIncludeDebugInfo() ? "-g" : "-g:none"); int javaVersion = options.getJavaVersion(); @@ -83,8 +81,13 @@ public class TestCompiler implements Closeable { arguments.add(javaVerStr); arguments.addAll(options.getArguments()); - CompilationTask compilerTask = compiler.getTask(null, fileManager, null, arguments, null, jfObjects); - return Boolean.TRUE.equals(compilerTask.call()); + DiagnosticListener diagnostic = + diagObj -> System.out.println("Compiler diagnostic: " + diagObj.getMessage(Locale.ROOT)); + Writer out = new PrintWriter(System.out); + CompilationTask compilerTask = compiler.getTask(out, fileManager, diagnostic, arguments, null, jfObjects); + if (Boolean.FALSE.equals(compilerTask.call())) { + throw new RuntimeException("Compilation failed"); + } } private ClassLoader getClassLoader() { diff --git a/jadx-core/src/test/java/jadx/tests/api/extensions/profiles/JadxTestProfilesExtension.java b/jadx-core/src/test/java/jadx/tests/api/extensions/profiles/JadxTestProfilesExtension.java index f8389b08f..7af35057a 100644 --- a/jadx-core/src/test/java/jadx/tests/api/extensions/profiles/JadxTestProfilesExtension.java +++ b/jadx-core/src/test/java/jadx/tests/api/extensions/profiles/JadxTestProfilesExtension.java @@ -2,6 +2,7 @@ package jadx.tests.api.extensions.profiles; import java.lang.reflect.Method; import java.util.Collections; +import java.util.EnumSet; import java.util.List; import java.util.stream.Stream; @@ -35,7 +36,13 @@ public class JadxTestProfilesExtension implements TestTemplateInvocationContextP Preconditions.condition(!testAnnAdded, "@Test annotation should be removed"); TestWithProfiles profilesAnn = AnnotationUtils.findAnnotation(testMethod, TestWithProfiles.class).get(); - return Stream.of(profilesAnn.value()) + EnumSet profilesSet = EnumSet.noneOf(TestProfile.class); + Collections.addAll(profilesSet, profilesAnn.value()); + if (profilesSet.contains(TestProfile.ALL)) { + Collections.addAll(profilesSet, TestProfile.values()); + } + profilesSet.remove(TestProfile.ALL); + return profilesSet.stream() .sorted() .map(RunWithProfile::new); } diff --git a/jadx-core/src/test/java/jadx/tests/api/extensions/profiles/TestProfile.java b/jadx-core/src/test/java/jadx/tests/api/extensions/profiles/TestProfile.java index a9f017ad7..fd8ef3328 100644 --- a/jadx-core/src/test/java/jadx/tests/api/extensions/profiles/TestProfile.java +++ b/jadx-core/src/test/java/jadx/tests/api/extensions/profiles/TestProfile.java @@ -20,7 +20,18 @@ public enum TestProfile implements Consumer { JAVA11("java-11", test -> { test.useTargetJavaVersion(11); test.useJavaInput(); - }); + }), + ECJ_DX_J8("ecj-dx-j8", test -> { + test.useEclipseCompiler(); + test.useTargetJavaVersion(8); + test.useDexInput(); + }), + ECJ_J8("ecj-j8", test -> { + test.useEclipseCompiler(); + test.useTargetJavaVersion(8); + test.useJavaInput(); + }), + ALL("all", null); private final String description; private final Consumer setup;