diff --git a/scip-gradle-plugin/src/main/java/org/scip_code/scip_java/gradle/ScipGradlePlugin.java b/scip-gradle-plugin/src/main/java/org/scip_code/scip_java/gradle/ScipGradlePlugin.java index 6d5bac22d..310dc2179 100644 --- a/scip-gradle-plugin/src/main/java/org/scip_code/scip_java/gradle/ScipGradlePlugin.java +++ b/scip-gradle-plugin/src/main/java/org/scip_code/scip_java/gradle/ScipGradlePlugin.java @@ -37,16 +37,8 @@ private void configureProject(Project project) { triggers.add("compileJava"); triggers.add("compileTestJava"); - boolean hasAnnotationPath; - try { - Configuration apConfig = project.getConfigurations().getByName("annotationProcessor"); - hasAnnotationPath = apConfig.isCanBeResolved() && !apConfig.getDependencies().isEmpty(); - } catch (Exception exc) { - hasAnnotationPath = false; - } - Object javacPluginDep = project.files(requiredExtra(extraProperties, "javacPluginJar")); - boolean pluginAdded = tryAddJavacPlugin(project, javacPluginDep, hasAnnotationPath); + boolean pluginAdded = tryAddJavacPlugin(project, javacPluginDep); project .getTasks() @@ -113,14 +105,34 @@ private void configureProject(Project project) { project.getTasks().create("scipPrintDependencies", WriteDependencies.class); } - private static boolean tryAddJavacPlugin( - Project project, Object javacPluginDep, boolean hasAnnotationPath) { + /** + * javac discovers {@code -Xplugin:} plugins from the annotation processor path when {@code + * -processorpath} is set, and only falls back to the classpath when it isn't. Gradle populates + * {@code -processorpath} from the {@code annotationProcessor} (main) and {@code + * testAnnotationProcessor} (test) configurations, so whenever one of them declares a processor we + * must add the SCIP javac plugin to that same configuration or the corresponding compile task + * fails with "plug-in not found: scip". The two configurations are independent (test does not + * extend main), so each is checked separately. + */ + private static boolean hasAnnotationProcessors(Project project, String configurationName) { + try { + Configuration config = project.getConfigurations().getByName(configurationName); + return config.isCanBeResolved() && !config.getDependencies().isEmpty(); + } catch (Exception exc) { + return false; + } + } + + private static boolean tryAddJavacPlugin(Project project, Object javacPluginDep) { try { project.getDependencies().add("compileOnly", javacPluginDep); - if (hasAnnotationPath) { + project.getDependencies().add("testCompileOnly", javacPluginDep); + if (hasAnnotationProcessors(project, "annotationProcessor")) { project.getDependencies().add("annotationProcessor", javacPluginDep); } - project.getDependencies().add("testCompileOnly", javacPluginDep); + if (hasAnnotationProcessors(project, "testAnnotationProcessor")) { + project.getDependencies().add("testAnnotationProcessor", javacPluginDep); + } return true; } catch (Exception exc) { // The `compileOnly` configuration has likely already been resolved by diff --git a/scip-java/src/test/kotlin/tests/GradleBuildToolTest.kt b/scip-java/src/test/kotlin/tests/GradleBuildToolTest.kt index cfda87c34..a1b3b933e 100644 --- a/scip-java/src/test/kotlin/tests/GradleBuildToolTest.kt +++ b/scip-java/src/test/kotlin/tests/GradleBuildToolTest.kt @@ -55,6 +55,19 @@ class GradleBuildToolTest : BuildToolHarness() { expectedScipFiles = 2, ) ) + // Regression test: annotation processors declared only for the test source + // set (testAnnotationProcessor) make Gradle pass -processorpath to + // compileTestJava, so the SCIP javac plugin must be added to that same + // configuration or plugin discovery fails with "plug-in not found: scip". + add( + checkGradleBuild( + "test-annotation-path", + "gradle/test-annotation-path", + // The generated immutable class is compiled alongside the original + // test source, so two SCIP shards are produced. + expectedScipFiles = 2, + ) + ) add( checkGradleBuild("build-with-Werror", "gradle/build-with-Werror", expectedScipFiles = 2) ) diff --git a/scip-java/src/test/resources/fixtures/gradle/test-annotation-path/build.gradle b/scip-java/src/test/resources/fixtures/gradle/test-annotation-path/build.gradle new file mode 100644 index 000000000..0c4e93824 --- /dev/null +++ b/scip-java/src/test/resources/fixtures/gradle/test-annotation-path/build.gradle @@ -0,0 +1,10 @@ +plugins { + id 'java' +} +repositories { + mavenCentral() +} +dependencies { + testCompileOnly 'org.immutables:value:2.9.2' + testAnnotationProcessor 'org.immutables:value:2.9.2' +} diff --git a/scip-java/src/test/resources/fixtures/gradle/test-annotation-path/src/test/java/WorkflowOptions.java b/scip-java/src/test/resources/fixtures/gradle/test-annotation-path/src/test/java/WorkflowOptions.java new file mode 100644 index 000000000..b57925691 --- /dev/null +++ b/scip-java/src/test/resources/fixtures/gradle/test-annotation-path/src/test/java/WorkflowOptions.java @@ -0,0 +1,7 @@ +package test; +import org.immutables.value.Value; +import java.util.Optional; +@Value.Immutable +public abstract class WorkflowOptions { + public abstract Optional getWorkflowIdReusePolicy(); +}