From 9726809e37f89fdd7b14c3bbd15043a6046f5a98 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sun, 10 Mar 2024 18:11:05 +0900 Subject: [PATCH] Add unstable --dep-coverage option --- README.md | 13 +++--- docs/cargo-llvm-cov-report.txt | 13 +++--- docs/cargo-llvm-cov-run.txt | 13 +++--- docs/cargo-llvm-cov-test.txt | 13 +++--- docs/cargo-llvm-cov.txt | 13 +++--- src/cli.rs | 5 +++ src/context.rs | 3 ++ src/json.rs | 10 ++--- src/main.rs | 82 ++++++++++++++++++++++------------ 9 files changed, 106 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index d37f1271..e2bf9bfb 100644 --- a/README.md +++ b/README.md @@ -115,11 +115,6 @@ OPTIONS: This flag can only be used together with --json, --lcov, or --cobertura. - --skip-functions - Skip exporting per-function coverage data. - - This flag can only be used together with --json, --lcov, or --cobertura. - --output-path Specify a file to write coverage data into. @@ -178,6 +173,14 @@ OPTIONS: --include-build-script Include build script in coverage report + --dep-coverage + Show coverage of th specified dependency instead of the crates in the current workspace. (unstable) + + --skip-functions + Skip exporting per-function coverage data. + + This flag can only be used together with --json, --lcov, or --cobertura. + --doctests Including doc tests (unstable) diff --git a/docs/cargo-llvm-cov-report.txt b/docs/cargo-llvm-cov-report.txt index 97ecbe12..7098a605 100644 --- a/docs/cargo-llvm-cov-report.txt +++ b/docs/cargo-llvm-cov-report.txt @@ -65,11 +65,6 @@ OPTIONS: This flag can only be used together with --json, --lcov, or --cobertura. - --skip-functions - Skip exporting per-function coverage data. - - This flag can only be used together with --json, --lcov, or --cobertura. - --output-path Specify a file to write coverage data into. @@ -115,6 +110,14 @@ OPTIONS: --include-build-script Include build script in coverage report + --dep-coverage + Show coverage of th specified dependency instead of the crates in the current workspace. (unstable) + + --skip-functions + Skip exporting per-function coverage data. + + This flag can only be used together with --json, --lcov, or --cobertura. + --doctests Including doc tests (unstable) diff --git a/docs/cargo-llvm-cov-run.txt b/docs/cargo-llvm-cov-run.txt index 01a9c26a..22ef54da 100644 --- a/docs/cargo-llvm-cov-run.txt +++ b/docs/cargo-llvm-cov-run.txt @@ -69,11 +69,6 @@ OPTIONS: This flag can only be used together with --json, --lcov, or --cobertura. - --skip-functions - Skip exporting per-function coverage data. - - This flag can only be used together with --json, --lcov, or --cobertura. - --output-path Specify a file to write coverage data into. @@ -132,6 +127,14 @@ OPTIONS: --include-build-script Include build script in coverage report + --dep-coverage + Show coverage of th specified dependency instead of the crates in the current workspace. (unstable) + + --skip-functions + Skip exporting per-function coverage data. + + This flag can only be used together with --json, --lcov, or --cobertura. + --ignore-run-fail Run all tests regardless of failure and generate report diff --git a/docs/cargo-llvm-cov-test.txt b/docs/cargo-llvm-cov-test.txt index 050d67c7..ffc32776 100644 --- a/docs/cargo-llvm-cov-test.txt +++ b/docs/cargo-llvm-cov-test.txt @@ -74,11 +74,6 @@ OPTIONS: This flag can only be used together with --json, --lcov, or --cobertura. - --skip-functions - Skip exporting per-function coverage data. - - This flag can only be used together with --json, --lcov, or --cobertura. - --output-path Specify a file to write coverage data into. @@ -137,6 +132,14 @@ OPTIONS: --include-build-script Include build script in coverage report + --dep-coverage + Show coverage of th specified dependency instead of the crates in the current workspace. (unstable) + + --skip-functions + Skip exporting per-function coverage data. + + This flag can only be used together with --json, --lcov, or --cobertura. + --doctests Including doc tests (unstable) diff --git a/docs/cargo-llvm-cov.txt b/docs/cargo-llvm-cov.txt index 2975d2ac..4436de4d 100644 --- a/docs/cargo-llvm-cov.txt +++ b/docs/cargo-llvm-cov.txt @@ -69,11 +69,6 @@ OPTIONS: This flag can only be used together with --json, --lcov, or --cobertura. - --skip-functions - Skip exporting per-function coverage data. - - This flag can only be used together with --json, --lcov, or --cobertura. - --output-path Specify a file to write coverage data into. @@ -132,6 +127,14 @@ OPTIONS: --include-build-script Include build script in coverage report + --dep-coverage + Show coverage of th specified dependency instead of the crates in the current workspace. (unstable) + + --skip-functions + Skip exporting per-function coverage data. + + This flag can only be used together with --json, --lcov, or --cobertura. + --doctests Including doc tests (unstable) diff --git a/src/cli.rs b/src/cli.rs index bf786206..8fc7e7c6 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -236,6 +236,7 @@ impl Args { let mut fail_uncovered_functions = None; let mut show_missing_lines = false; let mut include_build_script = false; + let mut dep_coverage = None; let mut skip_functions = false; // build options @@ -420,6 +421,7 @@ impl Args { Long("fail-uncovered-functions") => parse_opt!(fail_uncovered_functions), Long("show-missing-lines") => parse_flag!(show_missing_lines), Long("include-build-script") => parse_flag!(include_build_script), + Long("dep-coverage") => parse_opt!(dep_coverage), // show-env options Long("export-prefix") => parse_flag!(export_prefix), @@ -882,6 +884,7 @@ impl Args { fail_uncovered_functions, show_missing_lines, include_build_script, + dep_coverage, skip_functions, }, show_env: ShowEnvOptions { export_prefix }, @@ -1117,6 +1120,8 @@ pub(crate) struct LlvmCovOptions { pub(crate) show_missing_lines: bool, /// Include build script in coverage report. pub(crate) include_build_script: bool, + /// Show coverage of th specified dependency instead of the crates in the current workspace. (unstable) + pub(crate) dep_coverage: Option, /// Skip functions in coverage report. pub(crate) skip_functions: bool, } diff --git a/src/context.rs b/src/context.rs index 46ed79f4..519ea95c 100644 --- a/src/context.rs +++ b/src/context.rs @@ -62,6 +62,9 @@ impl Context { if args.cov.disable_default_ignore_filename_regex { warn!("--disable-default-ignore-filename-regex option is unstable"); } + if args.cov.dep_coverage.is_some() { + warn!("--dep-coverage option is unstable"); + } if args.doc { warn!("--doc option is unstable"); } else if args.doctests { diff --git a/src/json.rs b/src/json.rs index 20e1f677..30c3d32a 100644 --- a/src/json.rs +++ b/src/json.rs @@ -16,7 +16,7 @@ use serde_derive::{Deserialize, Serialize}; #[cfg_attr(test, serde(deny_unknown_fields))] pub struct LlvmCovJsonExport { /// List of one or more export objects - data: Vec, + pub data: Vec, // llvm.coverage.json.export #[serde(rename = "type")] type_: String, @@ -319,9 +319,9 @@ impl LlvmCovJsonExport { /// Json representation of one `CoverageMapping` #[derive(Debug, Serialize, Deserialize)] #[cfg_attr(test, serde(deny_unknown_fields))] -struct Export { +pub struct Export { /// List of objects describing coverage for files - files: Vec, + pub files: Vec, /// List of objects describing coverage for functions /// /// This is None if report is summary-only. @@ -333,7 +333,7 @@ struct Export { /// Coverage for a single file #[derive(Debug, Serialize, Deserialize)] #[cfg_attr(test, serde(deny_unknown_fields))] -struct File { +pub struct File { /// List of Branches in the file /// /// This is None if report is summary-only. @@ -345,7 +345,7 @@ struct File { /// This is None if report is summary-only. #[serde(skip_serializing_if = "Option::is_none")] expansions: Option>, - filename: String, + pub filename: String, /// List of Segments contained in the file /// /// This is None if report is summary-only. diff --git a/src/main.rs b/src/main.rs index c9540da5..476ee644 100644 --- a/src/main.rs +++ b/src/main.rs @@ -514,7 +514,7 @@ fn generate_report(cx: &Context) -> Result<()> { merge_profraw(cx).context("failed to merge profile data")?; let object_files = object_files(cx).context("failed to collect object files")?; - let ignore_filename_regex = ignore_filename_regex(cx); + let ignore_filename_regex = ignore_filename_regex(cx, &object_files)?; let format = Format::from_args(cx); format .generate_report(cx, &object_files, ignore_filename_regex.as_deref()) @@ -1165,7 +1165,7 @@ impl Format { } } -fn ignore_filename_regex(cx: &Context) -> Option { +fn ignore_filename_regex(cx: &Context, object_files: &[OsString]) -> Result> { // On Windows, we should escape the separator. const SEPARATOR: &str = if cfg!(windows) { "\\\\" } else { "/" }; @@ -1193,41 +1193,65 @@ fn ignore_filename_regex(cx: &Context) -> Option { out.push(ignore_filename); } if !cx.args.cov.disable_default_ignore_filename_regex { - // TODO: Should we use the actual target path instead of using `tests|examples|benches`? - // We may have a directory like tests/support, so maybe we need both? - if cx.args.remap_path_prefix { - out.push(format!( - r"(^|{SEPARATOR})(rustc{SEPARATOR}([0-9a-f]+|[0-9]+\.[0-9]+\.[0-9]+)|tests|examples|benches){SEPARATOR}" - )); + if let Some(dep) = &cx.args.cov.dep_coverage { + let format = Format::Json; + let json = format.get_json(cx, object_files, None).context("failed to get json")?; + let crates_io_re = Regex::new(&format!("{SEPARATOR}registry{SEPARATOR}src{SEPARATOR}index\\.crates\\.io-[0-9a-f]+{SEPARATOR}[0-9A-Za-z-_]+-[0-9]+\\.[0-9]+\\.[0-9]+(-[0-9A-Za-z\\.-]+)?(\\+[0-9A-Za-z\\.-]+)?{SEPARATOR}"))?; + let dep_re = Regex::new(&format!("{SEPARATOR}registry{SEPARATOR}src{SEPARATOR}index\\.crates\\.io-[0-9a-f]+{SEPARATOR}{dep}-[0-9]+\\.[0-9]+\\.[0-9]+(-[0-9A-Za-z\\.-]+)?(\\+[0-9A-Za-z\\.-]+)?{SEPARATOR}"))?; + let mut set = BTreeSet::new(); + for data in &json.data { + for file in &data.files { + // TODO: non-crates-io + if let Some(crates_io) = crates_io_re.find(&file.filename) { + if !dep_re.is_match(crates_io.as_str()) { + set.insert(crates_io.as_str()); + } + } else { + // TODO: dedup + set.insert(&file.filename); + } + } + } + for f in set { + out.push(f); + } } else { - out.push(format!( - r"{SEPARATOR}rustc{SEPARATOR}([0-9a-f]+|[0-9]+\.[0-9]+\.[0-9]+){SEPARATOR}|^{}({SEPARATOR}.*)?{SEPARATOR}(tests|examples|benches){SEPARATOR}", - regex::escape(cx.ws.metadata.workspace_root.as_str()) - )); - } - out.push_abs_path(&cx.ws.target_dir); - if cx.args.remap_path_prefix { - if let Some(path) = env::home_dir() { + // TODO: Should we use the actual target path instead of using `tests|examples|benches`? + // We may have a directory like tests/support, so maybe we need both? + if cx.args.remap_path_prefix { + out.push(format!( + r"(^|{SEPARATOR})(rustc{SEPARATOR}([0-9a-f]+|[0-9]+\.[0-9]+\.[0-9]+)|tests|examples|benches){SEPARATOR}" + )); + } else { + out.push(format!( + r"{SEPARATOR}rustc{SEPARATOR}([0-9a-f]+|[0-9]+\.[0-9]+\.[0-9]+){SEPARATOR}|^{}({SEPARATOR}.*)?{SEPARATOR}(tests|examples|benches){SEPARATOR}", + regex::escape(cx.ws.metadata.workspace_root.as_str()) + )); + } + out.push_abs_path(&cx.ws.target_dir); + if cx.args.remap_path_prefix { + if let Some(path) = env::home_dir() { + out.push_abs_path(path); + } + } + if let Some(path) = env::cargo_home_with_cwd(&cx.current_dir) { + let path = regex::escape(&path.as_os_str().to_string_lossy()); + let path = format!("^{path}{SEPARATOR}(registry|git){SEPARATOR}"); + out.push(path); + } + if let Some(path) = env::rustup_home_with_cwd(&cx.current_dir) { + out.push_abs_path(path.join("toolchains")); + } + for path in resolve_excluded_paths(cx) { out.push_abs_path(path); } } - if let Some(path) = env::cargo_home_with_cwd(&cx.current_dir) { - let path = regex::escape(&path.as_os_str().to_string_lossy()); - let path = format!("^{path}{SEPARATOR}(registry|git){SEPARATOR}"); - out.push(path); - } - if let Some(path) = env::rustup_home_with_cwd(&cx.current_dir) { - out.push_abs_path(path.join("toolchains")); - } - for path in resolve_excluded_paths(cx) { - out.push_abs_path(path); - } } if out.0.is_empty() { - None + Ok(None) } else { - Some(out.0) + Ok(Some(out.0)) } }