From 8736593a1498bab4964f307595744f463cad22d3 Mon Sep 17 00:00:00 2001 From: Steffeeen Date: Fri, 8 May 2026 14:47:20 +0200 Subject: [PATCH] Allow filtering instrumented classes in JacocoInstrumentationProcessor The filtering mechanism is the same as used by JaCoCo. All classes that are specified in include are instrumented except if they are in exclude. The matching engine allows using `?` to match any single character and `*` to match any number of any character. These are the same wildcards as supported by JaCoCo. --- .../JacocoInstrumentationProcessor.java | 19 +++++++++++++++++-- .../lib/rules/java/JavaCompilationHelper.java | 12 ++++++++++++ .../rules/java/JavaCompileActionBuilder.java | 16 ++++++++++++++++ .../lib/rules/java/JavaStarlarkCommon.java | 8 +++++++- .../starlarkbuildapi/java/JavaCommonApi.java | 6 +++++- 5 files changed, 57 insertions(+), 4 deletions(-) diff --git a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/instrumentation/JacocoInstrumentationProcessor.java b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/instrumentation/JacocoInstrumentationProcessor.java index 97ff75512e75d6..301b62ac992592 100644 --- a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/instrumentation/JacocoInstrumentationProcessor.java +++ b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/instrumentation/JacocoInstrumentationProcessor.java @@ -34,6 +34,7 @@ import java.util.List; import org.jacoco.core.instr.Instrumenter; import org.jacoco.core.runtime.OfflineInstrumentationAccessGenerator; +import org.jacoco.core.runtime.WildcardMatcher; /** Instruments compiled java classes using Jacoco instrumentation library. */ public final class JacocoInstrumentationProcessor { @@ -48,14 +49,22 @@ public static JacocoInstrumentationProcessor create(List args) + ": pathsForCoverageFile"); } - return new JacocoInstrumentationProcessor(args.getFirst()); + String coverageIncludes = args.size() >= 2 ? args.get(1) : ""; + String coverageExcludes = args.size() >= 3 ? args.get(2) : ""; + + return new JacocoInstrumentationProcessor(args.getFirst(), coverageIncludes, coverageExcludes); } private Path instrumentedClassesDirectory; private final String coverageInformation; + private final WildcardMatcher includeMatcher; + private final WildcardMatcher excludeMatcher; - private JacocoInstrumentationProcessor(String coverageInfo) { + private JacocoInstrumentationProcessor(String coverageInfo, String coverageIncludes, + String coverageExcludes) { this.coverageInformation = coverageInfo; + this.includeMatcher = new WildcardMatcher(coverageIncludes.isBlank() ? "*" : coverageIncludes); + this.excludeMatcher = new WildcardMatcher(coverageExcludes); } /** @@ -110,6 +119,12 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) // it only once during recursive directory traversal while also mutating the directory. Path instrumentedCopy = file; Path absoluteUninstrumentedCopy = Path.of(file + ".uninstrumented"); + Path relativeClassFile = root.relativize(file); + String className = relativeClassFile.toString().replace(".class", ""); + if (!includeMatcher.matches(className) || excludeMatcher.matches(className)) { + return FileVisitResult.CONTINUE; + } + Path uninstrumentedCopy = instrumentedClassesDirectory.resolve(root.relativize(absoluteUninstrumentedCopy)); Files.createDirectories(uninstrumentedCopy.getParent()); diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java index 6ab3027d946006..7de04ba284b460 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java @@ -74,6 +74,8 @@ public final class JavaCompilationHelper { private boolean enableJspecify = true; private boolean enableDirectClasspath = true; private final String execGroup; + private ImmutableList coverageIncludes; + private ImmutableList coverageExcludes; public JavaCompilationHelper( RuleContext ruleContext, @@ -104,6 +106,14 @@ public void enableJspecify(boolean enableJspecify) { this.enableJspecify = enableJspecify; } + public void setCoverageIncludes(ImmutableList coverageIncludes) { + this.coverageIncludes = coverageIncludes; + } + + public void setCoverageExcludes(ImmutableList coverageExcludes) { + this.coverageExcludes = coverageExcludes; + } + JavaTargetAttributes getAttributes() { if (builtAttributes == null) { builtAttributes = attributes.build(); @@ -247,6 +257,8 @@ && getJavaConfiguration().experimentalEnableJspecify() builder.setTargetLabel(label); Artifact coverageArtifact = maybeCreateCoverageArtifact(outputs.output()); builder.setCoverageArtifact(coverageArtifact); + builder.setCoverageIncludes(coverageIncludes); + builder.setCoverageExcludes(coverageExcludes); BootClassPathInfo bootClassPathInfo = getBootclasspathOrDefault(); builder.setBootClassPath(bootClassPathInfo); NestedSet classpath = diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileActionBuilder.java index 5b0d37636ee5be..753d79565cce54 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileActionBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileActionBuilder.java @@ -137,6 +137,8 @@ public void extend(ExtraActionInfo.Builder builder, ImmutableList argume private final String execGroup; private ImmutableSet additionalOutputs = ImmutableSet.of(); private Artifact coverageArtifact; + private ImmutableList coverageIncludes; + private ImmutableList coverageExcludes; private ImmutableSet sourceFiles = ImmutableSet.of(); private ImmutableList sourceJars = ImmutableList.of(); private StrictDepsMode strictJavaDeps = StrictDepsMode.ERROR; @@ -326,6 +328,8 @@ private CustomCommandLine buildParamFileContents(ImmutableList javacOpts if (coverageArtifact != null) { result.add("--post_processor"); result.addExecPath(JACOCO_INSTRUMENTATION_PROCESSOR, coverageArtifact); + result.addDynamicString(String.join(":", coverageIncludes)); + result.addDynamicString(String.join(":", coverageExcludes)); } return result.build(); } @@ -455,6 +459,18 @@ public JavaCompileActionBuilder setCoverageArtifact(Artifact coverageArtifact) { return this; } + @CanIgnoreReturnValue + public JavaCompileActionBuilder setCoverageIncludes(ImmutableList coverageIncludes) { + this.coverageIncludes = coverageIncludes; + return this; + } + + @CanIgnoreReturnValue + public JavaCompileActionBuilder setCoverageExcludes(ImmutableList coverageExcludes) { + this.coverageExcludes = coverageExcludes; + return this; + } + @CanIgnoreReturnValue public JavaCompileActionBuilder setTargetLabel(Label targetLabel) { this.targetLabel = targetLabel; diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaStarlarkCommon.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaStarlarkCommon.java index 18b18494682ec7..7f1e8fc3bb4942 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaStarlarkCommon.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaStarlarkCommon.java @@ -201,7 +201,9 @@ public void createCompilationAction( boolean enableJSpecify, boolean enableDirectClasspath, Sequence additionalInputs, - Sequence additionalOutputs) + Sequence additionalOutputs, + Sequence coverageIncludes, + Sequence coverageExcludes) throws EvalException, TypeException, RuleErrorException, @@ -261,6 +263,10 @@ public void createCompilationAction( Depset.cast(javaBuilderJvmFlags, String.class, "javabuilder_jvm_flags")); compilationHelper.enableJspecify(enableJSpecify); compilationHelper.enableDirectClasspath(enableDirectClasspath); + compilationHelper.setCoverageIncludes( + Sequence.cast(coverageIncludes, String.class, "coverage_includes").getImmutableList()); + compilationHelper.setCoverageExcludes( + Sequence.cast(coverageExcludes, String.class, "coverage_excludes").getImmutableList()); compilationHelper.createCompileAction(outputs); } diff --git a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaCommonApi.java b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaCommonApi.java index 8867bf9b446f0e..9adee6047adc3e 100644 --- a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaCommonApi.java +++ b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaCommonApi.java @@ -524,6 +524,8 @@ void createHeaderCompilationAction( @Param(name = "enable_direct_classpath", defaultValue = "True", named = true), @Param(name = "additional_inputs", defaultValue = "[]", named = true), @Param(name = "additional_outputs", defaultValue = "[]", named = true), + @Param(name = "coverage_includes", defaultValue = "[]", named = true), + @Param(name = "coverage_excludes", defaultValue = "[]", named = true) }) void createCompilationAction( StarlarkRuleContextT ctx, @@ -553,7 +555,9 @@ void createCompilationAction( boolean enableJSpecify, boolean enableDirectClasspath, Sequence additionalInputs, - Sequence additionalOutputs) + Sequence additionalOutputs, + Sequence coverageIncludes, + Sequence coverageExcludes) throws EvalException, TypeException, RuleErrorException,