Replace virtual includes generated paths with their actual paths in the coverage reports. Fixes #6254. RELNOTES: The code coverage report now includes the actual paths to header files instead of the ugly, Bazel generated, virtual includes path. For example, the `SF:` (source file) lines in the coverage report now look like this: ``` SF:include/common/strategy.h ``` instead of ``` SF:bazel-out/k8-fastbuild/bin/include/common/_virtual_includes/strategy/strategy.h ``` Closes #6372. PiperOrigin-RevId: 219112911
diff --git a/tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator/BUILD b/tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator/BUILD index 9f80e95..2e93c25 100644 --- a/tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator/BUILD +++ b/tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator/BUILD
@@ -104,6 +104,7 @@ deps = [ ":Constants", ":SourceFileCoverage", + "//third_party:guava", ], )
diff --git a/tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator/Coverage.java b/tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator/Coverage.java index 196723c..25c1851 100644 --- a/tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator/Coverage.java +++ b/tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator/Coverage.java
@@ -16,6 +16,8 @@ import static com.google.devtools.coverageoutputgenerator.Constants.CC_EXTENSIONS; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; import java.util.Collection; import java.util.List; import java.util.Set; @@ -86,6 +88,23 @@ return false; } + /** + * Replaces the source file names in the current coverage with their mapping in the given map, if + * it exists. + */ + void maybeReplaceSourceFileNames(ImmutableMap<String, String> reportedToOriginalSources) { + Preconditions.checkNotNull(reportedToOriginalSources); + if (reportedToOriginalSources.isEmpty()) { + // nothing to replace + return; + } + for (SourceFileCoverage source : this.getAllSourceFiles()) { + if (reportedToOriginalSources.containsKey(source.sourceFileName())) { + source.changeSourcefileName(reportedToOriginalSources.get(source.sourceFileName())); + } + } + } + static Coverage filterOutMatchingSources(Coverage coverage, List<String> regexes) throws IllegalArgumentException { if (coverage == null || regexes == null) {
diff --git a/tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator/LcovMergerFlags.java b/tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator/LcovMergerFlags.java index cbf3329..798b737 100644 --- a/tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator/LcovMergerFlags.java +++ b/tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator/LcovMergerFlags.java
@@ -42,6 +42,9 @@ @Nullable abstract String sourceFileManifest(); + @Nullable + abstract String sourcesToReplaceFile(); + /** Parse flags in the form of "--coverage_dir=... -output_file=..." */ static LcovMergerFlags parseFlags(String[] args) { ImmutableList.Builder<String> filterSources = new ImmutableList.Builder<>(); @@ -49,6 +52,7 @@ String reportsFile = null; String outputFile = null; String sourceFileManifest = null; + String sourcesToReplaceFile = null; for (String arg : args) { if (!arg.startsWith("--")) { @@ -74,6 +78,9 @@ case "source_file_manifest": sourceFileManifest = parts[1]; break; + case "sources_to_replace_file": + sourcesToReplaceFile = parts[1]; + break; default: throw new IllegalArgumentException("Unknown flag " + arg); } @@ -91,7 +98,12 @@ throw new IllegalArgumentException("--output_file was not specified."); } return new AutoValue_LcovMergerFlags( - coverageDir, reportsFile, outputFile, filterSources.build(), sourceFileManifest); + coverageDir, + reportsFile, + outputFile, + filterSources.build(), + sourceFileManifest, + sourcesToReplaceFile); } boolean hasSourceFileManifest() {
diff --git a/tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator/Main.java b/tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator/Main.java index e49e39f..1d215c1 100644 --- a/tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator/Main.java +++ b/tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator/Main.java
@@ -21,6 +21,7 @@ import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableMap; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -64,6 +65,10 @@ parseFiles(getTracefiles(flags, filesInCoverageDir), LcovParser::parse), parseFiles(getGcovInfoFiles(filesInCoverageDir), GcovParser::parse)); + if (flags.sourcesToReplaceFile() != null) { + coverage.maybeReplaceSourceFileNames(getMapFromFile(flags.sourcesToReplaceFile())); + } + File profdataFile = getProfdataFileOrNull(filesInCoverageDir); if (coverage.isEmpty()) { int exitStatus = 0; @@ -215,6 +220,32 @@ return lcovTracefiles; } + /** + * Reads the content of the given file and returns a matching map. + * + * <p>It assumes the file contains lines in the form key:value. For each line it creates an entry + * in the map with the corresponding key and value. + */ + private static ImmutableMap<String, String> getMapFromFile(String file) { + ImmutableMap.Builder<String, String> mapBuilder = ImmutableMap.builder(); + + try (FileInputStream inputStream = new FileInputStream(file); + InputStreamReader inputStreamReader = new InputStreamReader(inputStream, UTF_8); + BufferedReader reader = new BufferedReader(inputStreamReader)) { + for (String keyToValueLine = reader.readLine(); + keyToValueLine != null; + keyToValueLine = reader.readLine()) { + String[] keyAndValue = keyToValueLine.split(":"); + if (keyAndValue.length == 2) { + mapBuilder.put(keyAndValue[0], keyAndValue[1]); + } + } + } catch (IOException e) { + logger.log(Level.SEVERE, "Error reading file " + file + ": " + e.getMessage()); + } + return mapBuilder.build(); + } + private static Coverage parseFiles(List<File> files, Parser parser) { Coverage coverage = new Coverage(); for (File file : files) {
diff --git a/tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator/SourceFileCoverage.java b/tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator/SourceFileCoverage.java index d7c5f47..a1a0275 100644 --- a/tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator/SourceFileCoverage.java +++ b/tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator/SourceFileCoverage.java
@@ -28,7 +28,7 @@ */ class SourceFileCoverage { - private final String sourceFileName; + private String sourceFileName; private final TreeMap<String, Integer> lineNumbers; // function name to line numbers private final TreeMap<String, Integer> functionsExecution; // function name to execution count private final TreeMap<Integer, BranchCoverage> branches; // line number to branch @@ -56,6 +56,10 @@ this.lines.putAll(other.lines); } + void changeSourcefileName(String newSourcefileName) { + this.sourceFileName = newSourcefileName; + } + /* * Returns the merged functions found in the two given {@code SourceFileCoverage}s. */
diff --git a/tools/test/collect_coverage.sh b/tools/test/collect_coverage.sh index bcdf8fd..a31e083 100755 --- a/tools/test/collect_coverage.sh +++ b/tools/test/collect_coverage.sh
@@ -103,6 +103,7 @@ eval "${CC_CODE_COVERAGE_SCRIPT}" fi + # Export the command line that invokes LcovMerger with the flags: # --coverage_dir The absolute path of the directory where the # intermediate coverage reports are located. @@ -124,7 +125,7 @@ # keep only the C++ sources found in the manifest. # For other languages the sources in the manifest are # ignored. -export LCOV_MERGER_CMD="${LCOV_MERGER} --coverage_dir=${COVERAGE_DIR} \ +LCOV_MERGER_CMD="${LCOV_MERGER} --coverage_dir=${COVERAGE_DIR} \ --output_file=${COVERAGE_OUTPUT_FILE} \ --filter_sources=/usr/bin/.+ \ --filter_sources=/usr/lib/.+ \ @@ -132,6 +133,10 @@ --filter_sources=.*external/.+ \ --source_file_manifest=${COVERAGE_MANIFEST}" +if [[ $COVERAGE_REPORTED_TO_ACTUAL_SOURCES_FILE ]]; then + LCOV_MERGER_CMD="$LCOV_MERGER_CMD\ + --sources_to_replace_file=$ROOT/$COVERAGE_REPORTED_TO_ACTUAL_SOURCES_FILE" +fi if [[ $DISPLAY_LCOV_CMD ]] ; then echo "Running lcov_merger"