From aa1628c7b7ca46b8b97c0447553f88b3e8ed8de9 Mon Sep 17 00:00:00 2001 From: coverage Date: Fri, 27 Sep 2024 12:58:08 +0000 Subject: [PATCH] Coverage --- coverage/amber.png | Bin 0 -> 141 bytes coverage/cargo-dylint/src/index-sort-f.html | 93 +++ coverage/cargo-dylint/src/index-sort-l.html | 93 +++ coverage/cargo-dylint/src/index.html | 93 +++ .../cargo-dylint/src/main.rs.func-sort-c.html | 248 ++++++ coverage/cargo-dylint/src/main.rs.func.html | 248 ++++++ coverage/cargo-dylint/src/main.rs.gcov.html | 519 ++++++++++++ coverage/driver/src/index-sort-f.html | 93 +++ coverage/driver/src/index-sort-l.html | 93 +++ coverage/driver/src/index.html | 93 +++ coverage/driver/src/lib.rs.func-sort-c.html | 208 +++++ coverage/driver/src/lib.rs.func.html | 208 +++++ coverage/driver/src/lib.rs.gcov.html | 552 +++++++++++++ coverage/dylint-link/src/index-sort-f.html | 93 +++ coverage/dylint-link/src/index-sort-l.html | 93 +++ coverage/dylint-link/src/index.html | 93 +++ .../dylint-link/src/main.rs.func-sort-c.html | 168 ++++ coverage/dylint-link/src/main.rs.func.html | 168 ++++ coverage/dylint-link/src/main.rs.gcov.html | 461 +++++++++++ .../src/driver_builder.rs.func-sort-c.html | 168 ++++ .../dylint/src/driver_builder.rs.func.html | 168 ++++ .../dylint/src/driver_builder.rs.gcov.html | 320 ++++++++ coverage/dylint/src/error.rs.func-sort-c.html | 92 +++ coverage/dylint/src/error.rs.func.html | 92 +++ coverage/dylint/src/error.rs.gcov.html | 142 ++++ coverage/dylint/src/index-sort-f.html | 123 +++ coverage/dylint/src/index-sort-l.html | 123 +++ coverage/dylint/src/index.html | 123 +++ coverage/dylint/src/lib.rs.func-sort-c.html | 192 +++++ coverage/dylint/src/lib.rs.func.html | 192 +++++ coverage/dylint/src/lib.rs.gcov.html | 732 +++++++++++++++++ .../cargo_cli/index-sort-f.html | 93 +++ .../cargo_cli/index-sort-l.html | 93 +++ .../src/library_packages/cargo_cli/index.html | 93 +++ .../cargo_cli/mod.rs.func-sort-c.html | 240 ++++++ .../cargo_cli/mod.rs.func.html | 240 ++++++ .../cargo_cli/mod.rs.gcov.html | 472 +++++++++++ .../util/canonical_url.rs.func-sort-c.html | 84 ++ .../cargo_cli/util/canonical_url.rs.func.html | 84 ++ .../cargo_cli/util/canonical_url.rs.gcov.html | 168 ++++ .../cargo_cli/util/hex.rs.func-sort-c.html | 88 +++ .../cargo_cli/util/hex.rs.func.html | 88 +++ .../cargo_cli/util/hex.rs.gcov.html | 116 +++ .../cargo_cli/util/index-sort-f.html | 103 +++ .../cargo_cli/util/index-sort-l.html | 103 +++ .../cargo_cli/util/index.html | 103 +++ .../src/library_packages/index-sort-f.html | 93 +++ .../src/library_packages/index-sort-l.html | 93 +++ .../dylint/src/library_packages/index.html | 93 +++ .../library_packages/mod.rs.func-sort-c.html | 316 ++++++++ .../src/library_packages/mod.rs.func.html | 316 ++++++++ .../src/library_packages/mod.rs.gcov.html | 566 +++++++++++++ .../src/name_toolchain_map/index-sort-f.html | 103 +++ .../src/name_toolchain_map/index-sort-l.html | 103 +++ .../dylint/src/name_toolchain_map/index.html | 103 +++ .../maybe_library.rs.func-sort-c.html | 96 +++ .../maybe_library.rs.func.html | 96 +++ .../maybe_library.rs.gcov.html | 139 ++++ .../mod.rs.func-sort-c.html | 108 +++ .../src/name_toolchain_map/mod.rs.func.html | 108 +++ .../src/name_toolchain_map/mod.rs.gcov.html | 214 +++++ coverage/dylint/src/opts.rs.func-sort-c.html | 108 +++ coverage/dylint/src/opts.rs.func.html | 108 +++ coverage/dylint/src/opts.rs.gcov.html | 268 +++++++ .../src/package_options/index-sort-f.html | 103 +++ .../src/package_options/index-sort-l.html | 103 +++ .../dylint/src/package_options/index.html | 103 +++ .../package_options/mod.rs.func-sort-c.html | 148 ++++ .../src/package_options/mod.rs.func.html | 148 ++++ .../src/package_options/mod.rs.gcov.html | 250 ++++++ .../package_options/revs.rs.func-sort-c.html | 124 +++ .../src/package_options/revs.rs.func.html | 124 +++ .../src/package_options/revs.rs.gcov.html | 260 ++++++ coverage/emerald.png | Bin 0 -> 141 bytes coverage/gcov.css | 519 ++++++++++++ coverage/glass.png | Bin 0 -> 167 bytes coverage/index-sort-f.html | 203 +++++ coverage/index-sort-l.html | 203 +++++ coverage/index.html | 203 +++++ .../internal/src/cargo.rs.func-sort-c.html | 168 ++++ coverage/internal/src/cargo.rs.func.html | 168 ++++ coverage/internal/src/cargo.rs.gcov.html | 281 +++++++ .../src/clippy_utils.rs.func-sort-c.html | 164 ++++ .../internal/src/clippy_utils.rs.func.html | 164 ++++ .../internal/src/clippy_utils.rs.gcov.html | 182 +++++ .../internal/src/command.rs.func-sort-c.html | 100 +++ coverage/internal/src/command.rs.func.html | 100 +++ coverage/internal/src/command.rs.gcov.html | 163 ++++ .../internal/src/config.rs.func-sort-c.html | 116 +++ coverage/internal/src/config.rs.func.html | 116 +++ coverage/internal/src/config.rs.gcov.html | 181 +++++ coverage/internal/src/env.rs.func-sort-c.html | 88 +++ coverage/internal/src/env.rs.func.html | 88 +++ coverage/internal/src/env.rs.gcov.html | 141 ++++ .../internal/src/examples.rs.func-sort-c.html | 100 +++ coverage/internal/src/examples.rs.func.html | 100 +++ coverage/internal/src/examples.rs.gcov.html | 141 ++++ .../internal/src/filename.rs.func-sort-c.html | 88 +++ coverage/internal/src/filename.rs.func.html | 88 +++ coverage/internal/src/filename.rs.gcov.html | 171 ++++ coverage/internal/src/git.rs.func-sort-c.html | 108 +++ coverage/internal/src/git.rs.func.html | 108 +++ coverage/internal/src/git.rs.gcov.html | 160 ++++ coverage/internal/src/index-sort-f.html | 203 +++++ coverage/internal/src/index-sort-l.html | 203 +++++ coverage/internal/src/index.html | 203 +++++ .../src/packaging.rs.func-sort-c.html | 192 +++++ coverage/internal/src/packaging.rs.func.html | 192 +++++ coverage/internal/src/packaging.rs.gcov.html | 244 ++++++ .../internal/src/rustup.rs.func-sort-c.html | 112 +++ coverage/internal/src/rustup.rs.func.html | 112 +++ coverage/internal/src/rustup.rs.gcov.html | 136 ++++ coverage/internal/src/sed.rs.func-sort-c.html | 96 +++ coverage/internal/src/sed.rs.func.html | 96 +++ coverage/internal/src/sed.rs.gcov.html | 93 +++ .../internal/src/testing.rs.func-sort-c.html | 84 ++ coverage/internal/src/testing.rs.func.html | 84 ++ coverage/internal/src/testing.rs.gcov.html | 89 +++ coverage/ruby.png | Bin 0 -> 141 bytes coverage/snow.png | Bin 0 -> 141 bytes coverage/updown.png | Bin 0 -> 117 bytes coverage/utils/linting/src/index-sort-f.html | 93 +++ coverage/utils/linting/src/index-sort-l.html | 93 +++ coverage/utils/linting/src/index.html | 93 +++ .../utils/linting/src/lib.rs.func-sort-c.html | 124 +++ coverage/utils/linting/src/lib.rs.func.html | 124 +++ coverage/utils/linting/src/lib.rs.gcov.html | 742 ++++++++++++++++++ coverage/utils/testing/src/index-sort-f.html | 103 +++ coverage/utils/testing/src/index-sort-l.html | 103 +++ coverage/utils/testing/src/index.html | 103 +++ .../utils/testing/src/lib.rs.func-sort-c.html | 216 +++++ coverage/utils/testing/src/lib.rs.func.html | 216 +++++ coverage/utils/testing/src/lib.rs.gcov.html | 550 +++++++++++++ .../utils/testing/src/ui.rs.func-sort-c.html | 108 +++ coverage/utils/testing/src/ui.rs.func.html | 108 +++ coverage/utils/testing/src/ui.rs.gcov.html | 198 +++++ 136 files changed, 22171 insertions(+) create mode 100644 coverage/amber.png create mode 100644 coverage/cargo-dylint/src/index-sort-f.html create mode 100644 coverage/cargo-dylint/src/index-sort-l.html create mode 100644 coverage/cargo-dylint/src/index.html create mode 100644 coverage/cargo-dylint/src/main.rs.func-sort-c.html create mode 100644 coverage/cargo-dylint/src/main.rs.func.html create mode 100644 coverage/cargo-dylint/src/main.rs.gcov.html create mode 100644 coverage/driver/src/index-sort-f.html create mode 100644 coverage/driver/src/index-sort-l.html create mode 100644 coverage/driver/src/index.html create mode 100644 coverage/driver/src/lib.rs.func-sort-c.html create mode 100644 coverage/driver/src/lib.rs.func.html create mode 100644 coverage/driver/src/lib.rs.gcov.html create mode 100644 coverage/dylint-link/src/index-sort-f.html create mode 100644 coverage/dylint-link/src/index-sort-l.html create mode 100644 coverage/dylint-link/src/index.html create mode 100644 coverage/dylint-link/src/main.rs.func-sort-c.html create mode 100644 coverage/dylint-link/src/main.rs.func.html create mode 100644 coverage/dylint-link/src/main.rs.gcov.html create mode 100644 coverage/dylint/src/driver_builder.rs.func-sort-c.html create mode 100644 coverage/dylint/src/driver_builder.rs.func.html create mode 100644 coverage/dylint/src/driver_builder.rs.gcov.html create mode 100644 coverage/dylint/src/error.rs.func-sort-c.html create mode 100644 coverage/dylint/src/error.rs.func.html create mode 100644 coverage/dylint/src/error.rs.gcov.html create mode 100644 coverage/dylint/src/index-sort-f.html create mode 100644 coverage/dylint/src/index-sort-l.html create mode 100644 coverage/dylint/src/index.html create mode 100644 coverage/dylint/src/lib.rs.func-sort-c.html create mode 100644 coverage/dylint/src/lib.rs.func.html create mode 100644 coverage/dylint/src/lib.rs.gcov.html create mode 100644 coverage/dylint/src/library_packages/cargo_cli/index-sort-f.html create mode 100644 coverage/dylint/src/library_packages/cargo_cli/index-sort-l.html create mode 100644 coverage/dylint/src/library_packages/cargo_cli/index.html create mode 100644 coverage/dylint/src/library_packages/cargo_cli/mod.rs.func-sort-c.html create mode 100644 coverage/dylint/src/library_packages/cargo_cli/mod.rs.func.html create mode 100644 coverage/dylint/src/library_packages/cargo_cli/mod.rs.gcov.html create mode 100644 coverage/dylint/src/library_packages/cargo_cli/util/canonical_url.rs.func-sort-c.html create mode 100644 coverage/dylint/src/library_packages/cargo_cli/util/canonical_url.rs.func.html create mode 100644 coverage/dylint/src/library_packages/cargo_cli/util/canonical_url.rs.gcov.html create mode 100644 coverage/dylint/src/library_packages/cargo_cli/util/hex.rs.func-sort-c.html create mode 100644 coverage/dylint/src/library_packages/cargo_cli/util/hex.rs.func.html create mode 100644 coverage/dylint/src/library_packages/cargo_cli/util/hex.rs.gcov.html create mode 100644 coverage/dylint/src/library_packages/cargo_cli/util/index-sort-f.html create mode 100644 coverage/dylint/src/library_packages/cargo_cli/util/index-sort-l.html create mode 100644 coverage/dylint/src/library_packages/cargo_cli/util/index.html create mode 100644 coverage/dylint/src/library_packages/index-sort-f.html create mode 100644 coverage/dylint/src/library_packages/index-sort-l.html create mode 100644 coverage/dylint/src/library_packages/index.html create mode 100644 coverage/dylint/src/library_packages/mod.rs.func-sort-c.html create mode 100644 coverage/dylint/src/library_packages/mod.rs.func.html create mode 100644 coverage/dylint/src/library_packages/mod.rs.gcov.html create mode 100644 coverage/dylint/src/name_toolchain_map/index-sort-f.html create mode 100644 coverage/dylint/src/name_toolchain_map/index-sort-l.html create mode 100644 coverage/dylint/src/name_toolchain_map/index.html create mode 100644 coverage/dylint/src/name_toolchain_map/maybe_library.rs.func-sort-c.html create mode 100644 coverage/dylint/src/name_toolchain_map/maybe_library.rs.func.html create mode 100644 coverage/dylint/src/name_toolchain_map/maybe_library.rs.gcov.html create mode 100644 coverage/dylint/src/name_toolchain_map/mod.rs.func-sort-c.html create mode 100644 coverage/dylint/src/name_toolchain_map/mod.rs.func.html create mode 100644 coverage/dylint/src/name_toolchain_map/mod.rs.gcov.html create mode 100644 coverage/dylint/src/opts.rs.func-sort-c.html create mode 100644 coverage/dylint/src/opts.rs.func.html create mode 100644 coverage/dylint/src/opts.rs.gcov.html create mode 100644 coverage/dylint/src/package_options/index-sort-f.html create mode 100644 coverage/dylint/src/package_options/index-sort-l.html create mode 100644 coverage/dylint/src/package_options/index.html create mode 100644 coverage/dylint/src/package_options/mod.rs.func-sort-c.html create mode 100644 coverage/dylint/src/package_options/mod.rs.func.html create mode 100644 coverage/dylint/src/package_options/mod.rs.gcov.html create mode 100644 coverage/dylint/src/package_options/revs.rs.func-sort-c.html create mode 100644 coverage/dylint/src/package_options/revs.rs.func.html create mode 100644 coverage/dylint/src/package_options/revs.rs.gcov.html create mode 100644 coverage/emerald.png create mode 100644 coverage/gcov.css create mode 100644 coverage/glass.png create mode 100644 coverage/index-sort-f.html create mode 100644 coverage/index-sort-l.html create mode 100644 coverage/index.html create mode 100644 coverage/internal/src/cargo.rs.func-sort-c.html create mode 100644 coverage/internal/src/cargo.rs.func.html create mode 100644 coverage/internal/src/cargo.rs.gcov.html create mode 100644 coverage/internal/src/clippy_utils.rs.func-sort-c.html create mode 100644 coverage/internal/src/clippy_utils.rs.func.html create mode 100644 coverage/internal/src/clippy_utils.rs.gcov.html create mode 100644 coverage/internal/src/command.rs.func-sort-c.html create mode 100644 coverage/internal/src/command.rs.func.html create mode 100644 coverage/internal/src/command.rs.gcov.html create mode 100644 coverage/internal/src/config.rs.func-sort-c.html create mode 100644 coverage/internal/src/config.rs.func.html create mode 100644 coverage/internal/src/config.rs.gcov.html create mode 100644 coverage/internal/src/env.rs.func-sort-c.html create mode 100644 coverage/internal/src/env.rs.func.html create mode 100644 coverage/internal/src/env.rs.gcov.html create mode 100644 coverage/internal/src/examples.rs.func-sort-c.html create mode 100644 coverage/internal/src/examples.rs.func.html create mode 100644 coverage/internal/src/examples.rs.gcov.html create mode 100644 coverage/internal/src/filename.rs.func-sort-c.html create mode 100644 coverage/internal/src/filename.rs.func.html create mode 100644 coverage/internal/src/filename.rs.gcov.html create mode 100644 coverage/internal/src/git.rs.func-sort-c.html create mode 100644 coverage/internal/src/git.rs.func.html create mode 100644 coverage/internal/src/git.rs.gcov.html create mode 100644 coverage/internal/src/index-sort-f.html create mode 100644 coverage/internal/src/index-sort-l.html create mode 100644 coverage/internal/src/index.html create mode 100644 coverage/internal/src/packaging.rs.func-sort-c.html create mode 100644 coverage/internal/src/packaging.rs.func.html create mode 100644 coverage/internal/src/packaging.rs.gcov.html create mode 100644 coverage/internal/src/rustup.rs.func-sort-c.html create mode 100644 coverage/internal/src/rustup.rs.func.html create mode 100644 coverage/internal/src/rustup.rs.gcov.html create mode 100644 coverage/internal/src/sed.rs.func-sort-c.html create mode 100644 coverage/internal/src/sed.rs.func.html create mode 100644 coverage/internal/src/sed.rs.gcov.html create mode 100644 coverage/internal/src/testing.rs.func-sort-c.html create mode 100644 coverage/internal/src/testing.rs.func.html create mode 100644 coverage/internal/src/testing.rs.gcov.html create mode 100644 coverage/ruby.png create mode 100644 coverage/snow.png create mode 100644 coverage/updown.png create mode 100644 coverage/utils/linting/src/index-sort-f.html create mode 100644 coverage/utils/linting/src/index-sort-l.html create mode 100644 coverage/utils/linting/src/index.html create mode 100644 coverage/utils/linting/src/lib.rs.func-sort-c.html create mode 100644 coverage/utils/linting/src/lib.rs.func.html create mode 100644 coverage/utils/linting/src/lib.rs.gcov.html create mode 100644 coverage/utils/testing/src/index-sort-f.html create mode 100644 coverage/utils/testing/src/index-sort-l.html create mode 100644 coverage/utils/testing/src/index.html create mode 100644 coverage/utils/testing/src/lib.rs.func-sort-c.html create mode 100644 coverage/utils/testing/src/lib.rs.func.html create mode 100644 coverage/utils/testing/src/lib.rs.gcov.html create mode 100644 coverage/utils/testing/src/ui.rs.func-sort-c.html create mode 100644 coverage/utils/testing/src/ui.rs.func.html create mode 100644 coverage/utils/testing/src/ui.rs.gcov.html diff --git a/coverage/amber.png b/coverage/amber.png new file mode 100644 index 0000000000000000000000000000000000000000..2cab170d8359081983a4e343848dfe06bc490f12 GIT binary patch literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)ga>?NMQuI!iC1^G2tW}LqE04T&+ z;1OBOz`!j8!i<;h*8KqrvZOouIx;Y9?C1WI$O`1M1^9%x{(levWG + + + + + + LCOV - unnamed - cargo-dylint/src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - cargo-dylint/srcHitTotalCoverage
Test:unnamedLines:15016392.0 %
Date:2024-09-27 12:58:08Functions:134429.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
main.rs +
92.0%92.0%
+
92.0 %150 / 16329.5 %13 / 44
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/cargo-dylint/src/index-sort-l.html b/coverage/cargo-dylint/src/index-sort-l.html new file mode 100644 index 000000000..458462e01 --- /dev/null +++ b/coverage/cargo-dylint/src/index-sort-l.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - unnamed - cargo-dylint/src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - cargo-dylint/srcHitTotalCoverage
Test:unnamedLines:15016392.0 %
Date:2024-09-27 12:58:08Functions:134429.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
main.rs +
92.0%92.0%
+
92.0 %150 / 16329.5 %13 / 44
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/cargo-dylint/src/index.html b/coverage/cargo-dylint/src/index.html new file mode 100644 index 000000000..3e8c27c6c --- /dev/null +++ b/coverage/cargo-dylint/src/index.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - unnamed - cargo-dylint/src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - cargo-dylint/srcHitTotalCoverage
Test:unnamedLines:15016392.0 %
Date:2024-09-27 12:58:08Functions:134429.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
main.rs +
92.0%92.0%
+
92.0 %150 / 16329.5 %13 / 44
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/cargo-dylint/src/main.rs.func-sort-c.html b/coverage/cargo-dylint/src/main.rs.func-sort-c.html new file mode 100644 index 000000000..f5a55688f --- /dev/null +++ b/coverage/cargo-dylint/src/main.rs.func-sort-c.html @@ -0,0 +1,248 @@ + + + + + + + LCOV - unnamed - cargo-dylint/src/main.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - cargo-dylint/src - main.rs (source / functions)HitTotalCoverage
Test:unnamedLines:15016392.0 %
Date:2024-09-27 12:58:08Functions:134429.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<cargo_dylint::Dylint as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#0}0
<cargo_dylint::Dylint as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#1}0
<cargo_dylint::Dylint as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#2}0
<cargo_dylint::Dylint as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#4}0
<cargo_dylint::Dylint as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#0}0
<cargo_dylint::Dylint as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#1}0
<cargo_dylint::Dylint as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#2}0
<cargo_dylint::Dylint as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#3}0
<cargo_dylint::Dylint as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#4}0
<cargo_dylint::Dylint as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#5}0
<cargo_dylint::LibrarySelection as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#0}0
<cargo_dylint::LibrarySelection as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#1}0
<cargo_dylint::LibrarySelection as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#3}0
<cargo_dylint::LibrarySelection as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#4}0
<cargo_dylint::LibrarySelection as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#0}0
<cargo_dylint::LibrarySelection as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#1}0
<cargo_dylint::LibrarySelection as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#2}0
<cargo_dylint::LibrarySelection as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#3}0
<cargo_dylint::LibrarySelection as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#4}0
<cargo_dylint::LibrarySelection as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#5}0
<cargo_dylint::Operation as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#0}0
<cargo_dylint::Operation as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#1}0
<cargo_dylint::Operation as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#2}0
<cargo_dylint::Operation as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#3}0
<cargo_dylint::Operation as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#0}0
<cargo_dylint::Operation as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#1}0
<cargo_dylint::Operation as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#2}0
<cargo_dylint::Operation as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#3}0
<cargo_dylint::OutputOptions as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#0}0
<cargo_dylint::OutputOptions as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#0}0
cargo_dylint::cargo_dylint::<_>0
<cargo_dylint::Dylint as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#5}1
cargo_dylint::tests::usage1
cargo_dylint::tests::verify_cli1
cargo_dylint::tests::version1
<cargo_dylint::Dylint as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#3}2
<cargo_dylint::LibrarySelection as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#5}3
<cargo_dylint::LibrarySelection as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#2}9
<cargo_dylint::LibrarySelection>::absorb10
<dylint::opts::LibrarySelection as core::convert::From<cargo_dylint::LibrarySelection>>::from37
<dylint::opts::Dylint as core::convert::From<cargo_dylint::Dylint>>::from41
cargo_dylint::cargo_dylint::<std::ffi::os_str::OsString>43
cargo_dylint::main43
cargo_dylint::main::{closure#0}43
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/cargo-dylint/src/main.rs.func.html b/coverage/cargo-dylint/src/main.rs.func.html new file mode 100644 index 000000000..f138541e8 --- /dev/null +++ b/coverage/cargo-dylint/src/main.rs.func.html @@ -0,0 +1,248 @@ + + + + + + + LCOV - unnamed - cargo-dylint/src/main.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - cargo-dylint/src - main.rs (source / functions)HitTotalCoverage
Test:unnamedLines:15016392.0 %
Date:2024-09-27 12:58:08Functions:134429.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<cargo_dylint::Dylint as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#0}0
<cargo_dylint::Dylint as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#1}0
<cargo_dylint::Dylint as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#2}0
<cargo_dylint::Dylint as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#3}2
<cargo_dylint::Dylint as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#4}0
<cargo_dylint::Dylint as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#5}1
<cargo_dylint::Dylint as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#0}0
<cargo_dylint::Dylint as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#1}0
<cargo_dylint::Dylint as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#2}0
<cargo_dylint::Dylint as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#3}0
<cargo_dylint::Dylint as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#4}0
<cargo_dylint::Dylint as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#5}0
<cargo_dylint::LibrarySelection as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#0}0
<cargo_dylint::LibrarySelection as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#1}0
<cargo_dylint::LibrarySelection as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#2}9
<cargo_dylint::LibrarySelection as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#3}0
<cargo_dylint::LibrarySelection as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#4}0
<cargo_dylint::LibrarySelection as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#5}3
<cargo_dylint::LibrarySelection as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#0}0
<cargo_dylint::LibrarySelection as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#1}0
<cargo_dylint::LibrarySelection as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#2}0
<cargo_dylint::LibrarySelection as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#3}0
<cargo_dylint::LibrarySelection as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#4}0
<cargo_dylint::LibrarySelection as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#5}0
<cargo_dylint::LibrarySelection>::absorb10
<cargo_dylint::Operation as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#0}0
<cargo_dylint::Operation as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#1}0
<cargo_dylint::Operation as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#2}0
<cargo_dylint::Operation as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#3}0
<cargo_dylint::Operation as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#0}0
<cargo_dylint::Operation as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#1}0
<cargo_dylint::Operation as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#2}0
<cargo_dylint::Operation as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#3}0
<cargo_dylint::OutputOptions as clap_builder::derive::FromArgMatches>::from_arg_matches_mut::{closure#0}0
<cargo_dylint::OutputOptions as clap_builder::derive::FromArgMatches>::update_from_arg_matches_mut::{closure#0}0
<dylint::opts::Dylint as core::convert::From<cargo_dylint::Dylint>>::from41
<dylint::opts::LibrarySelection as core::convert::From<cargo_dylint::LibrarySelection>>::from37
cargo_dylint::cargo_dylint::<_>0
cargo_dylint::cargo_dylint::<std::ffi::os_str::OsString>43
cargo_dylint::main43
cargo_dylint::main::{closure#0}43
cargo_dylint::tests::usage1
cargo_dylint::tests::verify_cli1
cargo_dylint::tests::version1
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/cargo-dylint/src/main.rs.gcov.html b/coverage/cargo-dylint/src/main.rs.gcov.html new file mode 100644 index 000000000..f65df46f7 --- /dev/null +++ b/coverage/cargo-dylint/src/main.rs.gcov.html @@ -0,0 +1,519 @@ + + + + + + + LCOV - unnamed - cargo-dylint/src/main.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - cargo-dylint/src - main.rs (source / functions)HitTotalCoverage
Test:unnamedLines:15016392.0 %
Date:2024-09-27 12:58:08Functions:134429.5 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : use clap::{crate_version, ArgAction, Parser};
+       2             : use std::{
+       3             :     ffi::{OsStr, OsString},
+       4             :     fmt::Debug,
+       5             : };
+       6             : 
+       7             : #[derive(Debug, Parser)]
+       8             : #[clap(bin_name = "cargo", display_name = "cargo")]
+       9             : struct Opts {
+      10             :     #[clap(subcommand)]
+      11             :     subcmd: CargoSubcommand,
+      12             : }
+      13             : 
+      14             : #[derive(Debug, Parser)]
+      15             : enum CargoSubcommand {
+      16             :     Dylint(Dylint),
+      17             : }
+      18             : 
+      19             : #[allow(clippy::struct_excessive_bools)]
+      20             : #[derive(Debug, Parser)]
+      21             : #[clap(
+      22             :     version = crate_version!(),
+      23             :     args_conflicts_with_subcommands = true,
+      24             :     after_help = r#"ENVIRONMENT VARIABLES:
+      25             : 
+      26             : DYLINT_DRIVER_PATH (default: $HOME/.dylint_drivers) is the directory where Dylint stores rustc
+      27             : drivers.
+      28             : 
+      29             : DYLINT_LIBRARY_PATH (default: none) is a colon-separated list of directories where Dylint searches
+      30             : for libraries.
+      31             : 
+      32             : DYLINT_RUSTFLAGS (default: none) is a space-separated list of flags that Dylint passes to `rustc`
+      33             : when checking the packages in the workspace.
+      34             : 
+      35             : METADATA EXAMPLE:
+      36             : 
+      37             :     [workspace.metadata.dylint]
+      38             :     libraries = [
+      39             :         { git = "https://github.com/trailofbits/dylint", pattern = "examples/*/*" },
+      40             :         { path = "libs/*" },
+      41             :     ]
+      42             : "#,
+      43             : )]
+      44             : // smoelius: Please keep the last four fields `args`, `operation`, `lib_sel`, and `output`, in that
+      45             : // order. Please keep all other fields sorted.
+      46             : struct Dylint {
+      47             :     #[clap(long, help = "Automatically apply lint suggestions")]
+      48           0 :     fix: bool,
+      49             : 
+      50             :     #[clap(long, help = "Continue if `cargo check` fails")]
+      51           0 :     keep_going: bool,
+      52             : 
+      53             :     #[clap(long, help = "Do not check other packages within the workspace")]
+      54           0 :     no_deps: bool,
+      55             : 
+      56             :     #[clap(
+      57             :         action = ArgAction::Append,
+      58             :         number_of_values = 1,
+      59             :         short,
+      60             :         long = "package",
+      61             :         value_name = "spec",
+      62             :         help = "Package to check"
+      63             :     )]
+      64           2 :     packages: Vec<String>,
+      65             : 
+      66             :     #[clap(long, help = "Check all packages in the workspace")]
+      67           0 :     workspace: bool,
+      68             : 
+      69             :     #[clap(last = true, help = "Arguments for `cargo check`")]
+      70           1 :     args: Vec<String>,
+      71             : 
+      72             :     #[clap(subcommand)]
+      73             :     operation: Option<Operation>,
+      74             : 
+      75             :     #[clap(flatten)]
+      76             :     lib_sel: LibrarySelection,
+      77             : 
+      78             :     #[clap(flatten)]
+      79             :     output: OutputOptions,
+      80             : }
+      81             : 
+      82             : #[derive(Debug, Parser)]
+      83             : enum Operation {
+      84             :     #[clap(
+      85             :         about = "List libraries or lints",
+      86             :         long_about = "If no libraries are named, list the name, toolchain, and location of all \
+      87             : discovered libraries.
+      88             : 
+      89             : If at least one library is named, list the name, level, and description of all lints in all named \
+      90             : libraries.
+      91             : 
+      92             : Combine with `--all` to list all lints in all discovered libraries."
+      93             :     )]
+      94             :     List {
+      95             :         #[clap(flatten)]
+      96             :         lib_sel: LibrarySelection,
+      97             :     },
+      98             : 
+      99             :     #[clap(
+     100             :         about = "Create a new library package",
+     101             :         long_about = "Create a new library package at <PATH>"
+     102             :     )]
+     103             :     New {
+     104             :         #[clap(long, help = "Put the package in its own workspace")]
+     105           0 :         isolate: bool,
+     106             : 
+     107             :         #[clap(help = "Path to library package")]
+     108           0 :         path: String,
+     109             :     },
+     110             : 
+     111             :     #[clap(
+     112             :         about = "Upgrade library package",
+     113             :         long_about = "Upgrade the library package at <PATH> to the latest version of \
+     114             :                       `clippy_utils`"
+     115             :     )]
+     116             :     Upgrade {
+     117             :         #[clap(long, hide = true)]
+     118           0 :         allow_downgrade: bool,
+     119             : 
+     120             :         #[clap(
+     121             :             long,
+     122             :             value_name = "version",
+     123             :             help = "Upgrade to the version of `clippy_utils` with tag `rust-<version>`"
+     124             :         )]
+     125             :         rust_version: Option<String>,
+     126             : 
+     127             :         #[clap(help = "Path to library package")]
+     128           0 :         path: String,
+     129             :     },
+     130             : }
+     131             : 
+     132             : #[derive(Debug, Parser)]
+     133             : #[cfg_attr(feature = "__clap_headings", clap(next_help_heading = Some("Library Selection")))]
+     134             : struct LibrarySelection {
+     135             :     #[clap(long, help = "Load all discovered libraries")]
+     136           0 :     all: bool,
+     137             : 
+     138             :     #[clap(
+     139             :         long,
+     140             :         requires("git"),
+     141             :         help = "Branch to use when downloading library packages"
+     142             :     )]
+     143             :     branch: Option<String>,
+     144             : 
+     145             :     #[clap(
+     146             :         long,
+     147             :         value_name = "url",
+     148             :         conflicts_with("paths"),
+     149             :         help = "Git url containing library packages"
+     150             :     )]
+     151             :     git: Option<String>,
+     152             : 
+     153             :     #[clap(
+     154             :         action = ArgAction::Append,
+     155             :         number_of_values = 1,
+     156             :         long = "lib-path",
+     157             :         value_name = "path",
+     158             :         help = "Library path to load lints from"
+     159             :     )]
+     160           0 :     lib_paths: Vec<String>,
+     161             : 
+     162             :     #[clap(
+     163             :         action = ArgAction::Append,
+     164             :         number_of_values = 1,
+     165             :         long = "lib",
+     166             :         value_name = "name",
+     167             :         help = "Library name to load lints from. A file with a name of the form \"DLL_PREFIX \
+     168             :         <name> '@' TOOLCHAIN DLL_SUFFIX\" is searched for in the directories listed in \
+     169             :         DYLINT_LIBRARY_PATH, and in the `target/release` directories produced by building the \
+     170             :         current workspace's metadata entries (see example below)."
+     171             :     )]
+     172           9 :     libs: Vec<String>,
+     173             : 
+     174             :     #[clap(
+     175             :         long,
+     176             :         value_name = "path",
+     177             :         help = "Path to Cargo.toml. Note: if the manifest uses metadata, then `--manifest-path \
+     178             :                 <path>` must appear before `--`, not after."
+     179             :     )]
+     180             :     manifest_path: Option<String>,
+     181             : 
+     182             :     #[clap(long, help = "Do not build metadata entries")]
+     183           0 :     no_build: bool,
+     184             : 
+     185             :     #[clap(long, help = "Ignore metadata entirely")]
+     186           0 :     no_metadata: bool,
+     187             : 
+     188             :     #[clap(
+     189             :         action = ArgAction::Append,
+     190             :         number_of_values = 1,
+     191             :         long = "path",
+     192             :         value_name = "path",
+     193             :         conflicts_with("git"),
+     194             :         help = "Path containing library packages"
+     195             :     )]
+     196           3 :     paths: Vec<String>,
+     197             : 
+     198             :     #[clap(
+     199             :         long,
+     200             :         help = "Subdirectories of the `--git` or `--path` argument containing library packages"
+     201             :     )]
+     202             :     pattern: Option<String>,
+     203             : 
+     204             :     #[clap(
+     205             :         long,
+     206             :         requires("git"),
+     207             :         help = "Specific commit to use when downloading library packages"
+     208             :     )]
+     209             :     rev: Option<String>,
+     210             : 
+     211             :     #[clap(
+     212             :         long,
+     213             :         requires("git"),
+     214             :         help = "Tag to use when downloading library packages"
+     215             :     )]
+     216             :     tag: Option<String>,
+     217             : }
+     218             : 
+     219             : #[derive(Debug, Parser)]
+     220             : #[cfg_attr(feature = "__clap_headings", clap(next_help_heading = Some("Output Options")))]
+     221             : struct OutputOptions {
+     222             :     #[clap(long, value_name = "path", help = "Path to pipe stderr to")]
+     223             :     pipe_stderr: Option<String>,
+     224             : 
+     225             :     #[clap(long, value_name = "path", help = "Path to pipe stdout to")]
+     226             :     pipe_stdout: Option<String>,
+     227             : 
+     228             :     #[clap(
+     229             :         global = true,
+     230             :         short,
+     231             :         long,
+     232             :         help = "Do not show warnings or progress running commands besides `cargo check` and \
+     233             :                 `cargo fix`"
+     234             :     )]
+     235           0 :     quiet: bool,
+     236             : }
+     237             : 
+     238             : impl From<Dylint> for dylint::opts::Dylint {
+     239          41 :     fn from(opts: Dylint) -> Self {
+     240          41 :         let Dylint {
+     241          41 :             fix,
+     242          41 :             keep_going,
+     243          41 :             no_deps,
+     244          41 :             packages,
+     245          41 :             workspace,
+     246          41 :             args,
+     247          41 :             operation,
+     248          41 :             mut lib_sel,
+     249          41 :             output:
+     250          41 :                 OutputOptions {
+     251          41 :                     pipe_stderr,
+     252          41 :                     pipe_stdout,
+     253          41 :                     quiet,
+     254          41 :                 },
+     255          41 :         } = opts;
+     256          41 :         let operation = match operation {
+     257          27 :             None => dylint::opts::Operation::Check({
+     258          27 :                 dylint::opts::Check {
+     259          27 :                     lib_sel: lib_sel.into(),
+     260          27 :                     fix,
+     261          27 :                     keep_going,
+     262          27 :                     no_deps,
+     263          27 :                     packages,
+     264          27 :                     workspace,
+     265          27 :                     args,
+     266          27 :                 }
+     267          27 :             }),
+     268          10 :             Some(Operation::List { lib_sel: other }) => {
+     269          10 :                 lib_sel.absorb(other);
+     270          10 :                 dylint::opts::Operation::List(dylint::opts::List {
+     271          10 :                     lib_sel: lib_sel.into(),
+     272          10 :                 })
+     273             :             }
+     274           1 :             Some(Operation::New { isolate, path }) => {
+     275           1 :                 dylint::opts::Operation::New(dylint::opts::New { isolate, path })
+     276             :             }
+     277             :             Some(Operation::Upgrade {
+     278           3 :                 allow_downgrade,
+     279           3 :                 rust_version,
+     280           3 :                 path,
+     281           3 :             }) => dylint::opts::Operation::Upgrade(dylint::opts::Upgrade {
+     282           3 :                 allow_downgrade,
+     283           3 :                 rust_version,
+     284           3 :                 path,
+     285           3 :             }),
+     286             :         };
+     287          41 :         Self {
+     288          41 :             pipe_stderr,
+     289          41 :             pipe_stdout,
+     290          41 :             quiet,
+     291          41 :             operation,
+     292          41 :         }
+     293          41 :     }
+     294             : }
+     295             : 
+     296             : macro_rules! option_absorb {
+     297             :     ($this:expr, $other:expr) => {
+     298             :         if $other.is_some() {
+     299             :             assert!(
+     300             :                 $this.is_none(),
+     301             :                 "`--{}` used multiple times",
+     302             :                 stringify!($other).replace("_", "-")
+     303             :             );
+     304             :             *$this = $other;
+     305             :         }
+     306             :     };
+     307             : }
+     308             : 
+     309             : impl LibrarySelection {
+     310          10 :     pub fn absorb(&mut self, other: Self) {
+     311          10 :         let Self {
+     312          10 :             all,
+     313          10 :             branch,
+     314          10 :             git,
+     315          10 :             lib_paths,
+     316          10 :             libs,
+     317          10 :             manifest_path,
+     318          10 :             no_build,
+     319          10 :             no_metadata,
+     320          10 :             paths,
+     321          10 :             pattern,
+     322          10 :             rev,
+     323          10 :             tag,
+     324          10 :         } = other;
+     325          10 :         self.all |= all;
+     326          10 :         option_absorb!(&mut self.branch, branch);
+     327          10 :         option_absorb!(&mut self.git, git);
+     328          10 :         self.lib_paths.extend(lib_paths);
+     329          10 :         self.libs.extend(libs);
+     330          10 :         option_absorb!(&mut self.manifest_path, manifest_path);
+     331          10 :         self.no_build |= no_build;
+     332          10 :         self.no_metadata |= no_metadata;
+     333          10 :         self.paths.extend(paths);
+     334          10 :         option_absorb!(&mut self.pattern, pattern);
+     335          10 :         option_absorb!(&mut self.rev, rev);
+     336          10 :         option_absorb!(&mut self.tag, tag);
+     337          10 :     }
+     338             : }
+     339             : 
+     340             : impl From<LibrarySelection> for dylint::opts::LibrarySelection {
+     341          37 :     fn from(lib_sel: LibrarySelection) -> Self {
+     342          37 :         let LibrarySelection {
+     343          37 :             all,
+     344          37 :             branch,
+     345          37 :             git,
+     346          37 :             lib_paths,
+     347          37 :             libs,
+     348          37 :             manifest_path,
+     349          37 :             no_build,
+     350          37 :             no_metadata,
+     351          37 :             paths,
+     352          37 :             pattern,
+     353          37 :             rev,
+     354          37 :             tag,
+     355          37 :         } = lib_sel;
+     356          37 :         Self {
+     357          37 :             all,
+     358          37 :             branch,
+     359          37 :             git,
+     360          37 :             lib_paths,
+     361          37 :             libs,
+     362          37 :             manifest_path,
+     363          37 :             no_build,
+     364          37 :             no_metadata,
+     365          37 :             paths,
+     366          37 :             pattern,
+     367          37 :             rev,
+     368          37 :             tag,
+     369          37 :         }
+     370          37 :     }
+     371             : }
+     372             : 
+     373          43 : fn main() -> dylint::ColorizedResult<()> {
+     374          43 :     env_logger::try_init().unwrap_or_else(|error| {
+     375          43 :         dylint::__warn(
+     376          43 :             &dylint::opts::Dylint::default(),
+     377          43 :             &format!("`env_logger` already initialized: {error}"),
+     378          43 :         );
+     379          43 :     });
+     380          43 : 
+     381          43 :     let args: Vec<_> = std::env::args().map(OsString::from).collect();
+     382          43 : 
+     383          43 :     cargo_dylint(&args)
+     384          43 : }
+     385             : 
+     386          43 : fn cargo_dylint<T: AsRef<OsStr>>(args: &[T]) -> dylint::ColorizedResult<()> {
+     387          43 :     match Opts::parse_from(args).subcmd {
+     388          43 :         CargoSubcommand::Dylint(opts) => dylint::run(&dylint::opts::Dylint::from(opts)),
+     389          43 :     }
+     390          43 :     .map_err(dylint::ColorizedError::new)
+     391          43 : }
+     392             : 
+     393             : #[cfg(test)]
+     394             : mod tests {
+     395             :     use super::*;
+     396             :     use assert_cmd::prelude::*;
+     397             :     use clap::CommandFactory;
+     398             : 
+     399             :     #[test]
+     400           1 :     fn verify_cli() {
+     401           1 :         Opts::command().debug_assert();
+     402           1 :     }
+     403             : 
+     404             :     #[test]
+     405           1 :     fn usage() {
+     406           1 :         std::process::Command::cargo_bin("cargo-dylint")
+     407           1 :             .unwrap()
+     408           1 :             .args(["dylint", "--help"])
+     409           1 :             .assert()
+     410           1 :             .success()
+     411           1 :             .stdout(predicates::str::contains("Usage: cargo dylint"));
+     412           1 :     }
+     413             : 
+     414             :     #[test]
+     415           1 :     fn version() {
+     416           1 :         std::process::Command::cargo_bin("cargo-dylint")
+     417           1 :             .unwrap()
+     418           1 :             .args(["dylint", "--version"])
+     419           1 :             .assert()
+     420           1 :             .success()
+     421           1 :             .stdout(format!("cargo-dylint {}\n", env!("CARGO_PKG_VERSION")));
+     422           1 :     }
+     423             : 
+     424             :     // `no_env_logger_warning` fails if [`std::process::Command::new`] is replaced with
+     425             :     // [`assert_cmd::cargo::CommandCargoExt::cargo_bin`]. I don't understand why.
+     426             :     //
+     427             :     // [`assert_cmd::cargo::CommandCargoExt::cargo_bin`]: https://docs.rs/assert_cmd/latest/assert_cmd/cargo/trait.CommandCargoExt.html#tymethod.cargo_bin
+     428             :     // [`std::process::Command::new`]: https://doc.rust-lang.org/std/process/struct.Command.html#method.new
+     429             :     //
+     430             :     // smoelius: I am switching to `assert_cmd::cargo::CommandCargoExt::cargo_bin` and disabling
+     431             :     // this test. `cargo run` without a `--features=...` argument can cause `cargo-dylint` to be
+     432             :     // rebuilt with the wrong features.
+     433             :     #[cfg(any())]
+     434             :     #[test]
+     435             :     fn no_env_logger_warning() {
+     436             :         std::process::Command::cargo_bin("cargo-dylint")
+     437             :             .unwrap()
+     438             :             .arg("dylint")
+     439             :             .assert()
+     440             :             .failure()
+     441             :             .stderr(predicates::str::contains("`env_logger` already initialized").not());
+     442             :     }
+     443             : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/driver/src/index-sort-f.html b/coverage/driver/src/index-sort-f.html new file mode 100644 index 000000000..560c5ad01 --- /dev/null +++ b/coverage/driver/src/index-sort-f.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - unnamed - driver/src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - driver/srcHitTotalCoverage
Test:unnamedLines:6929123.7 %
Date:2024-09-27 12:58:08Functions:53414.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
lib.rs +
23.7%23.7%
+
23.7 %69 / 29114.7 %5 / 34
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/driver/src/index-sort-l.html b/coverage/driver/src/index-sort-l.html new file mode 100644 index 000000000..28374989b --- /dev/null +++ b/coverage/driver/src/index-sort-l.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - unnamed - driver/src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - driver/srcHitTotalCoverage
Test:unnamedLines:6929123.7 %
Date:2024-09-27 12:58:08Functions:53414.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
lib.rs +
23.7%23.7%
+
23.7 %69 / 29114.7 %5 / 34
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/driver/src/index.html b/coverage/driver/src/index.html new file mode 100644 index 000000000..f2895b991 --- /dev/null +++ b/coverage/driver/src/index.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - unnamed - driver/src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - driver/srcHitTotalCoverage
Test:unnamedLines:6929123.7 %
Date:2024-09-27 12:58:08Functions:53414.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
lib.rs +
23.7%23.7%
+
23.7 %69 / 29114.7 %5 / 34
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/driver/src/lib.rs.func-sort-c.html b/coverage/driver/src/lib.rs.func-sort-c.html new file mode 100644 index 000000000..fbe422955 --- /dev/null +++ b/coverage/driver/src/lib.rs.func-sort-c.html @@ -0,0 +1,208 @@ + + + + + + + LCOV - unnamed - driver/src/lib.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - driver/src - lib.rs (source / functions)HitTotalCoverage
Test:unnamedLines:6929123.7 %
Date:2024-09-27 12:58:08Functions:53414.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<dylint_driver::Callbacks as rustc_driver_impl::Callbacks>::config0
<dylint_driver::Callbacks as rustc_driver_impl::Callbacks>::config::{closure#0}0
<dylint_driver::Callbacks as rustc_driver_impl::Callbacks>::config::{closure#0}::{closure#0}0
<dylint_driver::Callbacks as rustc_driver_impl::Callbacks>::config::{closure#0}::{closure#1}0
<dylint_driver::Callbacks as rustc_driver_impl::Callbacks>::config::{closure#0}::{closure#2}0
<dylint_driver::Callbacks>::new0
<dylint_driver::Callbacks>::new::{closure#0}0
<dylint_driver::Lint as core::convert::From<&rustc_lint_defs::Lint>>::from0
<dylint_driver::LoadedLibrary>::register_lints0
<dylint_driver::LoadedLibrary>::register_lints::{closure#0}0
<dylint_driver::LoadedLibrary>::register_lints::{closure#1}0
<rustc_session::session::Session as dylint_driver::ParseSess>::parse_sess0
dylint_driver::dylint_driver::<_>0
dylint_driver::dylint_driver::<_>::{closure#0}0
dylint_driver::early_error::<_>0
dylint_driver::list_enabled0
dylint_driver::list_enabled::{closure#0}0
dylint_driver::list_lints0
dylint_driver::list_lints::{closure#0}0
dylint_driver::list_lints::{closure#1}0
dylint_driver::paths0
dylint_driver::paths::{closure#0}0
dylint_driver::run::<_>0
dylint_driver::rustflags0
dylint_driver::rustflags::{closure#0}0
dylint_driver::rustflags::{closure#1}0
dylint_driver::session_err::<_>0
dylint_driver::sysroot0
dylint_driver::zero_mir_opt_level0
dylint_driver::test::channel_is_nightly1
dylint_driver::test::no_rustc1
dylint_driver::test::plain_rustc1
dylint_driver::test::qualified_rustc1
dylint_driver::rustc_args::<&str12
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/driver/src/lib.rs.func.html b/coverage/driver/src/lib.rs.func.html new file mode 100644 index 000000000..6df765bf9 --- /dev/null +++ b/coverage/driver/src/lib.rs.func.html @@ -0,0 +1,208 @@ + + + + + + + LCOV - unnamed - driver/src/lib.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - driver/src - lib.rs (source / functions)HitTotalCoverage
Test:unnamedLines:6929123.7 %
Date:2024-09-27 12:58:08Functions:53414.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<dylint_driver::Callbacks as rustc_driver_impl::Callbacks>::config0
<dylint_driver::Callbacks as rustc_driver_impl::Callbacks>::config::{closure#0}0
<dylint_driver::Callbacks as rustc_driver_impl::Callbacks>::config::{closure#0}::{closure#0}0
<dylint_driver::Callbacks as rustc_driver_impl::Callbacks>::config::{closure#0}::{closure#1}0
<dylint_driver::Callbacks as rustc_driver_impl::Callbacks>::config::{closure#0}::{closure#2}0
<dylint_driver::Callbacks>::new0
<dylint_driver::Callbacks>::new::{closure#0}0
<dylint_driver::Lint as core::convert::From<&rustc_lint_defs::Lint>>::from0
<dylint_driver::LoadedLibrary>::register_lints0
<dylint_driver::LoadedLibrary>::register_lints::{closure#0}0
<dylint_driver::LoadedLibrary>::register_lints::{closure#1}0
<rustc_session::session::Session as dylint_driver::ParseSess>::parse_sess0
dylint_driver::dylint_driver::<_>0
dylint_driver::dylint_driver::<_>::{closure#0}0
dylint_driver::early_error::<_>0
dylint_driver::list_enabled0
dylint_driver::list_enabled::{closure#0}0
dylint_driver::list_lints0
dylint_driver::list_lints::{closure#0}0
dylint_driver::list_lints::{closure#1}0
dylint_driver::paths0
dylint_driver::paths::{closure#0}0
dylint_driver::run::<_>0
dylint_driver::rustc_args::<&str12
dylint_driver::rustflags0
dylint_driver::rustflags::{closure#0}0
dylint_driver::rustflags::{closure#1}0
dylint_driver::session_err::<_>0
dylint_driver::sysroot0
dylint_driver::test::channel_is_nightly1
dylint_driver::test::no_rustc1
dylint_driver::test::plain_rustc1
dylint_driver::test::qualified_rustc1
dylint_driver::zero_mir_opt_level0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/driver/src/lib.rs.gcov.html b/coverage/driver/src/lib.rs.gcov.html new file mode 100644 index 000000000..8f2e7d0d8 --- /dev/null +++ b/coverage/driver/src/lib.rs.gcov.html @@ -0,0 +1,552 @@ + + + + + + + LCOV - unnamed - driver/src/lib.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - driver/src - lib.rs (source / functions)HitTotalCoverage
Test:unnamedLines:6929123.7 %
Date:2024-09-27 12:58:08Functions:53414.7 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #![feature(rustc_private)]
+       2             : #![deny(clippy::expect_used)]
+       3             : #![deny(clippy::unwrap_used)]
+       4             : #![deny(clippy::panic)]
+       5             : #![deny(unused_extern_crates)]
+       6             : 
+       7             : extern crate rustc_driver;
+       8             : extern crate rustc_interface;
+       9             : extern crate rustc_lint;
+      10             : extern crate rustc_session;
+      11             : extern crate rustc_span;
+      12             : 
+      13             : use anyhow::{bail, ensure, Result};
+      14             : use dylint_internal::{env, parse_path_filename, rustup::is_rustc};
+      15             : use std::{
+      16             :     collections::BTreeSet,
+      17             :     ffi::{CString, OsStr},
+      18             :     path::{Path, PathBuf},
+      19             : };
+      20             : 
+      21             : pub const DYLINT_VERSION: &str = "0.1.0";
+      22             : 
+      23             : type DylintVersionFunc = unsafe fn() -> *mut std::os::raw::c_char;
+      24             : 
+      25             : type RegisterLintsFunc =
+      26             :     unsafe fn(sess: &rustc_session::Session, store: &mut rustc_lint::LintStore);
+      27             : 
+      28             : /// A library that has been loaded but whose lints have not necessarily been registered.
+      29             : struct LoadedLibrary {
+      30             :     path: PathBuf,
+      31             :     lib: libloading::Library,
+      32             : }
+      33             : 
+      34             : #[derive(Clone, Eq, Ord, PartialEq, PartialOrd)]
+      35             : struct Lint {
+      36             :     name: &'static str,
+      37             :     level: rustc_lint::Level,
+      38             :     desc: &'static str,
+      39             : }
+      40             : 
+      41             : impl From<&rustc_lint::Lint> for Lint {
+      42           0 :     fn from(lint: &rustc_lint::Lint) -> Self {
+      43           0 :         Self {
+      44           0 :             name: lint.name,
+      45           0 :             level: lint.default_level,
+      46           0 :             desc: lint.desc,
+      47           0 :         }
+      48           0 :     }
+      49             : }
+      50             : 
+      51             : impl LoadedLibrary {
+      52           0 :     fn register_lints(
+      53           0 :         &self,
+      54           0 :         sess: &rustc_session::Session,
+      55           0 :         lint_store: &mut rustc_lint::LintStore,
+      56           0 :     ) {
+      57           0 :         (|| unsafe {
+      58           0 :             if let Ok(func) = self.lib.get::<DylintVersionFunc>(b"dylint_version") {
+      59           0 :                 let dylint_version = CString::from_raw(func()).into_string()?;
+      60           0 :                 ensure!(
+      61           0 :                     dylint_version == DYLINT_VERSION,
+      62           0 :                     "`{}` has dylint version `{}`, but `{}` was expected",
+      63           0 :                     self.path.to_string_lossy(),
+      64             :                     dylint_version,
+      65             :                     DYLINT_VERSION
+      66             :                 );
+      67             :             } else {
+      68           0 :                 bail!(
+      69           0 :                     "could not find `dylint_version` in `{}`",
+      70           0 :                     self.path.to_string_lossy()
+      71           0 :                 );
+      72             :             }
+      73           0 :             if let Ok(func) = self.lib.get::<RegisterLintsFunc>(b"register_lints") {
+      74           0 :                 func(sess, lint_store);
+      75           0 :             } else {
+      76           0 :                 bail!(
+      77           0 :                     "could not find `register_lints` in `{}`",
+      78           0 :                     self.path.to_string_lossy()
+      79           0 :                 );
+      80             :             }
+      81           0 :             Ok(())
+      82           0 :         })()
+      83           0 :         .unwrap_or_else(|err| {
+      84           0 :             session_err(sess, &err);
+      85           0 :         });
+      86           0 :     }
+      87             : }
+      88             : 
+      89             : #[rustversion::before(2023-12-18)]
+      90             : fn session_err(sess: &rustc_session::Session, err: &impl ToString) -> rustc_span::ErrorGuaranteed {
+      91             :     sess.diagnostic().err(err.to_string())
+      92             : }
+      93             : 
+      94             : #[rustversion::since(2023-12-18)]
+      95           0 : fn session_err(sess: &rustc_session::Session, err: &impl ToString) -> rustc_span::ErrorGuaranteed {
+      96           0 :     sess.dcx().err(err.to_string())
+      97           0 : }
+      98             : 
+      99             : struct Callbacks {
+     100             :     loaded_libs: Vec<LoadedLibrary>,
+     101             : }
+     102             : 
+     103             : // smoelius: Use of thread local storage was added to Clippy by:
+     104             : // https://github.com/rust-lang/rust-clippy/commit/3c06e0b1ce003912f8fe0536d3a7fe22558e38cf
+     105             : // This results in a segfault after the Clippy library has been unloaded; see the following issue
+     106             : // for an explanation as to why: https://github.com/nagisa/rust_libloading/issues/5
+     107             : // The workaround I've chosen is:
+     108             : // https://github.com/nagisa/rust_libloading/issues/5#issuecomment-244195096
+     109             : impl Callbacks {
+     110             :     // smoelius: Load the libraries when `Callbacks` is created and not later (e.g., in `config`)
+     111             :     // to ensure that the libraries live long enough.
+     112           0 :     fn new(paths: Vec<PathBuf>) -> Self {
+     113           0 :         let mut loaded_libs = Vec::new();
+     114           0 :         for path in paths {
+     115           0 :             unsafe {
+     116           0 :                 // smoelius: `libloading` does not define `RTLD_NODELETE`.
+     117           0 :                 #[cfg(unix)]
+     118           0 :                 let result = libloading::os::unix::Library::open(
+     119           0 :                     Some(&path),
+     120           0 :                     libloading::os::unix::RTLD_LAZY
+     121           0 :                         | libloading::os::unix::RTLD_LOCAL
+     122           0 :                         | libc::RTLD_NODELETE,
+     123           0 :                 )
+     124           0 :                 .map(Into::into);
+     125           0 : 
+     126           0 :                 #[cfg(not(unix))]
+     127           0 :                 let result = libloading::Library::new(&path);
+     128           0 : 
+     129           0 :                 let lib = result.unwrap_or_else(|err| {
+     130           0 :                     // smoelius: rust-lang/rust#111633 changed the type of `early_error`'s `msg`
+     131           0 :                     // argument from `&str` to `impl Into<DiagnosticMessage>`.
+     132           0 :                     // smoelius: And rust-lang/rust#111748 made it that `msg` is borrowed for
+     133           0 :                     // `'static`. Since the program is about to exit, it's probably fine to leak the
+     134           0 :                     // string.
+     135           0 :                     let msg = format!(
+     136           0 :                         "could not load library `{}`: {}",
+     137           0 :                         path.to_string_lossy(),
+     138           0 :                         err
+     139           0 :                     );
+     140           0 :                     early_error(msg);
+     141           0 :                 });
+     142           0 : 
+     143           0 :                 loaded_libs.push(LoadedLibrary { path, lib });
+     144           0 :             }
+     145             :         }
+     146           0 :         Self { loaded_libs }
+     147           0 :     }
+     148             : }
+     149             : 
+     150             : #[rustversion::before(2023-06-28)]
+     151             : fn early_error(msg: String) -> ! {
+     152             :     rustc_session::early_error(
+     153             :         rustc_session::config::ErrorOutputType::default(),
+     154             :         Box::leak(msg.into_boxed_str()) as &str,
+     155             :     )
+     156             : }
+     157             : 
+     158             : #[rustversion::since(2023-06-28)]
+     159             : extern crate rustc_errors;
+     160             : 
+     161             : #[rustversion::all(since(2023-06-28), before(2023-12-18))]
+     162             : fn early_error(msg: impl Into<rustc_errors::DiagnosticMessage>) -> ! {
+     163             :     let handler =
+     164             :         rustc_session::EarlyErrorHandler::new(rustc_session::config::ErrorOutputType::default());
+     165             :     handler.early_error(msg)
+     166             : }
+     167             : 
+     168             : #[rustversion::all(since(2023-12-18), before(2023-12-23))]
+     169             : fn early_error(msg: impl Into<rustc_errors::DiagnosticMessage>) -> ! {
+     170             :     let handler =
+     171             :         rustc_session::EarlyDiagCtxt::new(rustc_session::config::ErrorOutputType::default());
+     172             :     handler.early_error(msg)
+     173             : }
+     174             : 
+     175             : #[rustversion::all(since(2023-12-23), before(2024-03-05))]
+     176             : fn early_error(msg: impl Into<rustc_errors::DiagnosticMessage>) -> ! {
+     177             :     let handler =
+     178             :         rustc_session::EarlyDiagCtxt::new(rustc_session::config::ErrorOutputType::default());
+     179             :     handler.early_fatal(msg)
+     180             : }
+     181             : 
+     182             : #[rustversion::since(2024-03-05)]
+     183           0 : fn early_error(msg: impl Into<rustc_errors::DiagMessage>) -> ! {
+     184           0 :     let handler =
+     185           0 :         rustc_session::EarlyDiagCtxt::new(rustc_session::config::ErrorOutputType::default());
+     186           0 :     handler.early_fatal(msg)
+     187             : }
+     188             : 
+     189             : trait ParseSess {
+     190             :     fn parse_sess(&self) -> &rustc_session::parse::ParseSess;
+     191             : }
+     192             : 
+     193             : impl ParseSess for rustc_session::Session {
+     194             :     #[rustversion::before(2024-03-05)]
+     195             :     fn parse_sess(&self) -> &rustc_session::parse::ParseSess {
+     196             :         &self.parse_sess
+     197             :     }
+     198             : 
+     199             :     #[rustversion::since(2024-03-05)]
+     200           0 :     fn parse_sess(&self) -> &rustc_session::parse::ParseSess {
+     201           0 :         &self.psess
+     202           0 :     }
+     203             : }
+     204             : 
+     205             : #[rustversion::before(2022-07-14)]
+     206             : fn zero_mir_opt_level(config: &mut rustc_interface::Config) {
+     207             :     trait Zeroable {
+     208             :         fn zero(&mut self);
+     209             :     }
+     210             : 
+     211             :     impl Zeroable for usize {
+     212             :         fn zero(&mut self) {
+     213             :             *self = 0;
+     214             :         }
+     215             :     }
+     216             : 
+     217             :     impl Zeroable for Option<usize> {
+     218             :         fn zero(&mut self) {
+     219             :             *self = Some(0);
+     220             :         }
+     221             :     }
+     222             : 
+     223             :     // smoelius: `Zeroable` is a hack to make the next line compile for different Rust versions:
+     224             :     // https://github.com/rust-lang/rust-clippy/commit/0941fc0bb5d655cdd0816f862af8cfe70556dad6
+     225             :     config.opts.debugging_opts.mir_opt_level.zero();
+     226             : }
+     227             : 
+     228             : // smoelius: Relevant PR and merge commit:
+     229             : // - https://github.com/rust-lang/rust/pull/98975
+     230             : // - https://github.com/rust-lang/rust/commit/0ed9c64c3e63acac9bd77abce62501696c390450
+     231             : #[rustversion::since(2022-07-14)]
+     232           0 : fn zero_mir_opt_level(config: &mut rustc_interface::Config) {
+     233           0 :     config.opts.unstable_opts.mir_opt_level = Some(0);
+     234           0 : }
+     235             : 
+     236             : impl rustc_driver::Callbacks for Callbacks {
+     237           0 :     fn config(&mut self, config: &mut rustc_interface::Config) {
+     238           0 :         let previous = config.register_lints.take();
+     239           0 :         let loaded_libs = self.loaded_libs.split_off(0);
+     240           0 :         config.register_lints = Some(Box::new(move |sess, lint_store| {
+     241           0 :             if let Some(previous) = &previous {
+     242           0 :                 previous(sess, lint_store);
+     243           0 :             }
+     244             : 
+     245           0 :             let dylint_libs = env::var(env::DYLINT_LIBS).ok();
+     246           0 :             let dylint_metadata = env::var(env::DYLINT_METADATA).ok();
+     247           0 :             let dylint_no_deps = env::var(env::DYLINT_NO_DEPS).ok();
+     248           0 :             let dylint_no_deps_enabled =
+     249           0 :                 dylint_no_deps.as_ref().map_or(false, |value| value != "0");
+     250           0 :             let cargo_primary_package_is_set = env::var(env::CARGO_PRIMARY_PACKAGE).is_ok();
+     251           0 : 
+     252           0 :             sess.parse_sess().env_depinfo.lock().insert((
+     253           0 :                 rustc_span::Symbol::intern(env::DYLINT_LIBS),
+     254           0 :                 dylint_libs.as_deref().map(rustc_span::Symbol::intern),
+     255           0 :             ));
+     256           0 :             sess.parse_sess().env_depinfo.lock().insert((
+     257           0 :                 rustc_span::Symbol::intern(env::DYLINT_METADATA),
+     258           0 :                 dylint_metadata.as_deref().map(rustc_span::Symbol::intern),
+     259           0 :             ));
+     260           0 :             sess.parse_sess().env_depinfo.lock().insert((
+     261           0 :                 rustc_span::Symbol::intern(env::DYLINT_NO_DEPS),
+     262           0 :                 dylint_no_deps.as_deref().map(rustc_span::Symbol::intern),
+     263           0 :             ));
+     264           0 : 
+     265           0 :             if dylint_no_deps_enabled && !cargo_primary_package_is_set {
+     266           0 :                 return;
+     267           0 :             }
+     268           0 : 
+     269           0 :             let mut before = BTreeSet::<Lint>::new();
+     270           0 :             if list_enabled() {
+     271           0 :                 lint_store.get_lints().iter().for_each(|&lint| {
+     272           0 :                     before.insert(lint.into());
+     273           0 :                 });
+     274           0 :             }
+     275           0 :             for loaded_lib in &loaded_libs {
+     276           0 :                 if let Some(path) = loaded_lib.path.to_str() {
+     277           0 :                     sess.parse_sess()
+     278           0 :                         .file_depinfo
+     279           0 :                         .lock()
+     280           0 :                         .insert(rustc_span::Symbol::intern(path));
+     281           0 :                 }
+     282           0 :                 loaded_lib.register_lints(sess, lint_store);
+     283             :             }
+     284           0 :             if list_enabled() {
+     285           0 :                 let mut after = BTreeSet::<Lint>::new();
+     286           0 :                 lint_store.get_lints().iter().for_each(|&lint| {
+     287           0 :                     after.insert(lint.into());
+     288           0 :                 });
+     289           0 :                 list_lints(&before, &after);
+     290           0 :                 std::process::exit(0);
+     291           0 :             }
+     292           0 :         }));
+     293           0 : 
+     294           0 :         // smoelius: Choose to be compatible with Clippy:
+     295           0 :         // https://github.com/rust-lang/rust-clippy/commit/7bae5bd828e98af9d245b77118c075a7f1a036b9
+     296           0 :         zero_mir_opt_level(config);
+     297           0 :     }
+     298             : }
+     299             : 
+     300             : #[must_use]
+     301           0 : fn list_enabled() -> bool {
+     302           0 :     env::var(env::DYLINT_LIST).map_or(false, |value| value != "0")
+     303           0 : }
+     304             : 
+     305           0 : fn list_lints(before: &BTreeSet<Lint>, after: &BTreeSet<Lint>) {
+     306           0 :     let difference: Vec<Lint> = after.difference(before).cloned().collect();
+     307           0 : 
+     308           0 :     let name_width = difference
+     309           0 :         .iter()
+     310           0 :         .map(|lint| lint.name.len())
+     311           0 :         .max()
+     312           0 :         .unwrap_or_default();
+     313           0 : 
+     314           0 :     let level_width = difference
+     315           0 :         .iter()
+     316           0 :         .map(|lint| lint.level.as_str().len())
+     317           0 :         .max()
+     318           0 :         .unwrap_or_default();
+     319             : 
+     320           0 :     for Lint { name, level, desc } in difference {
+     321           0 :         println!(
+     322           0 :             "    {:<name_width$}    {:<level_width$}    {}",
+     323           0 :             name.to_lowercase(),
+     324           0 :             level.as_str(),
+     325           0 :             desc,
+     326           0 :             name_width = name_width,
+     327           0 :             level_width = level_width
+     328           0 :         );
+     329           0 :     }
+     330           0 : }
+     331             : 
+     332           0 : pub fn dylint_driver<T: AsRef<OsStr>>(args: &[T]) -> Result<()> {
+     333           0 :     if args.len() <= 1 || args.iter().any(|arg| arg.as_ref() == "-V") {
+     334           0 :         println!("{} {}", env!("RUSTUP_TOOLCHAIN"), env!("CARGO_PKG_VERSION"));
+     335           0 :         return Ok(());
+     336           0 :     }
+     337           0 : 
+     338           0 :     run(&args[1..])
+     339           0 : }
+     340             : 
+     341           0 : pub fn run<T: AsRef<OsStr>>(args: &[T]) -> Result<()> {
+     342           0 :     let sysroot = sysroot().ok();
+     343           0 :     let rustflags = rustflags();
+     344           0 :     let paths = paths();
+     345             : 
+     346           0 :     let rustc_args = rustc_args(args, &sysroot, &rustflags, &paths)?;
+     347             : 
+     348           0 :     let mut callbacks = Callbacks::new(paths);
+     349           0 : 
+     350           0 :     // smoelius: I am not sure that this should be here. `RUST_LOG=debug cargo test` fails because
+     351           0 :     // of the log messages.
+     352           0 :     log::debug!("{:?}", rustc_args);
+     353             : 
+     354           0 :     rustc_driver::RunCompiler::new(&rustc_args, &mut callbacks)
+     355           0 :         .run()
+     356           0 :         .map_err(|_| std::process::exit(1))
+     357           0 : }
+     358             : 
+     359           0 : fn sysroot() -> Result<PathBuf> {
+     360           0 :     let rustup_home = env::var(env::RUSTUP_HOME)?;
+     361           0 :     let rustup_toolchain = env::var(env::RUSTUP_TOOLCHAIN)?;
+     362           0 :     Ok(PathBuf::from(rustup_home)
+     363           0 :         .join("toolchains")
+     364           0 :         .join(rustup_toolchain))
+     365           0 : }
+     366             : 
+     367           0 : fn rustflags() -> Vec<String> {
+     368           0 :     env::var(env::DYLINT_RUSTFLAGS).map_or_else(
+     369           0 :         |_| Vec::new(),
+     370           0 :         |rustflags| rustflags.split_whitespace().map(String::from).collect(),
+     371           0 :     )
+     372           0 : }
+     373             : 
+     374           0 : fn paths() -> Vec<PathBuf> {
+     375           0 :     (|| -> Result<_> {
+     376           0 :         let dylint_libs = env::var(env::DYLINT_LIBS)?;
+     377           0 :         serde_json::from_str(&dylint_libs).map_err(Into::into)
+     378           0 :     })()
+     379           0 :     .unwrap_or_default()
+     380           0 : }
+     381             : 
+     382           3 : fn rustc_args<T: AsRef<OsStr>, U: AsRef<str>, V: AsRef<Path>>(
+     383           3 :     args: &[T],
+     384           3 :     sysroot: &Option<PathBuf>,
+     385           3 :     rustflags: &[U],
+     386           3 :     paths: &[V],
+     387           3 : ) -> Result<Vec<String>> {
+     388           3 :     let mut args = args.iter().peekable();
+     389           3 :     let mut rustc_args = Vec::new();
+     390           3 : 
+     391           3 :     let first_arg = args.peek();
+     392           3 :     if first_arg.map_or(true, |arg| !is_rustc(arg)) {
+     393           1 :         rustc_args.push("rustc".to_owned());
+     394           2 :     }
+     395           3 :     if let Some(arg) = first_arg {
+     396           3 :         if is_rustc(arg) {
+     397           2 :             rustc_args.push(arg.as_ref().to_string_lossy().to_string());
+     398           2 :             let _ = args.next();
+     399           2 :         }
+     400           0 :     }
+     401           3 :     if let Some(sysroot) = sysroot {
+     402           0 :         rustc_args.extend([
+     403           0 :             "--sysroot".to_owned(),
+     404           0 :             sysroot.to_string_lossy().to_string(),
+     405           0 :         ]);
+     406           3 :     }
+     407           3 :     for path in paths {
+     408           0 :         if let Some((name, _)) = parse_path_filename(path.as_ref()) {
+     409           0 :             rustc_args.push(format!(r#"--cfg=dylint_lib="{name}""#));
+     410           0 :         } else {
+     411           0 :             bail!("could not parse `{}`", path.as_ref().to_string_lossy());
+     412             :         }
+     413             :     }
+     414           6 :     rustc_args.extend(args.map(|s| s.as_ref().to_string_lossy().to_string()));
+     415           3 :     rustc_args.extend(
+     416           3 :         rustflags
+     417           3 :             .iter()
+     418           3 :             .map(|rustflag| rustflag.as_ref().to_owned()),
+     419           3 :     );
+     420           3 : 
+     421           3 :     Ok(rustc_args)
+     422           3 : }
+     423             : 
+     424             : #[expect(clippy::unwrap_used)]
+     425             : #[cfg(test)]
+     426             : mod test {
+     427             :     use super::*;
+     428             :     use rustc_version::{version_meta, Channel};
+     429             : 
+     430             :     #[test]
+     431           1 :     fn channel_is_nightly() {
+     432           1 :         assert!(matches!(version_meta().unwrap().channel, Channel::Nightly));
+     433           1 :     }
+     434             : 
+     435             :     #[test]
+     436           1 :     fn no_rustc() {
+     437           1 :         assert_eq!(
+     438           1 :             rustc_args(
+     439           1 :                 &["--crate-name", "name"],
+     440           1 :                 &None,
+     441           1 :                 &[] as &[&str],
+     442           1 :                 &[] as &[&Path]
+     443           1 :             )
+     444           1 :             .unwrap(),
+     445           1 :             vec!["rustc", "--crate-name", "name"]
+     446           1 :         );
+     447           1 :     }
+     448             : 
+     449             :     #[test]
+     450           1 :     fn plain_rustc() {
+     451           1 :         assert_eq!(
+     452           1 :             rustc_args(
+     453           1 :                 &["rustc", "--crate-name", "name"],
+     454           1 :                 &None,
+     455           1 :                 &[] as &[&str],
+     456           1 :                 &[] as &[&Path]
+     457           1 :             )
+     458           1 :             .unwrap(),
+     459           1 :             vec!["rustc", "--crate-name", "name"]
+     460           1 :         );
+     461           1 :     }
+     462             : 
+     463             :     #[test]
+     464           1 :     fn qualified_rustc() {
+     465           1 :         assert_eq!(
+     466           1 :             rustc_args(
+     467           1 :                 &["/bin/rustc", "--crate-name", "name"],
+     468           1 :                 &None,
+     469           1 :                 &[] as &[&str],
+     470           1 :                 &[] as &[&Path]
+     471           1 :             )
+     472           1 :             .unwrap(),
+     473           1 :             vec!["/bin/rustc", "--crate-name", "name"]
+     474           1 :         );
+     475           1 :     }
+     476             : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint-link/src/index-sort-f.html b/coverage/dylint-link/src/index-sort-f.html new file mode 100644 index 000000000..62cb00044 --- /dev/null +++ b/coverage/dylint-link/src/index-sort-f.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - unnamed - dylint-link/src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint-link/srcHitTotalCoverage
Test:unnamedLines:8418046.7 %
Date:2024-09-27 12:58:08Functions:52420.8 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
main.rs +
46.7%46.7%
+
46.7 %84 / 18020.8 %5 / 24
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint-link/src/index-sort-l.html b/coverage/dylint-link/src/index-sort-l.html new file mode 100644 index 000000000..df148f71c --- /dev/null +++ b/coverage/dylint-link/src/index-sort-l.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - unnamed - dylint-link/src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint-link/srcHitTotalCoverage
Test:unnamedLines:8418046.7 %
Date:2024-09-27 12:58:08Functions:52420.8 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
main.rs +
46.7%46.7%
+
46.7 %84 / 18020.8 %5 / 24
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint-link/src/index.html b/coverage/dylint-link/src/index.html new file mode 100644 index 000000000..c72c7ae8e --- /dev/null +++ b/coverage/dylint-link/src/index.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - unnamed - dylint-link/src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint-link/srcHitTotalCoverage
Test:unnamedLines:8418046.7 %
Date:2024-09-27 12:58:08Functions:52420.8 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
main.rs +
46.7%46.7%
+
46.7 %84 / 18020.8 %5 / 24
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint-link/src/main.rs.func-sort-c.html b/coverage/dylint-link/src/main.rs.func-sort-c.html new file mode 100644 index 000000000..722900e0e --- /dev/null +++ b/coverage/dylint-link/src/main.rs.func-sort-c.html @@ -0,0 +1,168 @@ + + + + + + + LCOV - unnamed - dylint-link/src/main.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint-link/src - main.rs (source / functions)HitTotalCoverage
Test:unnamedLines:8418046.7 %
Date:2024-09-27 12:58:08Functions:52420.8 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint_link::copy_library0
dylint_link::copy_library::{closure#0}0
dylint_link::copy_library::{closure#1}0
dylint_link::default_linker0
dylint_link::linker0
dylint_link::linker::{closure#0}0
dylint_link::linker::{closure#1}0
dylint_link::linker::{closure#2}0
dylint_link::linker::{closure#3}0
dylint_link::linker::{closure#4}0
dylint_link::linker::{closure#5}0
dylint_link::linker::{closure#6}0
dylint_link::main0
dylint_link::output_path::<_>0
dylint_link::parse_path_plain_filename0
dylint_link::parse_toolchain0
dylint_link::parse_toolchain::{closure#0}0
dylint_link::parse_toolchain::{closure#1}0
dylint_link::strip_deps0
dylint_link::test::architectures_are_current1
dylint_link::test::architectures_are_sorted1
dylint_link::test::global_config1
dylint_link::test::architectures_are_current::{closure#0}247
dylint_link::test::architectures_are_current::{closure#0}::{closure#0}247
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint-link/src/main.rs.func.html b/coverage/dylint-link/src/main.rs.func.html new file mode 100644 index 000000000..786c8c29e --- /dev/null +++ b/coverage/dylint-link/src/main.rs.func.html @@ -0,0 +1,168 @@ + + + + + + + LCOV - unnamed - dylint-link/src/main.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint-link/src - main.rs (source / functions)HitTotalCoverage
Test:unnamedLines:8418046.7 %
Date:2024-09-27 12:58:08Functions:52420.8 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint_link::copy_library0
dylint_link::copy_library::{closure#0}0
dylint_link::copy_library::{closure#1}0
dylint_link::default_linker0
dylint_link::linker0
dylint_link::linker::{closure#0}0
dylint_link::linker::{closure#1}0
dylint_link::linker::{closure#2}0
dylint_link::linker::{closure#3}0
dylint_link::linker::{closure#4}0
dylint_link::linker::{closure#5}0
dylint_link::linker::{closure#6}0
dylint_link::main0
dylint_link::output_path::<_>0
dylint_link::parse_path_plain_filename0
dylint_link::parse_toolchain0
dylint_link::parse_toolchain::{closure#0}0
dylint_link::parse_toolchain::{closure#1}0
dylint_link::strip_deps0
dylint_link::test::architectures_are_current1
dylint_link::test::architectures_are_current::{closure#0}247
dylint_link::test::architectures_are_current::{closure#0}::{closure#0}247
dylint_link::test::architectures_are_sorted1
dylint_link::test::global_config1
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint-link/src/main.rs.gcov.html b/coverage/dylint-link/src/main.rs.gcov.html new file mode 100644 index 000000000..2662e2a5b --- /dev/null +++ b/coverage/dylint-link/src/main.rs.gcov.html @@ -0,0 +1,461 @@ + + + + + + + LCOV - unnamed - dylint-link/src/main.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint-link/src - main.rs (source / functions)HitTotalCoverage
Test:unnamedLines:8418046.7 %
Date:2024-09-27 12:58:08Functions:52420.8 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #![deny(clippy::expect_used)]
+       2             : #![deny(clippy::unwrap_used)]
+       3             : #![deny(clippy::panic)]
+       4             : 
+       5             : #[cfg(target_os = "windows")]
+       6             : use anyhow::ensure;
+       7             : use anyhow::{anyhow, Context, Result};
+       8             : use dylint_internal::{cargo::cargo_home, env, library_filename, CommandExt};
+       9             : use if_chain::if_chain;
+      10             : use std::{
+      11             :     env::{args, consts},
+      12             :     ffi::OsStr,
+      13             :     fs::{copy, read_to_string},
+      14             :     path::{Path, PathBuf},
+      15             :     process::Command,
+      16             : };
+      17             : #[cfg(target_os = "windows")]
+      18             : use std::{fs::File, io::Read};
+      19             : use toml_edit::{DocumentMut, Item};
+      20             : 
+      21           0 : fn main() -> Result<()> {
+      22           0 :     env_logger::init();
+      23             : 
+      24           0 :     let linker = linker()?;
+      25           0 :     let args: Vec<String> = args().collect();
+      26           0 :     Command::new(linker).args(&args[1..]).success()?;
+      27             : 
+      28           0 :     if let Some(path) = output_path(args.iter())? {
+      29           0 :         copy_library(&path)?;
+      30           0 :     }
+      31             : 
+      32           0 :     Ok(())
+      33           0 : }
+      34             : 
+      35           0 : fn linker() -> Result<PathBuf> {
+      36           0 :     let rustup_toolchain = env::var(env::RUSTUP_TOOLCHAIN)?;
+      37           0 :     let target = parse_toolchain(&rustup_toolchain)
+      38           0 :         .map_or_else(|| env!("TARGET").to_owned(), |(_, target)| target);
+      39           0 :     let cargo_home = cargo_home().with_context(|| "Could not determine `CARGO_HOME`")?;
+      40           0 :     let config_toml = cargo_home.join("config.toml");
+      41           0 :     if config_toml.is_file() {
+      42           0 :         let contents = read_to_string(&config_toml).with_context(|| {
+      43           0 :             format!(
+      44           0 :                 "`read_to_string` failed for `{}`",
+      45           0 :                 config_toml.to_string_lossy()
+      46           0 :             )
+      47           0 :         })?;
+      48           0 :         let document = contents.parse::<DocumentMut>()?;
+      49           0 :         document
+      50           0 :             .as_table()
+      51           0 :             .get("target")
+      52           0 :             .and_then(Item::as_table)
+      53           0 :             .and_then(|table| table.get(&target))
+      54           0 :             .and_then(Item::as_table)
+      55           0 :             .and_then(|table| table.get("linker"))
+      56           0 :             .and_then(Item::as_str)
+      57           0 :             .map_or_else(default_linker, |s| Ok(PathBuf::from(s)))
+      58             :     } else {
+      59           0 :         default_linker()
+      60             :     }
+      61           0 : }
+      62             : 
+      63             : #[cfg(target_os = "windows")]
+      64             : fn default_linker() -> Result<PathBuf> {
+      65             :     let rustup_toolchain = env::var(env::RUSTUP_TOOLCHAIN)?;
+      66             :     if rustup_toolchain.split('-').last() == Some("msvc") {
+      67             :         // MinerSebas: Removes the Release Information: "nightly-2021-04-08-x86_64-pc-windows-msvc"
+      68             :         // -> "x86_64-pc-windows-msvc"
+      69             :         // smoelius: The approach has changed slightly.
+      70             :         if let Some(tool) = parse_toolchain(&rustup_toolchain)
+      71             :             .and_then(|(_, target)| cc::windows_registry::find_tool(&target, "link.exe"))
+      72             :         {
+      73             :             Ok(tool.path().into())
+      74             :         } else {
+      75             :             Err(anyhow!("Could not find the MSVC Linker"))
+      76             :         }
+      77             :     } else {
+      78             :         Err(anyhow!("Only the MSVC toolchain is supported on Windows"))
+      79             :     }
+      80             : }
+      81             : 
+      82             : #[cfg(not(target_os = "windows"))]
+      83             : #[allow(clippy::unnecessary_wraps)]
+      84           0 : fn default_linker() -> Result<PathBuf> {
+      85           0 :     Ok(PathBuf::from("cc"))
+      86           0 : }
+      87             : 
+      88             : #[cfg(target_os = "windows")]
+      89             : fn output_path<'a, I>(iter: I) -> Result<Option<PathBuf>>
+      90             : where
+      91             :     I: Iterator<Item = &'a String>,
+      92             : {
+      93             :     for arg in iter {
+      94             :         if let Some(path) = arg.strip_prefix("/OUT:") {
+      95             :             return Ok(Some(path.into()));
+      96             :         }
+      97             :         if let Some(path) = arg.strip_prefix('@') {
+      98             :             return extract_out_path_from_linker_response_file(path);
+      99             :         }
+     100             :     }
+     101             : 
+     102             :     Ok(None)
+     103             : }
+     104             : 
+     105             : #[cfg(not(target_os = "windows"))]
+     106             : #[allow(clippy::unnecessary_wraps)]
+     107           0 : fn output_path<'a, I>(mut iter: I) -> Result<Option<PathBuf>>
+     108           0 : where
+     109           0 :     I: Iterator<Item = &'a String>,
+     110           0 : {
+     111           0 :     while let Some(arg) = iter.next() {
+     112           0 :         if arg == "-o" {
+     113           0 :             if let Some(path) = iter.next() {
+     114           0 :                 return Ok(Some(path.into()));
+     115           0 :             }
+     116           0 :         }
+     117             :     }
+     118             : 
+     119           0 :     Ok(None)
+     120           0 : }
+     121             : 
+     122             : #[cfg(target_os = "windows")]
+     123             : fn extract_out_path_from_linker_response_file(path: impl AsRef<Path>) -> Result<Option<PathBuf>> {
+     124             :     // MinerSebas: On Windows the cmd line has a Limit of 8191 Characters.
+     125             :     // If your command would exceed this you can instead use a Linker Response File to set
+     126             :     // arguments. (https://docs.microsoft.com/en-us/cpp/build/reference/at-specify-a-linker-response-file?view=msvc-160)
+     127             : 
+     128             :     // MinerSebas: Read the Linker Response File
+     129             :     let mut buf: Vec<u8> = Vec::new();
+     130             :     File::open(path)?.read_to_end(&mut buf)?;
+     131             : 
+     132             :     // MinerSebas: Convert the File from UTF-16 to a Rust UTF-8 String
+     133             :     // (Only necessary for MSVC, the GNU Linker uses UTF-8 isntead.)
+     134             :     // Based on: https://stackoverflow.com/a/57172592
+     135             :     let file: Vec<u16> = buf
+     136             :         .chunks_exact(2)
+     137             :         .into_iter()
+     138             :         .map(|a| u16::from_ne_bytes([a[0], a[1]]))
+     139             :         .collect();
+     140             :     let file = String::from_utf16_lossy(file.as_slice());
+     141             : 
+     142             :     let paths: Vec<_> = file
+     143             :         .lines()
+     144             :         .flat_map(|line| line.trim().trim_matches('"').strip_prefix("/OUT:"))
+     145             :         .collect();
+     146             : 
+     147             :     ensure!(paths.len() <= 1, "Found multiple output paths");
+     148             : 
+     149             :     // smoelius: Do not raise an error if no output path is found.
+     150             :     Ok(paths.last().map(Into::into))
+     151             : }
+     152             : 
+     153           0 : fn copy_library(path: &Path) -> Result<()> {
+     154           0 :     if_chain! {
+     155           0 :         if let Some(lib_name) = parse_path_plain_filename(path);
+     156           0 :         let cargo_pkg_name = env::var(env::CARGO_PKG_NAME)?;
+     157           0 :         if lib_name == cargo_pkg_name.replace('-', "_");
+     158             :         then {
+     159           0 :             let rustup_toolchain = env::var(env::RUSTUP_TOOLCHAIN)?;
+     160           0 :             let filename_with_toolchain = library_filename(&lib_name, &rustup_toolchain);
+     161           0 :             let parent = path
+     162           0 :                 .parent()
+     163           0 :                 .ok_or_else(|| anyhow!("Could not get parent directory"))?;
+     164           0 :             let path_with_toolchain = strip_deps(parent).join(filename_with_toolchain);
+     165           0 :             copy(path, &path_with_toolchain).with_context(|| {
+     166           0 :                 format!(
+     167           0 :                     "Could not copy `{}` to `{}`",
+     168           0 :                     path.to_string_lossy(),
+     169           0 :                     path_with_toolchain.to_string_lossy()
+     170           0 :                 )
+     171           0 :             })?;
+     172             :         }
+     173             :     }
+     174             : 
+     175           0 :     Ok(())
+     176           0 : }
+     177             : 
+     178             : // smoelius: I do not know what the right/best way to parse a toolchain is. `parse_toolchain` does
+     179             : // so by looking for the architecture.
+     180           0 : fn parse_toolchain(toolchain: &str) -> Option<(String, String)> {
+     181           0 :     let split_toolchain: Vec<_> = toolchain.split('-').collect();
+     182           0 :     split_toolchain
+     183           0 :         .iter()
+     184           0 :         .rposition(|s| ARCHITECTURES.binary_search(s).is_ok())
+     185           0 :         .map(|i| {
+     186           0 :             (
+     187           0 :                 split_toolchain[..i].join("-"),
+     188           0 :                 split_toolchain[i..].join("-"),
+     189           0 :             )
+     190           0 :         })
+     191           0 : }
+     192             : 
+     193           0 : fn parse_path_plain_filename(path: &Path) -> Option<String> {
+     194           0 :     let filename = path.file_name()?;
+     195           0 :     let s = filename.to_string_lossy();
+     196           0 :     let file_stem = s.strip_suffix(consts::DLL_SUFFIX)?;
+     197           0 :     let lib_name = file_stem.strip_prefix(consts::DLL_PREFIX)?;
+     198           0 :     Some(lib_name.to_owned())
+     199           0 : }
+     200             : 
+     201           0 : fn strip_deps(path: &Path) -> PathBuf {
+     202           0 :     if path.file_name() == Some(OsStr::new("deps")) {
+     203           0 :         path.parent()
+     204             :     } else {
+     205           0 :         None
+     206             :     }
+     207           0 :     .unwrap_or(path)
+     208           0 :     .to_path_buf()
+     209           0 : }
+     210             : 
+     211             : // smoelius: `ARCHITECTURES` is based on: https://doc.rust-lang.org/rustc/platform-support.html
+     212             : const ARCHITECTURES: &[&str] = &[
+     213             :     "aarch64",
+     214             :     "aarch64_be",
+     215             :     "arm",
+     216             :     "arm64_32",
+     217             :     "arm64e",
+     218             :     "arm64ec",
+     219             :     "armeb",
+     220             :     "armebv7r",
+     221             :     "armv4t",
+     222             :     "armv5te",
+     223             :     "armv6",
+     224             :     "armv6k",
+     225             :     "armv7",
+     226             :     "armv7a",
+     227             :     "armv7k",
+     228             :     "armv7r",
+     229             :     "armv7s",
+     230             :     "armv8r",
+     231             :     "avr",
+     232             :     "bpfeb",
+     233             :     "bpfel",
+     234             :     "csky",
+     235             :     "hexagon",
+     236             :     "i386",
+     237             :     "i586",
+     238             :     "i686",
+     239             :     "loongarch64",
+     240             :     "m68k",
+     241             :     "mips",
+     242             :     "mips64",
+     243             :     "mips64el",
+     244             :     "mipsel",
+     245             :     "mipsisa32r6",
+     246             :     "mipsisa32r6el",
+     247             :     "mipsisa64r6",
+     248             :     "mipsisa64r6el",
+     249             :     "msp430",
+     250             :     "nvptx64",
+     251             :     "powerpc",
+     252             :     "powerpc64",
+     253             :     "powerpc64le",
+     254             :     "riscv32gc",
+     255             :     "riscv32i",
+     256             :     "riscv32im",
+     257             :     "riscv32ima",
+     258             :     "riscv32imac",
+     259             :     "riscv32imafc",
+     260             :     "riscv32imc",
+     261             :     "riscv64",
+     262             :     "riscv64gc",
+     263             :     "riscv64imac",
+     264             :     "s390x",
+     265             :     "sparc",
+     266             :     "sparc64",
+     267             :     "sparcv9",
+     268             :     "thumbv4t",
+     269             :     "thumbv5te",
+     270             :     "thumbv6m",
+     271             :     "thumbv7a",
+     272             :     "thumbv7em",
+     273             :     "thumbv7m",
+     274             :     "thumbv7neon",
+     275             :     "thumbv8m.base",
+     276             :     "thumbv8m.main",
+     277             :     "wasm32",
+     278             :     "wasm64",
+     279             :     "x86_64",
+     280             :     "x86_64h",
+     281             :     "xtensa",
+     282             : ];
+     283             : 
+     284             : #[allow(clippy::unwrap_used)]
+     285             : #[cfg(test)]
+     286             : mod test {
+     287             :     use super::{env, ARCHITECTURES};
+     288             :     use assert_cmd::prelude::*;
+     289             :     use dylint_internal::{packaging::isolate, CommandExt};
+     290             :     use predicates::prelude::*;
+     291             :     use std::fs::{create_dir, write};
+     292             :     use tempfile::{tempdir, tempdir_in};
+     293             : 
+     294             :     #[test]
+     295           1 :     fn architectures_are_current() {
+     296           1 :         let output = std::process::Command::new("rustc")
+     297           1 :             .args(["--print", "target-list"])
+     298           1 :             .unwrap();
+     299           1 :         let mut architectures = std::str::from_utf8(&output.stdout)
+     300           1 :             .unwrap()
+     301           1 :             .lines()
+     302         247 :             .filter_map(|line| line.split_once('-').map(|(architecture, _)| architecture))
+     303           1 :             .collect::<Vec<_>>();
+     304           1 :         architectures.sort_unstable();
+     305           1 :         architectures.dedup();
+     306           1 :         assert_eq!(ARCHITECTURES, architectures);
+     307           1 :     }
+     308             : 
+     309             :     #[test]
+     310           1 :     fn architectures_are_sorted() {
+     311           1 :         let mut architectures = ARCHITECTURES.to_vec();
+     312           1 :         architectures.sort_unstable();
+     313           1 :         architectures.dedup();
+     314           1 :         assert_eq!(ARCHITECTURES, architectures);
+     315           1 :     }
+     316             : 
+     317             :     #[cfg_attr(not(all(target_arch = "x86_64", target_os = "linux")), ignore)]
+     318             :     #[cfg_attr(dylint_lib = "general", allow(non_thread_safe_call_in_test))]
+     319             :     #[test]
+     320           1 :     fn global_config() {
+     321           1 :         let cargo_home = tempdir().unwrap();
+     322           1 :         let package = tempdir_in(".").unwrap();
+     323           1 : 
+     324           1 :         dylint_internal::cargo::build("dylint-link")
+     325           1 :             .build()
+     326           1 :             .current_dir(env!("CARGO_MANIFEST_DIR"))
+     327           1 :             .success()
+     328           1 :             .unwrap();
+     329           1 : 
+     330           1 :         dylint_internal::cargo::init("package `global_config_test`")
+     331           1 :             .build()
+     332           1 :             .current_dir(&package)
+     333           1 :             .args(["--name", "global_config_test"])
+     334           1 :             .success()
+     335           1 :             .unwrap();
+     336           1 : 
+     337           1 :         isolate(package.path()).unwrap();
+     338           1 : 
+     339           1 :         let package_cargo = package.path().join(".cargo");
+     340           1 :         create_dir(&package_cargo).unwrap();
+     341           1 :         write(
+     342           1 :             package_cargo.join("config.toml"),
+     343           1 :             r#"
+     344           1 : [target.x86_64-unknown-linux-gnu]
+     345           1 : linker = "../../target/debug/dylint-link"
+     346           1 : "#,
+     347           1 :         )
+     348           1 :         .unwrap();
+     349           1 : 
+     350           1 :         std::process::Command::new("cargo")
+     351           1 :             .current_dir(&package)
+     352           1 :             .arg("build")
+     353           1 :             .assert()
+     354           1 :             .success();
+     355           1 : 
+     356           1 :         write(
+     357           1 :             cargo_home.path().join("config.toml"),
+     358           1 :             r#"
+     359           1 : [target.x86_64-unknown-linux-gnu]
+     360           1 : linker = "false"
+     361           1 : "#,
+     362           1 :         )
+     363           1 :         .unwrap();
+     364           1 : 
+     365           1 :         std::process::Command::new("cargo")
+     366           1 :             .current_dir(&package)
+     367           1 :             .arg("clean")
+     368           1 :             .assert()
+     369           1 :             .success();
+     370           1 : 
+     371           1 :         std::process::Command::new("cargo")
+     372           1 :             .env(env::CARGO_HOME, cargo_home.path())
+     373           1 :             .env(env::CARGO_TERM_COLOR, "never")
+     374           1 :             .current_dir(&package)
+     375           1 :             .arg("build")
+     376           1 :             .assert()
+     377           1 :             .failure()
+     378           1 :             .stderr(
+     379           1 :                 predicate::str::is_match(
+     380           1 :                     "error: linking with `[^`]*/target/debug/dylint-link` failed",
+     381           1 :                 )
+     382           1 :                 .unwrap(),
+     383           1 :             );
+     384           1 :     }
+     385             : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/driver_builder.rs.func-sort-c.html b/coverage/dylint/src/driver_builder.rs.func-sort-c.html new file mode 100644 index 000000000..dce77d67a --- /dev/null +++ b/coverage/dylint/src/driver_builder.rs.func-sort-c.html @@ -0,0 +1,168 @@ + + + + + + + LCOV - unnamed - dylint/src/driver_builder.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src - driver_builder.rs (source / functions)HitTotalCoverage
Test:unnamedLines:13515885.4 %
Date:2024-09-27 12:58:08Functions:112445.8 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint::driver_builder::build::{closure#0}0
dylint::driver_builder::build::{closure#1}0
dylint::driver_builder::dylint_drivers::{closure#0}0
dylint::driver_builder::dylint_drivers::{closure#1}0
dylint::driver_builder::dylint_drivers::{closure#2}0
dylint::driver_builder::get::{closure#0}0
dylint::driver_builder::initialize::{closure#1}0
dylint::driver_builder::initialize::{closure#2}0
dylint::driver_builder::initialize::{closure#3}0
dylint::driver_builder::initialize::{closure#4}0
dylint::driver_builder::is_outdated::{closure#0}::{closure#1}0
dylint::driver_builder::is_outdated::{closure#0}::{closure#2}0
dylint::driver_builder::is_outdated::{closure#1}0
dylint::driver_builder::test::nightly1
dylint::driver_builder::build6
dylint::driver_builder::cargo_toml6
dylint::driver_builder::initialize6
dylint::driver_builder::initialize::{closure#0}6
dylint::driver_builder::rust_toolchain6
dylint::driver_builder::is_outdated25
dylint::driver_builder::is_outdated::{closure#0}25
dylint::driver_builder::is_outdated::{closure#0}::{closure#0}25
dylint::driver_builder::dylint_drivers30
dylint::driver_builder::get30
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/driver_builder.rs.func.html b/coverage/dylint/src/driver_builder.rs.func.html new file mode 100644 index 000000000..bbe1b1d1f --- /dev/null +++ b/coverage/dylint/src/driver_builder.rs.func.html @@ -0,0 +1,168 @@ + + + + + + + LCOV - unnamed - dylint/src/driver_builder.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src - driver_builder.rs (source / functions)HitTotalCoverage
Test:unnamedLines:13515885.4 %
Date:2024-09-27 12:58:08Functions:112445.8 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint::driver_builder::build6
dylint::driver_builder::build::{closure#0}0
dylint::driver_builder::build::{closure#1}0
dylint::driver_builder::cargo_toml6
dylint::driver_builder::dylint_drivers30
dylint::driver_builder::dylint_drivers::{closure#0}0
dylint::driver_builder::dylint_drivers::{closure#1}0
dylint::driver_builder::dylint_drivers::{closure#2}0
dylint::driver_builder::get30
dylint::driver_builder::get::{closure#0}0
dylint::driver_builder::initialize6
dylint::driver_builder::initialize::{closure#0}6
dylint::driver_builder::initialize::{closure#1}0
dylint::driver_builder::initialize::{closure#2}0
dylint::driver_builder::initialize::{closure#3}0
dylint::driver_builder::initialize::{closure#4}0
dylint::driver_builder::is_outdated25
dylint::driver_builder::is_outdated::{closure#0}25
dylint::driver_builder::is_outdated::{closure#0}::{closure#0}25
dylint::driver_builder::is_outdated::{closure#0}::{closure#1}0
dylint::driver_builder::is_outdated::{closure#0}::{closure#2}0
dylint::driver_builder::is_outdated::{closure#1}0
dylint::driver_builder::rust_toolchain6
dylint::driver_builder::test::nightly1
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/driver_builder.rs.gcov.html b/coverage/dylint/src/driver_builder.rs.gcov.html new file mode 100644 index 000000000..e6cb5a6f9 --- /dev/null +++ b/coverage/dylint/src/driver_builder.rs.gcov.html @@ -0,0 +1,320 @@ + + + + + + + LCOV - unnamed - dylint/src/driver_builder.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src - driver_builder.rs (source / functions)HitTotalCoverage
Test:unnamedLines:13515885.4 %
Date:2024-09-27 12:58:08Functions:112445.8 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : use crate::{error::warn, opts};
+       2             : use anyhow::{anyhow, ensure, Context, Result};
+       3             : use cargo_metadata::MetadataCommand;
+       4             : use dylint_internal::{
+       5             :     driver as dylint_driver, env,
+       6             :     rustup::{toolchain_path, SanitizeEnvironment},
+       7             :     CommandExt,
+       8             : };
+       9             : use semver::Version;
+      10             : use std::{
+      11             :     env::consts,
+      12             :     fs::{copy, create_dir_all, write},
+      13             :     path::{Path, PathBuf},
+      14             : };
+      15             : use tempfile::tempdir;
+      16             : 
+      17             : include!(concat!(env!("OUT_DIR"), "/dylint_driver_manifest_dir.rs"));
+      18             : 
+      19             : const README_TXT: &str = "
+      20             : This directory contains Rust compiler drivers used by Dylint
+      21             : (https://github.com/trailofbits/dylint).
+      22             : 
+      23             : Deleting this directory will cause Dylint to rebuild the drivers
+      24             : the next time it needs them, but will have no ill effects.
+      25             : ";
+      26             : 
+      27           6 : fn cargo_toml(toolchain: &str, dylint_driver_spec: &str) -> String {
+      28           6 :     format!(
+      29           6 :         r#"
+      30           6 : [package]
+      31           6 : name = "dylint_driver-{toolchain}"
+      32           6 : version = "0.1.0"
+      33           6 : edition = "2018"
+      34           6 : 
+      35           6 : [dependencies]
+      36           6 : anyhow = "1.0"
+      37           6 : env_logger = "0.11"
+      38           6 : dylint_driver = {{ {dylint_driver_spec} }}
+      39           6 : "#,
+      40           6 :     )
+      41           6 : }
+      42             : 
+      43           6 : fn rust_toolchain(toolchain: &str) -> String {
+      44           6 :     format!(
+      45           6 :         r#"
+      46           6 : [toolchain]
+      47           6 : channel = "{toolchain}"
+      48           6 : components = ["llvm-tools-preview", "rustc-dev"]
+      49           6 : "#,
+      50           6 :     )
+      51           6 : }
+      52             : 
+      53             : // smoelius: We need `#![feature(rustc_private)]` as it changes `dylib` linking behavior and allows
+      54             : // us to link to `rustc_driver`. See: https://github.com/rust-lang/rust/pull/122362
+      55             : const MAIN_RS: &str = r"
+      56             : #![feature(rustc_private)]
+      57             : 
+      58             : use anyhow::Result;
+      59             : use std::env;
+      60             : use std::ffi::OsString;
+      61             : 
+      62             : pub fn main() -> Result<()> {
+      63             :     env_logger::init();
+      64             : 
+      65             :     let args: Vec<_> = env::args().map(OsString::from).collect();
+      66             : 
+      67             :     dylint_driver::dylint_driver(&args)
+      68             : }
+      69             : ";
+      70             : 
+      71             : #[cfg_attr(
+      72             :     dylint_lib = "question_mark_in_expression",
+      73             :     allow(question_mark_in_expression)
+      74             : )]
+      75          30 : pub fn get(opts: &opts::Dylint, toolchain: &str) -> Result<PathBuf> {
+      76          30 :     let dylint_drivers = dylint_drivers()?;
+      77             : 
+      78          30 :     let driver_dir = dylint_drivers.join(toolchain);
+      79          30 :     if !driver_dir.is_dir() {
+      80           5 :         create_dir_all(&driver_dir).with_context(|| {
+      81           0 :             format!(
+      82           0 :                 "`create_dir_all` failed for `{}`",
+      83           0 :                 driver_dir.to_string_lossy()
+      84           0 :             )
+      85           5 :         })?;
+      86          25 :     }
+      87             : 
+      88          30 :     let driver = driver_dir.join("dylint-driver");
+      89          30 :     if !driver.exists() || is_outdated(opts, toolchain, &driver)? {
+      90           5 :         build(opts, toolchain, &driver)?;
+      91          25 :     }
+      92             : 
+      93          30 :     Ok(driver)
+      94          30 : }
+      95             : 
+      96          30 : fn dylint_drivers() -> Result<PathBuf> {
+      97          30 :     if let Ok(dylint_driver_path) = env::var(env::DYLINT_DRIVER_PATH) {
+      98           0 :         let dylint_drivers = Path::new(&dylint_driver_path);
+      99           0 :         ensure!(dylint_drivers.is_dir());
+     100           0 :         Ok(dylint_drivers.to_path_buf())
+     101             :     } else {
+     102          30 :         let home = dirs::home_dir().ok_or_else(|| anyhow!("Could not find HOME directory"))?;
+     103          30 :         let dylint_drivers = Path::new(&home).join(".dylint_drivers");
+     104          30 :         if !dylint_drivers.is_dir() {
+     105           1 :             create_dir_all(&dylint_drivers).with_context(|| {
+     106           0 :                 format!(
+     107           0 :                     "`create_dir_all` failed for `{}`",
+     108           0 :                     dylint_drivers.to_string_lossy()
+     109           0 :                 )
+     110           1 :             })?;
+     111           1 :             let readme_txt = dylint_drivers.join("README.txt");
+     112           1 :             write(&readme_txt, README_TXT).with_context(|| {
+     113           0 :                 format!("`write` failed for `{}`", readme_txt.to_string_lossy())
+     114           1 :             })?;
+     115          29 :         }
+     116          30 :         Ok(dylint_drivers)
+     117             :     }
+     118          30 : }
+     119             : 
+     120          25 : fn is_outdated(opts: &opts::Dylint, toolchain: &str, driver: &Path) -> Result<bool> {
+     121          25 :     (|| -> Result<bool> {
+     122          25 :         let mut command = dylint_driver(toolchain, driver)?;
+     123          25 :         let output = command.args(["-V"]).logged_output(true)?;
+     124          25 :         let stdout = std::str::from_utf8(&output.stdout)?;
+     125          25 :         let theirs = stdout
+     126          25 :             .trim_end()
+     127          25 :             .rsplit_once(' ')
+     128          25 :             .map(|(_, s)| s)
+     129          25 :             .ok_or_else(|| anyhow!("Could not determine driver version"))?;
+     130             : 
+     131          25 :         let their_version = Version::parse(theirs)
+     132          25 :             .with_context(|| format!("Could not parse driver version `{theirs}`"))?;
+     133             : 
+     134          25 :         let our_version = Version::parse(env!("CARGO_PKG_VERSION"))?;
+     135             : 
+     136          25 :         Ok(their_version < our_version)
+     137          25 :     })()
+     138          25 :     .or_else(|error| {
+     139           0 :         warn(opts, &error.to_string());
+     140           0 :         Ok(true)
+     141          25 :     })
+     142          25 : }
+     143             : 
+     144             : #[cfg_attr(dylint_lib = "supplementary", allow(commented_code))]
+     145           6 : fn build(opts: &opts::Dylint, toolchain: &str, driver: &Path) -> Result<()> {
+     146           6 :     let tempdir = tempdir().with_context(|| "`tempdir` failed")?;
+     147           6 :     let package = tempdir.path();
+     148           6 : 
+     149           6 :     initialize(toolchain, package)?;
+     150             : 
+     151           6 :     let metadata = MetadataCommand::new()
+     152           6 :         .current_dir(package)
+     153           6 :         .no_deps()
+     154           6 :         .exec()?;
+     155             : 
+     156           6 :     let toolchain_path = toolchain_path(package)?;
+     157             : 
+     158             :     // smoelius: The commented code was the old behavior. It would cause the driver to have rpaths
+     159             :     // like `$ORIGIN/../../`... (see https://github.com/trailofbits/dylint/issues/54). The new
+     160             :     // behavior causes the driver to have absolute rpaths.
+     161             :     // let rustflags = "-C rpath=yes";
+     162           6 :     let rustflags = format!(
+     163           6 :         "{} -C link-args=-Wl,-rpath,{}/lib ",
+     164           6 :         env::var("RUSTFLAGS").unwrap_or_default(),
+     165           6 :         toolchain_path.to_string_lossy()
+     166           6 :     );
+     167           6 : 
+     168           6 :     #[cfg(debug_assertions)]
+     169           6 :     if DYLINT_DRIVER_MANIFEST_DIR.is_none() {
+     170           0 :         warn(opts, "In debug mode building driver from `crates.io`");
+     171           6 :     }
+     172             : 
+     173           6 :     dylint_internal::cargo::build(&format!("driver for toolchain `{toolchain}`"))
+     174           6 :         .quiet(opts.quiet)
+     175           6 :         .build()
+     176           6 :         .sanitize_environment()
+     177           6 :         .envs([(env::RUSTFLAGS, rustflags)])
+     178           6 :         .current_dir(package)
+     179           6 :         .success()?;
+     180             : 
+     181           6 :     let binary = metadata
+     182           6 :         .target_directory
+     183           6 :         .join("debug")
+     184           6 :         .join(format!("dylint_driver-{toolchain}{}", consts::EXE_SUFFIX));
+     185           6 :     #[cfg_attr(dylint_lib = "general", allow(non_thread_safe_call_in_test))]
+     186           6 :     copy(&binary, driver).with_context(|| {
+     187           0 :         format!(
+     188           0 :             "Could not copy `{binary}` to `{}`",
+     189           0 :             driver.to_string_lossy()
+     190           0 :         )
+     191           6 :     })?;
+     192             : 
+     193           6 :     Ok(())
+     194           6 : }
+     195             : 
+     196             : // smoelius: `package` is a temporary directory. So there should be no race here.
+     197             : #[cfg_attr(dylint_lib = "general", allow(non_thread_safe_call_in_test))]
+     198           6 : fn initialize(toolchain: &str, package: &Path) -> Result<()> {
+     199           6 :     let version_spec = format!("version = \"={}\"", env!("CARGO_PKG_VERSION"));
+     200           6 : 
+     201           6 :     let path_spec = DYLINT_DRIVER_MANIFEST_DIR.map_or(String::new(), |path| {
+     202           6 :         format!(", path = \"{}\"", path.replace('\\', "\\\\"))
+     203           6 :     });
+     204           6 : 
+     205           6 :     let dylint_driver_spec = format!("{version_spec}{path_spec}");
+     206           6 : 
+     207           6 :     let cargo_toml_path = package.join("Cargo.toml");
+     208           6 :     write(&cargo_toml_path, cargo_toml(toolchain, &dylint_driver_spec))
+     209           6 :         .with_context(|| format!("`write` failed for `{}`", cargo_toml_path.to_string_lossy()))?;
+     210           6 :     let rust_toolchain_path = package.join("rust-toolchain");
+     211           6 :     write(&rust_toolchain_path, rust_toolchain(toolchain)).with_context(|| {
+     212           0 :         format!(
+     213           0 :             "`write` failed for `{}`",
+     214           0 :             rust_toolchain_path.to_string_lossy()
+     215           0 :         )
+     216           6 :     })?;
+     217           6 :     let src = package.join("src");
+     218           6 :     create_dir_all(&src)
+     219           6 :         .with_context(|| format!("`create_dir_all` failed for `{}`", src.to_string_lossy()))?;
+     220           6 :     let main_rs = src.join("main.rs");
+     221           6 :     write(&main_rs, MAIN_RS)
+     222           6 :         .with_context(|| format!("`write` failed for `{}`", main_rs.to_string_lossy()))?;
+     223             : 
+     224           6 :     Ok(())
+     225           6 : }
+     226             : 
+     227             : #[allow(clippy::unwrap_used)]
+     228             : #[cfg(test)]
+     229             : mod test {
+     230             :     use super::*;
+     231             : 
+     232             :     // smoelius: `tempdir` is a temporary directory. So there should be no race here.
+     233             :     #[cfg_attr(dylint_lib = "general", allow(non_thread_safe_call_in_test))]
+     234             :     #[test]
+     235           1 :     fn nightly() {
+     236           1 :         let tempdir = tempdir().unwrap();
+     237           1 :         build(
+     238           1 :             &opts::Dylint::default(),
+     239           1 :             "nightly",
+     240           1 :             &tempdir.path().join("dylint-driver"),
+     241           1 :         )
+     242           1 :         .unwrap();
+     243           1 :     }
+     244             : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/error.rs.func-sort-c.html b/coverage/dylint/src/error.rs.func-sort-c.html new file mode 100644 index 000000000..e1f3278c5 --- /dev/null +++ b/coverage/dylint/src/error.rs.func-sort-c.html @@ -0,0 +1,92 @@ + + + + + + + LCOV - unnamed - dylint/src/error.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src - error.rs (source / functions)HitTotalCoverage
Test:unnamedLines:212487.5 %
Date:2024-09-27 12:58:08Functions:3560.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<dylint::error::ColorizedError<_> as core::fmt::Debug>::fmt0
<dylint::error::ColorizedError<_>>::new0
<dylint::error::ColorizedError<anyhow::Error> as core::fmt::Debug>::fmt9
<dylint::error::ColorizedError<anyhow::Error>>::new9
dylint::error::warn48
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/error.rs.func.html b/coverage/dylint/src/error.rs.func.html new file mode 100644 index 000000000..634e57597 --- /dev/null +++ b/coverage/dylint/src/error.rs.func.html @@ -0,0 +1,92 @@ + + + + + + + LCOV - unnamed - dylint/src/error.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src - error.rs (source / functions)HitTotalCoverage
Test:unnamedLines:212487.5 %
Date:2024-09-27 12:58:08Functions:3560.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<dylint::error::ColorizedError<_> as core::fmt::Debug>::fmt0
<dylint::error::ColorizedError<_>>::new0
<dylint::error::ColorizedError<anyhow::Error> as core::fmt::Debug>::fmt9
<dylint::error::ColorizedError<anyhow::Error>>::new9
dylint::error::warn48
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/error.rs.gcov.html b/coverage/dylint/src/error.rs.gcov.html new file mode 100644 index 000000000..7d3ba05ea --- /dev/null +++ b/coverage/dylint/src/error.rs.gcov.html @@ -0,0 +1,142 @@ + + + + + + + LCOV - unnamed - dylint/src/error.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src - error.rs (source / functions)HitTotalCoverage
Test:unnamedLines:212487.5 %
Date:2024-09-27 12:58:08Functions:3560.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : use ansi_term::{
+       2             :     Color::{Red, Yellow},
+       3             :     Style,
+       4             : };
+       5             : use is_terminal::IsTerminal;
+       6             : use std::io::Write;
+       7             : 
+       8             : // smoelius: `ColorizedError` is currently used only by `cargo-dylint`. But given the similarity of
+       9             : // its implementation to `warn`, I prefer to keep it here for now. Also, FWIW, this limits the
+      10             : // packages that directly depend on `ansi_term`.
+      11             : 
+      12             : #[allow(clippy::module_name_repetitions)]
+      13             : pub struct ColorizedError<E>(E)
+      14             : where
+      15             :     E: std::fmt::Debug;
+      16             : 
+      17             : impl<E> ColorizedError<E>
+      18             : where
+      19             :     E: std::fmt::Debug,
+      20             : {
+      21             :     #[allow(clippy::missing_const_for_fn)]
+      22           9 :     pub fn new(error: E) -> Self {
+      23           9 :         Self(error)
+      24           9 :     }
+      25             : }
+      26             : 
+      27             : // smoelius: The use of `\r` is a bit of a hack, but it works, most notably with `anyhow`
+      28             : // backtraces. Another way might be to implement the `Termination` trait, but that trait is still
+      29             : // unstable: https://github.com/rust-lang/rust/issues/43301
+      30             : impl<E> std::fmt::Debug for ColorizedError<E>
+      31             : where
+      32             :     E: std::fmt::Debug,
+      33             : {
+      34           9 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+      35           9 :         write!(
+      36           9 :             f,
+      37           9 :             "{}{:?}",
+      38           9 :             if std::io::stderr().is_terminal() {
+      39           0 :                 format!("\r{}: ", Red.bold().paint("Error"))
+      40             :             } else {
+      41           9 :                 String::new()
+      42             :             },
+      43             :             self.0
+      44             :         )
+      45           9 :     }
+      46             : }
+      47             : 
+      48             : pub type ColorizedResult<T> = Result<T, ColorizedError<anyhow::Error>>;
+      49             : 
+      50             : #[allow(clippy::expect_used)]
+      51          48 : pub fn warn(opts: &crate::opts::Dylint, message: &str) {
+      52          48 :     if !opts.quiet {
+      53             :         // smoelius: Writing directly to `stderr` prevents capture by `libtest`.
+      54          48 :         std::io::stderr()
+      55          48 :             .write_fmt(format_args!(
+      56          48 :                 "{}: {message}\n",
+      57          48 :                 if std::io::stderr().is_terminal() {
+      58           0 :                     Yellow.bold()
+      59             :                 } else {
+      60          48 :                     Style::new()
+      61             :                 }
+      62          48 :                 .paint("Warning")
+      63          48 :             ))
+      64          48 :             .expect("Could not write to stderr");
+      65           0 :     }
+      66          48 : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/index-sort-f.html b/coverage/dylint/src/index-sort-f.html new file mode 100644 index 000000000..216bdda3a --- /dev/null +++ b/coverage/dylint/src/index-sort-f.html @@ -0,0 +1,123 @@ + + + + + + + LCOV - unnamed - dylint/src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/srcHitTotalCoverage
Test:unnamedLines:57467984.5 %
Date:2024-09-27 12:58:08Functions:456866.2 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
driver_builder.rs +
85.4%85.4%
+
85.4 %135 / 15845.8 %11 / 24
error.rs +
87.5%87.5%
+
87.5 %21 / 2460.0 %3 / 5
lib.rs +
85.7%85.7%
+
85.7 %385 / 44973.3 %22 / 30
opts.rs +
68.8%68.8%
+
68.8 %33 / 48100.0 %9 / 9
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/index-sort-l.html b/coverage/dylint/src/index-sort-l.html new file mode 100644 index 000000000..348bc3255 --- /dev/null +++ b/coverage/dylint/src/index-sort-l.html @@ -0,0 +1,123 @@ + + + + + + + LCOV - unnamed - dylint/src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/srcHitTotalCoverage
Test:unnamedLines:57467984.5 %
Date:2024-09-27 12:58:08Functions:456866.2 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
opts.rs +
68.8%68.8%
+
68.8 %33 / 48100.0 %9 / 9
driver_builder.rs +
85.4%85.4%
+
85.4 %135 / 15845.8 %11 / 24
lib.rs +
85.7%85.7%
+
85.7 %385 / 44973.3 %22 / 30
error.rs +
87.5%87.5%
+
87.5 %21 / 2460.0 %3 / 5
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/index.html b/coverage/dylint/src/index.html new file mode 100644 index 000000000..e09228d6a --- /dev/null +++ b/coverage/dylint/src/index.html @@ -0,0 +1,123 @@ + + + + + + + LCOV - unnamed - dylint/src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/srcHitTotalCoverage
Test:unnamedLines:57467984.5 %
Date:2024-09-27 12:58:08Functions:456866.2 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
driver_builder.rs +
85.4%85.4%
+
85.4 %135 / 15845.8 %11 / 24
error.rs +
87.5%87.5%
+
87.5 %21 / 2460.0 %3 / 5
lib.rs +
85.7%85.7%
+
85.7 %385 / 44973.3 %22 / 30
opts.rs +
68.8%68.8%
+
68.8 %33 / 48100.0 %9 / 9
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/lib.rs.func-sort-c.html b/coverage/dylint/src/lib.rs.func-sort-c.html new file mode 100644 index 000000000..0855d620d --- /dev/null +++ b/coverage/dylint/src/lib.rs.func-sort-c.html @@ -0,0 +1,192 @@ + + + + + + + LCOV - unnamed - dylint/src/lib.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src - lib.rs (source / functions)HitTotalCoverage
Test:unnamedLines:38544985.7 %
Date:2024-09-27 12:58:08Functions:223073.3 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint::REQUIRED_FORM::{closure#0}0
dylint::check_or_fix::{closure#1}0
dylint::check_or_fix::{closure#2}0
dylint::display_location::{closure#0}0
dylint::display_location::{closure#1}0
dylint::list_lints::{closure#0}0
dylint::name_as_lib::{closure#0}0
dylint::run::{closure#0}::{closure#0}0
dylint::name_as_path1
dylint::test::OPTS::{closure#0}1
dylint::test::multiple_libraries_multiple_toolchains1
dylint::test::multiple_libraries_one_toolchain1
dylint::test::name_toolchain_map2
dylint::check_or_fix::{closure#3}3
dylint::run::{closure#0}3
dylint::list_libs5
dylint::list_lints5
dylint::warn_if_empty6
dylint::display_location7
dylint::is_valid_lib_name13
dylint::name_as_lib13
dylint::check_or_fix::{closure#0}17
dylint::resolve::{closure#0}17
dylint::check_or_fix22
dylint::clippy_disable_docs_links22
dylint::target_dir22
dylint::resolve32
dylint::flatten_toolchain_map::<alloc::collections::btree::set::BTreeSet<dylint::name_toolchain_map::maybe_library::MaybeLibrary>39
dylint::run_with_name_toolchain_map39
dylint::run41
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/lib.rs.func.html b/coverage/dylint/src/lib.rs.func.html new file mode 100644 index 000000000..eb945bba7 --- /dev/null +++ b/coverage/dylint/src/lib.rs.func.html @@ -0,0 +1,192 @@ + + + + + + + LCOV - unnamed - dylint/src/lib.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src - lib.rs (source / functions)HitTotalCoverage
Test:unnamedLines:38544985.7 %
Date:2024-09-27 12:58:08Functions:223073.3 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint::REQUIRED_FORM::{closure#0}0
dylint::check_or_fix22
dylint::check_or_fix::{closure#0}17
dylint::check_or_fix::{closure#1}0
dylint::check_or_fix::{closure#2}0
dylint::check_or_fix::{closure#3}3
dylint::clippy_disable_docs_links22
dylint::display_location7
dylint::display_location::{closure#0}0
dylint::display_location::{closure#1}0
dylint::flatten_toolchain_map::<alloc::collections::btree::set::BTreeSet<dylint::name_toolchain_map::maybe_library::MaybeLibrary>39
dylint::is_valid_lib_name13
dylint::list_libs5
dylint::list_lints5
dylint::list_lints::{closure#0}0
dylint::name_as_lib13
dylint::name_as_lib::{closure#0}0
dylint::name_as_path1
dylint::resolve32
dylint::resolve::{closure#0}17
dylint::run41
dylint::run::{closure#0}3
dylint::run::{closure#0}::{closure#0}0
dylint::run_with_name_toolchain_map39
dylint::target_dir22
dylint::test::OPTS::{closure#0}1
dylint::test::multiple_libraries_multiple_toolchains1
dylint::test::multiple_libraries_one_toolchain1
dylint::test::name_toolchain_map2
dylint::warn_if_empty6
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/lib.rs.gcov.html b/coverage/dylint/src/lib.rs.gcov.html new file mode 100644 index 000000000..0aca84efe --- /dev/null +++ b/coverage/dylint/src/lib.rs.gcov.html @@ -0,0 +1,732 @@ + + + + + + + LCOV - unnamed - dylint/src/lib.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src - lib.rs (source / functions)HitTotalCoverage
Test:unnamedLines:38544985.7 %
Date:2024-09-27 12:58:08Functions:223073.3 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #![cfg_attr(dylint_lib = "general", allow(crate_wide_allow))]
+       2             : #![deny(clippy::expect_used)]
+       3             : #![deny(clippy::unwrap_used)]
+       4             : #![deny(clippy::panic)]
+       5             : 
+       6             : use anyhow::{anyhow, bail, ensure, Context, Result};
+       7             : use cargo_metadata::MetadataCommand;
+       8             : use dylint_internal::{
+       9             :     driver as dylint_driver, env, parse_path_filename, rustup::SanitizeEnvironment, CommandExt,
+      10             : };
+      11             : use once_cell::sync::Lazy;
+      12             : use std::{
+      13             :     collections::BTreeMap,
+      14             :     env::{consts, current_dir},
+      15             :     ffi::OsStr,
+      16             :     fs::{metadata, OpenOptions},
+      17             :     path::{Path, PathBuf, MAIN_SEPARATOR},
+      18             : };
+      19             : 
+      20             : type Object = serde_json::Map<String, serde_json::Value>;
+      21             : 
+      22             : // smoelius: See note in dylint/src/library_packages/mod.rs.
+      23             : #[cfg(feature = "__cargo_lib")]
+      24             : pub(crate) use cargo::{core, sources, util};
+      25             : 
+      26             : pub mod driver_builder;
+      27             : 
+      28             : mod error;
+      29             : use error::warn;
+      30             : #[doc(hidden)]
+      31             : pub use error::warn as __warn;
+      32             : pub use error::{ColorizedError, ColorizedResult};
+      33             : 
+      34             : mod name_toolchain_map;
+      35             : pub use name_toolchain_map::{Lazy as NameToolchainMap, ToolchainMap};
+      36             : use name_toolchain_map::{LazyToolchainMap, MaybeLibrary};
+      37             : 
+      38             : #[cfg(__library_packages)]
+      39             : pub(crate) mod library_packages;
+      40             : 
+      41             : pub mod opts;
+      42             : 
+      43             : #[cfg(feature = "package_options")]
+      44             : mod package_options;
+      45             : 
+      46           0 : static REQUIRED_FORM: Lazy<String> = Lazy::new(|| {
+      47           0 :     format!(
+      48           0 :         r#""{}" LIBRARY_NAME "@" TOOLCHAIN "{}""#,
+      49           0 :         consts::DLL_PREFIX,
+      50           0 :         consts::DLL_SUFFIX
+      51           0 :     )
+      52           0 : });
+      53             : 
+      54             : #[cfg_attr(dylint_lib = "general", allow(non_local_effect_before_error_return))]
+      55             : #[cfg_attr(dylint_lib = "overscoped_allow", allow(overscoped_allow))]
+      56          41 : pub fn run(opts: &opts::Dylint) -> Result<()> {
+      57          41 :     let opts = {
+      58          41 :         let opts_orig = opts;
+      59          41 : 
+      60          41 :         let mut opts = opts.clone();
+      61             : 
+      62           4 :         if matches!(
+      63          41 :             opts.operation,
+      64             :             opts::Operation::Check(_) | opts::Operation::List(_)
+      65             :         ) {
+      66          37 :             let lib_sel = opts.library_selection_mut();
+      67             : 
+      68          37 :             let path_refers_to_libraries =
+      69          37 :                 lib_sel
+      70          37 :                     .paths
+      71          37 :                     .iter()
+      72          37 :                     .try_fold(false, |is_file, path| -> Result<_> {
+      73           3 :                         let metadata =
+      74           3 :                             metadata(path).with_context(|| "Could not read file metadata")?;
+      75           3 :                         Ok(is_file || metadata.is_file())
+      76          37 :                     })?;
+      77             : 
+      78          37 :             if path_refers_to_libraries {
+      79           1 :                 warn(
+      80           1 :                     opts_orig,
+      81           1 :                     "Referring to libraries with `--path` is deprecated. Use `--lib-path`.",
+      82           1 :                 );
+      83           1 :                 lib_sel.lib_paths.extend(lib_sel.paths.split_off(0));
+      84          36 :             };
+      85             : 
+      86             :             // smoelius: Use of `--git` or `--path` implies `--all`.
+      87             :             //
+      88             :             // smoelius: The intuition is as follows. Option `--git` or `--path` creates an
+      89             :             // alternative namespace of library packages, i.e., alternative to the one built
+      90             :             // from workspace metadata. The alternative namespace consists of just the
+      91             :             // library packages in the `--git`-named repository, or the `--path`-named
+      92             :             // directory.
+      93             :             //
+      94             :             // It would seem silly to require the user to pass `--lib` in addition to `--git` or
+      95             :             // `--path`. For this reason, all of the libraries in the alternative namespace are
+      96             :             // loaded.
+      97          37 :             lib_sel.all |= lib_sel.git_or_path();
+      98           4 :         }
+      99             : 
+     100          41 :         opts
+     101          41 :     };
+     102          41 : 
+     103          41 :     if opts.has_library_selection()
+     104          37 :         && opts.library_selection().pattern.is_some()
+     105           0 :         && !opts.git_or_path()
+     106             :     {
+     107           0 :         bail!("`--pattern` can be used only with `--git` or `--path`");
+     108          41 :     }
+     109          41 : 
+     110          41 :     if opts.pipe_stderr.is_some() {
+     111           0 :         warn(&opts, "`--pipe-stderr` is experimental");
+     112          41 :     }
+     113             : 
+     114          41 :     if opts.pipe_stdout.is_some() {
+     115           0 :         warn(&opts, "`--pipe-stdout` is experimental");
+     116          41 :     }
+     117             : 
+     118          41 :     match &opts.operation {
+     119             :         opts::Operation::Check(_) | opts::Operation::List(_) => {
+     120          37 :             let name_toolchain_map = NameToolchainMap::new(&opts);
+     121          37 :             run_with_name_toolchain_map(&opts, &name_toolchain_map)
+     122             :         }
+     123             :         #[cfg(feature = "package_options")]
+     124           1 :         opts::Operation::New(new_opts) => package_options::new_package(&opts, new_opts),
+     125             :         #[cfg(feature = "package_options")]
+     126           3 :         opts::Operation::Upgrade(upgrade_opts) => {
+     127           3 :             package_options::upgrade_package(&opts, upgrade_opts)
+     128             :         }
+     129             :     }
+     130          41 : }
+     131             : 
+     132          39 : fn run_with_name_toolchain_map(
+     133          39 :     opts: &opts::Dylint,
+     134          39 :     name_toolchain_map: &NameToolchainMap,
+     135          39 : ) -> Result<()> {
+     136          39 :     let lib_sel = opts.library_selection();
+     137          39 : 
+     138          39 :     if lib_sel.libs.is_empty() && lib_sel.lib_paths.is_empty() && !lib_sel.all {
+     139           7 :         if matches!(opts.operation, opts::Operation::List(_)) {
+     140           5 :             warn_if_empty(opts, name_toolchain_map)?;
+     141           5 :             return list_libs(name_toolchain_map);
+     142           2 :         }
+     143           2 : 
+     144           2 :         warn(opts, "Nothing to do. Did you forget `--all`?");
+     145           2 :         return Ok(());
+     146          32 :     }
+     147             : 
+     148          32 :     let resolved = resolve(opts, name_toolchain_map)?;
+     149             : 
+     150          27 :     if resolved.is_empty() {
+     151           1 :         assert!(lib_sel.libs.is_empty());
+     152           1 :         assert!(lib_sel.lib_paths.is_empty());
+     153             : 
+     154           1 :         let name_toolchain_map_is_empty = warn_if_empty(opts, name_toolchain_map)?;
+     155             : 
+     156             :         // smoelius: If `name_toolchain_map` is NOT empty, then it had better be the case that
+     157             :         // `--all` was not passed.
+     158           1 :         assert!(name_toolchain_map_is_empty || !lib_sel.all);
+     159          26 :     }
+     160             : 
+     161          27 :     match &opts.operation {
+     162          22 :         opts::Operation::Check(check_opts) => check_or_fix(opts, check_opts, &resolved),
+     163           5 :         opts::Operation::List(_) => list_lints(opts, &resolved),
+     164             :         #[allow(unreachable_patterns)]
+     165           0 :         _ => unreachable!(),
+     166             :     }
+     167          39 : }
+     168             : 
+     169           6 : fn warn_if_empty(opts: &opts::Dylint, name_toolchain_map: &NameToolchainMap) -> Result<bool> {
+     170           6 :     let name_toolchain_map = name_toolchain_map.get_or_try_init()?;
+     171             : 
+     172           6 :     Ok(if name_toolchain_map.is_empty() {
+     173           2 :         warn(opts, "No libraries were found.");
+     174           2 :         true
+     175             :     } else {
+     176           4 :         false
+     177             :     })
+     178           6 : }
+     179             : 
+     180           5 : fn list_libs(name_toolchain_map: &NameToolchainMap) -> Result<()> {
+     181           5 :     let name_toolchain_map = name_toolchain_map.get_or_try_init()?;
+     182             : 
+     183           5 :     let name_width = name_toolchain_map
+     184           5 :         .keys()
+     185           5 :         .map(String::len)
+     186           5 :         .max()
+     187           5 :         .unwrap_or_default();
+     188           5 : 
+     189           5 :     let toolchain_width = name_toolchain_map
+     190           5 :         .values()
+     191           5 :         .flat_map(LazyToolchainMap::keys)
+     192           5 :         .map(String::len)
+     193           5 :         .max()
+     194           5 :         .unwrap_or_default();
+     195             : 
+     196          10 :     for (name, toolchain_map) in name_toolchain_map {
+     197          10 :         for (toolchain, maybe_libraries) in toolchain_map {
+     198          10 :             for maybe_library in maybe_libraries {
+     199           5 :                 let location = display_location(&maybe_library.path())?;
+     200           5 :                 println!("{name:<name_width$}  {toolchain:<toolchain_width$}  {location}",);
+     201             :             }
+     202             :         }
+     203             :     }
+     204             : 
+     205           5 :     Ok(())
+     206           5 : }
+     207             : 
+     208             : #[cfg_attr(
+     209             :     dylint_lib = "question_mark_in_expression",
+     210             :     allow(question_mark_in_expression)
+     211             : )]
+     212          32 : fn resolve(opts: &opts::Dylint, name_toolchain_map: &NameToolchainMap) -> Result<ToolchainMap> {
+     213          32 :     let lib_sel = opts.library_selection();
+     214          32 : 
+     215          32 :     let mut toolchain_map = ToolchainMap::new();
+     216          32 : 
+     217          32 :     if lib_sel.all {
+     218          20 :         let name_toolchain_map = name_toolchain_map.get_or_try_init()?;
+     219             : 
+     220          15 :         for other in name_toolchain_map.values() {
+     221          31 :             for (toolchain, maybe_libraries) in other {
+     222          16 :                 let paths = maybe_libraries
+     223          16 :                     .iter()
+     224          17 :                     .map(|maybe_library| maybe_library.build(opts))
+     225          16 :                     .collect::<Result<Vec<_>>>()?;
+     226          16 :                 toolchain_map
+     227          16 :                     .entry(toolchain.clone())
+     228          16 :                     .or_default()
+     229          16 :                     .extend(paths);
+     230             :             }
+     231             :         }
+     232          12 :     }
+     233             : 
+     234          40 :     for name in &lib_sel.libs {
+     235          13 :         ensure!(!lib_sel.all, "`--lib` cannot be used with `--all`");
+     236          13 :         let (toolchain, maybe_library) =
+     237          13 :             name_as_lib(name_toolchain_map, name, true)?.unwrap_or_else(|| unreachable!());
+     238          13 :         let path = maybe_library.build(opts)?;
+     239          13 :         toolchain_map.entry(toolchain).or_default().insert(path);
+     240             :     }
+     241             : 
+     242          28 :     for name in &lib_sel.lib_paths {
+     243           1 :         let (toolchain, path) = name_as_path(name, true)?.unwrap_or_else(|| unreachable!());
+     244           1 :         toolchain_map.entry(toolchain).or_default().insert(path);
+     245           1 :     }
+     246             : 
+     247          27 :     Ok(toolchain_map)
+     248          32 : }
+     249             : 
+     250          13 : pub fn name_as_lib(
+     251          13 :     name_toolchain_map: &NameToolchainMap,
+     252          13 :     name: &str,
+     253          13 :     as_lib_only: bool,
+     254          13 : ) -> Result<Option<(String, MaybeLibrary)>> {
+     255          13 :     if !is_valid_lib_name(name) {
+     256           0 :         ensure!(!as_lib_only, "`{}` is not a valid library name", name);
+     257           0 :         return Ok(None);
+     258          13 :     }
+     259             : 
+     260          13 :     let name_toolchain_map = name_toolchain_map.get_or_try_init()?;
+     261             : 
+     262          13 :     if let Some(toolchain_map) = name_toolchain_map.get(name) {
+     263          13 :         let mut toolchain_maybe_libraries = flatten_toolchain_map(toolchain_map);
+     264          13 : 
+     265          13 :         return match toolchain_maybe_libraries.len() {
+     266           0 :             0 => Ok(None),
+     267          13 :             1 => Ok(Some(toolchain_maybe_libraries.remove(0))),
+     268           0 :             _ => Err(anyhow!(
+     269           0 :                 "Found multiple libraries matching `{}`: {:?}",
+     270           0 :                 name,
+     271           0 :                 toolchain_maybe_libraries
+     272           0 :                     .iter()
+     273           0 :                     .map(|(_, path)| path)
+     274           0 :                     .collect::<Vec<_>>()
+     275           0 :             )),
+     276             :         };
+     277           0 :     }
+     278           0 : 
+     279           0 :     ensure!(!as_lib_only, "Could not find `--lib {}`", name);
+     280             : 
+     281           0 :     Ok(None)
+     282          13 : }
+     283             : 
+     284          13 : fn is_valid_lib_name(name: &str) -> bool {
+     285          13 :     Path::new(name).file_name() == Some(OsStr::new(name))
+     286          13 : }
+     287             : 
+     288          13 : fn flatten_toolchain_map<I, T>(toolchain_map: &BTreeMap<String, I>) -> Vec<(String, T)>
+     289          13 : where
+     290          13 :     for<'a> &'a I: IntoIterator<Item = &'a T>,
+     291          13 :     T: Clone,
+     292          13 : {
+     293          13 :     toolchain_map
+     294          13 :         .iter()
+     295          13 :         .flat_map(|(toolchain, values)| {
+     296          13 :             values
+     297          13 :                 .into_iter()
+     298          13 :                 .map(|value| (toolchain.clone(), value.clone()))
+     299          13 :                 .collect::<Vec<_>>()
+     300          13 :         })
+     301          13 :         .collect()
+     302          13 : }
+     303             : 
+     304           1 : fn name_as_path(name: &str, as_path_only: bool) -> Result<Option<(String, PathBuf)>> {
+     305           1 :     if let Ok(path) = PathBuf::from(name).canonicalize() {
+     306           1 :         if let Some((_, toolchain)) = parse_path_filename(&path) {
+     307           1 :             return Ok(Some((toolchain, path)));
+     308           0 :         }
+     309           0 : 
+     310           0 :         ensure!(
+     311           0 :             !as_path_only,
+     312           0 :             "`--lib-path {}` was used, but the filename does not have the required form: {}",
+     313           0 :             name,
+     314           0 :             *REQUIRED_FORM
+     315             :         );
+     316             : 
+     317             :         // smoelius: If `name` contains a path separator, then it was clearly meant to be a
+     318             :         // path.
+     319           0 :         ensure!(
+     320           0 :             !name.contains(MAIN_SEPARATOR),
+     321           0 :             "`{}` is a valid path, but the filename does not have the required form: {}",
+     322           0 :             name,
+     323           0 :             *REQUIRED_FORM
+     324             :         );
+     325             : 
+     326           0 :         ensure!(
+     327           0 :             !as_path_only,
+     328           0 :             "`--lib-path {}` was used, but it is invalid",
+     329             :             name
+     330             :         );
+     331           0 :     }
+     332             : 
+     333           0 :     ensure!(!as_path_only, "Could not find `--path {}`", name);
+     334             : 
+     335           0 :     Ok(None)
+     336           1 : }
+     337             : 
+     338           5 : fn list_lints(opts: &opts::Dylint, resolved: &ToolchainMap) -> Result<()> {
+     339          11 :     for (toolchain, paths) in resolved {
+     340          13 :         for path in paths {
+     341           7 :             let driver = driver_builder::get(opts, toolchain)?;
+     342           7 :             let dylint_libs = serde_json::to_string(&[path])?;
+     343           7 :             let (name, _) =
+     344           7 :                 parse_path_filename(path).ok_or_else(|| anyhow!("Could not parse path"))?;
+     345             : 
+     346           7 :             print!("{name}");
+     347           7 :             if resolved.keys().len() >= 2 {
+     348           2 :                 print!("@{toolchain}");
+     349           5 :             }
+     350           7 :             if paths.len() >= 2 {
+     351           2 :                 let location = display_location(path)?;
+     352           2 :                 print!(" ({location})");
+     353           5 :             }
+     354           7 :             println!();
+     355             : 
+     356             :             // smoelius: `-W help` is the normal way to list lints, so we can be sure it
+     357             :             // gets the lints loaded. However, we don't actually use it to list the lints.
+     358           7 :             let mut command = dylint_driver(toolchain, &driver)?;
+     359           7 :             command
+     360           7 :                 .envs([
+     361           7 :                     (env::DYLINT_LIBS, dylint_libs.as_str()),
+     362           7 :                     (env::DYLINT_LIST, "1"),
+     363           7 :                 ])
+     364           7 :                 .args(["rustc", "-W", "help"])
+     365           7 :                 .success()?;
+     366             : 
+     367           7 :             println!();
+     368             :         }
+     369             :     }
+     370             : 
+     371           5 :     Ok(())
+     372           5 : }
+     373             : 
+     374           7 : fn display_location(path: &Path) -> Result<String> {
+     375           7 :     let current_dir = current_dir().with_context(|| "Could not get current directory")?;
+     376           7 :     let Ok(path_buf) = path.canonicalize() else {
+     377           3 :         return Ok("<unbuilt>".to_owned());
+     378             :     };
+     379           4 :     let parent = path_buf
+     380           4 :         .parent()
+     381           4 :         .ok_or_else(|| anyhow!("Could not get parent directory"))?;
+     382           4 :     Ok(parent
+     383           4 :         .strip_prefix(&current_dir)
+     384           4 :         .unwrap_or(parent)
+     385           4 :         .to_string_lossy()
+     386           4 :         .to_string())
+     387           7 : }
+     388             : 
+     389          22 : fn check_or_fix(
+     390          22 :     opts: &opts::Dylint,
+     391          22 :     check_opts: &opts::Check,
+     392          22 :     resolved: &ToolchainMap,
+     393          22 : ) -> Result<()> {
+     394          22 :     let clippy_disable_docs_links = clippy_disable_docs_links()?;
+     395             : 
+     396          22 :     let mut failures = Vec::new();
+     397             : 
+     398          41 :     for (toolchain, paths) in resolved {
+     399          22 :         let target_dir = target_dir(opts, toolchain)?;
+     400          22 :         let target_dir_str = target_dir.to_string_lossy();
+     401          22 :         let driver = driver_builder::get(opts, toolchain)?;
+     402          22 :         let dylint_libs = serde_json::to_string(&paths)?;
+     403             :         #[cfg(not(__library_packages))]
+     404             :         let dylint_metadata = None;
+     405             :         #[cfg(__library_packages)]
+     406          22 :         let dylint_metadata = library_packages::dylint_metadata(opts)?;
+     407          22 :         let dylint_metadata_str = dylint_metadata
+     408          22 :             .map(|object: &Object| serde_json::Value::from(object.clone()))
+     409          22 :             .unwrap_or_default()
+     410          22 :             .to_string();
+     411          22 :         let description = format!("with toolchain `{toolchain}`");
+     412          22 :         let mut command = if check_opts.fix {
+     413           1 :             dylint_internal::cargo::fix(&description)
+     414             :         } else {
+     415          21 :             dylint_internal::cargo::check(&description)
+     416             :         }
+     417          22 :         .build();
+     418          22 :         let mut args = vec!["--target-dir", &target_dir_str];
+     419          22 :         if let Some(path) = &check_opts.lib_sel.manifest_path {
+     420           3 :             args.extend(["--manifest-path", path]);
+     421          19 :         }
+     422          24 :         for spec in &check_opts.packages {
+     423           2 :             args.extend(["-p", spec]);
+     424           2 :         }
+     425          22 :         if check_opts.workspace {
+     426           0 :             args.extend(["--workspace"]);
+     427          22 :         }
+     428          22 :         args.extend(check_opts.args.iter().map(String::as_str));
+     429          22 : 
+     430          22 :         // smoelius: Set CLIPPY_DISABLE_DOCS_LINKS to prevent lints from accidentally linking to the
+     431          22 :         // Clippy repository. But set it to the JSON-encoded original value so that the Clippy
+     432          22 :         // library can unset the variable.
+     433          22 :         // smoelius: This doesn't work if another library is loaded alongside Clippy.
+     434          22 :         // smoelius: This was fixed in `clippy_utils`:
+     435          22 :         // https://github.com/rust-lang/rust-clippy/commit/1a206fc4abae0b57a3f393481367cf3efca23586
+     436          22 :         // But I am going to continue to set CLIPPY_DISABLE_DOCS_LINKS because it doesn't seem to
+     437          22 :         // hurt and it provides a small amount of backward compatibility.
+     438          22 :         command
+     439          22 :             .sanitize_environment()
+     440          22 :             .envs([
+     441          22 :                 (
+     442          22 :                     env::CLIPPY_DISABLE_DOCS_LINKS,
+     443          22 :                     clippy_disable_docs_links.as_str(),
+     444          22 :                 ),
+     445          22 :                 (env::DYLINT_LIBS, &dylint_libs),
+     446          22 :                 (env::DYLINT_METADATA, &dylint_metadata_str),
+     447          22 :                 (
+     448          22 :                     env::DYLINT_NO_DEPS,
+     449          22 :                     if check_opts.no_deps { "1" } else { "0" },
+     450             :                 ),
+     451          22 :                 (env::RUSTC_WORKSPACE_WRAPPER, &*driver.to_string_lossy()),
+     452          22 :                 (env::RUSTUP_TOOLCHAIN, toolchain),
+     453          22 :             ])
+     454          22 :             .args(args);
+     455             : 
+     456             :         // smoelius:: See: https://github.com/rust-lang/rustup/pull/3703 and
+     457             :         // https://github.com/rust-lang/rustup/issues/3825
+     458             :         #[cfg(windows)]
+     459             :         {
+     460             :             let new_path = dylint_internal::prepend_toolchain_path(toolchain)?;
+     461             :             command.envs(vec![(crate::env::PATH, new_path)]);
+     462             :         }
+     463             : 
+     464          22 :         if let Some(stderr_path) = &opts.pipe_stderr {
+     465           0 :             let file = OpenOptions::new()
+     466           0 :                 .append(true)
+     467           0 :                 .create(true)
+     468           0 :                 .open(stderr_path)
+     469           0 :                 .with_context(|| format!("Failed to open `{stderr_path}` for stderr usage"))?;
+     470           0 :             command.stderr(file);
+     471          22 :         }
+     472             : 
+     473          22 :         if let Some(stdout_path) = &opts.pipe_stdout {
+     474           0 :             let file = OpenOptions::new()
+     475           0 :                 .append(true)
+     476           0 :                 .create(true)
+     477           0 :                 .open(stdout_path)
+     478           0 :                 .with_context(|| format!("Failed to open `{stdout_path}` for stdout usage"))?;
+     479           0 :             command.stdout(file);
+     480          22 :         }
+     481             : 
+     482          22 :         let result = command.success();
+     483          22 :         if result.is_err() {
+     484           3 :             if !check_opts.keep_going {
+     485           3 :                 return result
+     486           3 :                     .with_context(|| format!("Compilation failed with toolchain `{toolchain}`"));
+     487           0 :             };
+     488           0 :             failures.push(toolchain);
+     489          19 :         }
+     490             :     }
+     491             : 
+     492          19 :     if failures.is_empty() {
+     493          19 :         Ok(())
+     494             :     } else {
+     495           0 :         Err(anyhow!(
+     496           0 :             "Compilation failed with the following toolchains: {:?}",
+     497           0 :             failures
+     498           0 :         ))
+     499             :     }
+     500          22 : }
+     501             : 
+     502          22 : fn target_dir(opts: &opts::Dylint, toolchain: &str) -> Result<PathBuf> {
+     503          22 :     let mut command = MetadataCommand::new();
+     504          22 :     if let Some(path) = &opts.library_selection().manifest_path {
+     505           3 :         command.manifest_path(path);
+     506          19 :     }
+     507          22 :     let metadata = command.no_deps().exec()?;
+     508          22 :     Ok(metadata
+     509          22 :         .target_directory
+     510          22 :         .join("dylint/target")
+     511          22 :         .join(toolchain)
+     512          22 :         .into())
+     513          22 : }
+     514             : 
+     515          22 : fn clippy_disable_docs_links() -> Result<String> {
+     516          22 :     let val = env::var(env::CLIPPY_DISABLE_DOCS_LINKS).ok();
+     517          22 :     serde_json::to_string(&val).map_err(Into::into)
+     518          22 : }
+     519             : 
+     520             : #[allow(clippy::unwrap_used)]
+     521             : #[cfg(test)]
+     522             : mod test {
+     523             :     use super::*;
+     524             :     use dylint_internal::examples;
+     525             :     use std::{
+     526             :         env::{join_paths, set_var},
+     527             :         sync::Mutex,
+     528             :     };
+     529             : 
+     530             :     // smoelius: With the upgrade to nightly-2023-03-10, I started running into this:
+     531             :     // https://github.com/rust-lang/rustup/issues/988
+     532             :     // The easiest solution is to just not run the tests concurrently.
+     533             :     static MUTEX: Mutex<()> = Mutex::new(());
+     534             : 
+     535           1 :     static OPTS: Lazy<opts::Dylint> = Lazy::new(|| opts::Dylint {
+     536           1 :         operation: opts::Operation::Check(opts::Check {
+     537           1 :             lib_sel: opts::LibrarySelection {
+     538           1 :                 no_metadata: true,
+     539           1 :                 ..Default::default()
+     540           1 :             },
+     541           1 :             ..Default::default()
+     542           1 :         }),
+     543           1 :         ..Default::default()
+     544           1 :     });
+     545             : 
+     546           2 :     fn name_toolchain_map() -> NameToolchainMap<'static> {
+     547           2 :         examples::build().unwrap();
+     548           2 :         let metadata = dylint_internal::cargo::current_metadata().unwrap();
+     549           2 :         // smoelius: As of version 0.1.14, `cargo-llvm-cov` no longer sets `CARGO_TARGET_DIR`.
+     550           2 :         // So `dylint_library_path` no longer requires a `cfg!(coverage)` special case.
+     551           2 :         let dylint_library_path = join_paths([
+     552           2 :             metadata.target_directory.join("examples/debug"),
+     553           2 :             metadata.target_directory.join("straggler/debug"),
+     554           2 :         ])
+     555           2 :         .unwrap();
+     556           2 : 
+     557           2 :         #[rustfmt::skip]
+     558           2 :         // smoelius: Following the upgrade nightly-2023-08-24, I started seeing the following error:
+     559           2 :         //
+     560           2 :         //   error: internal compiler error: encountered incremental compilation error with shallow_lint_levels_on(dylint_internal[...]::cargo::{use#15})
+     561           2 :         //     |
+     562           2 :         //     = help: This is a known issue with the compiler. Run `cargo clean -p dylint_internal` or `cargo clean` to allow your project to compile
+     563           2 :         //     = note: Please follow the instructions below to create a bug report with the provided information
+     564           2 :         //     = note: See <https://github.com/rust-lang/rust/issues/84970> for more information
+     565           2 :         set_var(env::CARGO_INCREMENTAL, "0");
+     566           2 :         set_var(env::DYLINT_LIBRARY_PATH, dylint_library_path);
+     567           2 : 
+     568           2 :         NameToolchainMap::new(&OPTS)
+     569           2 :     }
+     570             : 
+     571             :     #[cfg_attr(dylint_lib = "general", allow(non_thread_safe_call_in_test))]
+     572             :     #[test]
+     573           1 :     fn multiple_libraries_multiple_toolchains() {
+     574           1 :         let _lock = MUTEX.lock().unwrap();
+     575           1 : 
+     576           1 :         let name_toolchain_map = name_toolchain_map();
+     577           1 : 
+     578           1 :         let inited = name_toolchain_map.get_or_try_init().unwrap();
+     579           1 : 
+     580           1 :         let question_mark_in_expression = inited.get("question_mark_in_expression").unwrap();
+     581           1 :         let straggler = inited.get("straggler").unwrap();
+     582           1 : 
+     583           1 :         assert_ne!(
+     584           1 :             question_mark_in_expression.keys().collect::<Vec<_>>(),
+     585           1 :             straggler.keys().collect::<Vec<_>>()
+     586           1 :         );
+     587             : 
+     588           1 :         let opts = opts::Dylint {
+     589           1 :             operation: opts::Operation::Check(opts::Check {
+     590           1 :                 lib_sel: opts::LibrarySelection {
+     591           1 :                     libs: vec![
+     592           1 :                         "question_mark_in_expression".to_owned(),
+     593           1 :                         "straggler".to_owned(),
+     594           1 :                     ],
+     595           1 :                     ..Default::default()
+     596           1 :                 },
+     597           1 :                 ..Default::default()
+     598           1 :             }),
+     599           1 :             ..Default::default()
+     600           1 :         };
+     601           1 : 
+     602           1 :         run_with_name_toolchain_map(&opts, &name_toolchain_map).unwrap();
+     603           1 :     }
+     604             : 
+     605             :     // smoelius: Check that loading multiple libraries with the same Rust toolchain works. At one
+     606             :     // point, I was getting this error from `libloading`:
+     607             :     //
+     608             :     //   cannot allocate memory in static TLS block
+     609             :     //
+     610             :     // The culprit turned out to be the `rand` crate, which uses a lot of thread local storage.
+     611             :     // `rand` is used by `tempfile`, which is used by various Rust compiler crates. Essentially,
+     612             :     // each library had its own copy of the Rust compiler, and therefore its own copy of the `rand`
+     613             :     // crate, and this was eating up all the thread local storage.
+     614             :     //
+     615             :     // The solution was to add `extern crate rustc_driver` to each library. This causes the library
+     616             :     // to link against `librust_driver.so`, which dylint-driver also links against. So, essentially,
+     617             :     // each library now uses dylint-driver's copy of the `rand` crate.
+     618             :     //
+     619             :     // This thread was very helpful in diagnosing the problem:
+     620             :     //
+     621             :     //   https://bugzilla.redhat.com/show_bug.cgi?id=1722181
+     622             :     //
+     623             :     #[cfg_attr(dylint_lib = "general", allow(non_thread_safe_call_in_test))]
+     624             :     #[test]
+     625           1 :     fn multiple_libraries_one_toolchain() {
+     626           1 :         let _lock = MUTEX.lock().unwrap();
+     627           1 : 
+     628           1 :         let name_toolchain_map = name_toolchain_map();
+     629           1 : 
+     630           1 :         let inited = name_toolchain_map.get_or_try_init().unwrap();
+     631           1 : 
+     632           1 :         let clippy = inited.get("clippy").unwrap();
+     633           1 :         let question_mark_in_expression = inited.get("question_mark_in_expression").unwrap();
+     634           1 : 
+     635           1 :         assert_eq!(
+     636           1 :             clippy.keys().collect::<Vec<_>>(),
+     637           1 :             question_mark_in_expression.keys().collect::<Vec<_>>()
+     638           1 :         );
+     639             : 
+     640           1 :         let opts = opts::Dylint {
+     641           1 :             operation: opts::Operation::Check(opts::Check {
+     642           1 :                 lib_sel: opts::LibrarySelection {
+     643           1 :                     libs: vec![
+     644           1 :                         "clippy".to_owned(),
+     645           1 :                         "question_mark_in_expression".to_owned(),
+     646           1 :                     ],
+     647           1 :                     ..Default::default()
+     648           1 :                 },
+     649           1 :                 ..Default::default()
+     650           1 :             }),
+     651           1 :             ..Default::default()
+     652           1 :         };
+     653           1 : 
+     654           1 :         run_with_name_toolchain_map(&opts, &name_toolchain_map).unwrap();
+     655           1 :     }
+     656             : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/library_packages/cargo_cli/index-sort-f.html b/coverage/dylint/src/library_packages/cargo_cli/index-sort-f.html new file mode 100644 index 000000000..1a8a2a992 --- /dev/null +++ b/coverage/dylint/src/library_packages/cargo_cli/index-sort-f.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - unnamed - dylint/src/library_packages/cargo_cli + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/library_packages/cargo_cliHitTotalCoverage
Test:unnamedLines:24825597.3 %
Date:2024-09-27 12:58:08Functions:254259.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
mod.rs +
97.3%97.3%
+
97.3 %248 / 25559.5 %25 / 42
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/library_packages/cargo_cli/index-sort-l.html b/coverage/dylint/src/library_packages/cargo_cli/index-sort-l.html new file mode 100644 index 000000000..09dcc4a47 --- /dev/null +++ b/coverage/dylint/src/library_packages/cargo_cli/index-sort-l.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - unnamed - dylint/src/library_packages/cargo_cli + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/library_packages/cargo_cliHitTotalCoverage
Test:unnamedLines:24825597.3 %
Date:2024-09-27 12:58:08Functions:254259.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
mod.rs +
97.3%97.3%
+
97.3 %248 / 25559.5 %25 / 42
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/library_packages/cargo_cli/index.html b/coverage/dylint/src/library_packages/cargo_cli/index.html new file mode 100644 index 000000000..c7a90c94b --- /dev/null +++ b/coverage/dylint/src/library_packages/cargo_cli/index.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - unnamed - dylint/src/library_packages/cargo_cli + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/library_packages/cargo_cliHitTotalCoverage
Test:unnamedLines:24825597.3 %
Date:2024-09-27 12:58:08Functions:254259.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
mod.rs +
97.3%97.3%
+
97.3 %248 / 25559.5 %25 / 42
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/library_packages/cargo_cli/mod.rs.func-sort-c.html b/coverage/dylint/src/library_packages/cargo_cli/mod.rs.func-sort-c.html new file mode 100644 index 000000000..20081996f --- /dev/null +++ b/coverage/dylint/src/library_packages/cargo_cli/mod.rs.func-sort-c.html @@ -0,0 +1,240 @@ + + + + + + + LCOV - unnamed - dylint/src/library_packages/cargo_cli/mod.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/library_packages/cargo_cli - mod.rs (source / functions)HitTotalCoverage
Test:unnamedLines:24825597.3 %
Date:2024-09-27 12:58:08Functions:254259.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint::library_packages::impl_::create_dummy_dependency::{closure#0}0
dylint::library_packages::impl_::create_dummy_package::{closure#0}0
dylint::library_packages::impl_::create_dummy_package::{closure#1}0
dylint::library_packages::impl_::create_dummy_package::{closure#2}0
dylint::library_packages::impl_::create_dummy_package::{closure#3}0
dylint::library_packages::impl_::find_accessed_subdir::{closure#1}::{closure#0}0
dylint::library_packages::impl_::find_accessed_subdir::{closure#1}::{closure#1}0
dylint::library_packages::impl_::find_accessed_subdir::{closure#3}0
dylint::library_packages::impl_::for_each_subdir::<dylint::library_packages::impl_::find_accessed_subdir::{closure#2}>::{closure#0}0
dylint::library_packages::impl_::for_each_subdir::<dylint::library_packages::impl_::find_accessed_subdir::{closure#2}>::{closure#1}0
dylint::library_packages::impl_::for_each_subdir::<dylint::library_packages::impl_::find_accessed_subdir::{closure#2}>::{closure#2}0
dylint::library_packages::impl_::for_each_subdir::<dylint::library_packages::impl_::inject_dummy_dependencies::{closure#0}>::{closure#0}0
dylint::library_packages::impl_::for_each_subdir::<dylint::library_packages::impl_::inject_dummy_dependencies::{closure#0}>::{closure#1}0
dylint::library_packages::impl_::for_each_subdir::<dylint::library_packages::impl_::inject_dummy_dependencies::{closure#0}>::{closure#2}0
dylint::library_packages::impl_::git_dependency_root::{closure#0}0
dylint::library_packages::impl_::git_dependency_root::{closure#1}0
dylint::library_packages::impl_::git_dependency_root::{closure#2}0
dylint::library_packages::impl_::dummy_dependency_free_suffix2
dylint::library_packages::impl_::for_each_subdir::<dylint::library_packages::impl_::find_accessed_subdir::{closure#2}>2
dylint::library_packages::impl_::git_dependency_root::{closure#3}2
dylint::library_packages::impl_::find_accessed_subdir::{closure#2}4
dylint::library_packages::impl_::dummy_dependency_free_suffix::{closure#0}6
dylint::library_packages::impl_::create_dummy_dependency9
dylint::library_packages::impl_::create_dummy_package9
dylint::library_packages::impl_::find_accessed_subdir::{closure#0}9
dylint::library_packages::impl_::for_each_subdir::<dylint::library_packages::impl_::inject_dummy_dependencies::{closure#0}>9
dylint::library_packages::impl_::git_dependency_root9
dylint::library_packages::impl_::git_source_id9
dylint::library_packages::impl_::ident9
dylint::library_packages::impl_::ident::{closure#0}9
dylint::library_packages::impl_::inject_dummy_dependencies9
dylint::library_packages::impl_::manifest_contents9
dylint::library_packages::impl_::cargo_fetch11
dylint::library_packages::impl_::cargo_metadata11
dylint::library_packages::impl_::find_accessed_subdir11
<dylint::library_packages::impl_::NamedTempDir as core::ops::drop::Drop>::drop18
dylint::library_packages::impl_::find_accessed_subdir::{closure#1}18
dylint::library_packages::impl_::inject_dummy_dependencies::{closure#0}18
<dylint::library_packages::impl_::PackageId>::name21
<dylint::library_packages::impl_::GlobalContext>::default27
<dylint::library_packages::impl_::PackageId>::new30
dylint::library_packages::impl_::dependency_source_id_and_root33
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/library_packages/cargo_cli/mod.rs.func.html b/coverage/dylint/src/library_packages/cargo_cli/mod.rs.func.html new file mode 100644 index 000000000..814941510 --- /dev/null +++ b/coverage/dylint/src/library_packages/cargo_cli/mod.rs.func.html @@ -0,0 +1,240 @@ + + + + + + + LCOV - unnamed - dylint/src/library_packages/cargo_cli/mod.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/library_packages/cargo_cli - mod.rs (source / functions)HitTotalCoverage
Test:unnamedLines:24825597.3 %
Date:2024-09-27 12:58:08Functions:254259.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<dylint::library_packages::impl_::GlobalContext>::default27
<dylint::library_packages::impl_::NamedTempDir as core::ops::drop::Drop>::drop18
<dylint::library_packages::impl_::PackageId>::name21
<dylint::library_packages::impl_::PackageId>::new30
dylint::library_packages::impl_::cargo_fetch11
dylint::library_packages::impl_::cargo_metadata11
dylint::library_packages::impl_::create_dummy_dependency9
dylint::library_packages::impl_::create_dummy_dependency::{closure#0}0
dylint::library_packages::impl_::create_dummy_package9
dylint::library_packages::impl_::create_dummy_package::{closure#0}0
dylint::library_packages::impl_::create_dummy_package::{closure#1}0
dylint::library_packages::impl_::create_dummy_package::{closure#2}0
dylint::library_packages::impl_::create_dummy_package::{closure#3}0
dylint::library_packages::impl_::dependency_source_id_and_root33
dylint::library_packages::impl_::dummy_dependency_free_suffix2
dylint::library_packages::impl_::dummy_dependency_free_suffix::{closure#0}6
dylint::library_packages::impl_::find_accessed_subdir11
dylint::library_packages::impl_::find_accessed_subdir::{closure#0}9
dylint::library_packages::impl_::find_accessed_subdir::{closure#1}18
dylint::library_packages::impl_::find_accessed_subdir::{closure#1}::{closure#0}0
dylint::library_packages::impl_::find_accessed_subdir::{closure#1}::{closure#1}0
dylint::library_packages::impl_::find_accessed_subdir::{closure#2}4
dylint::library_packages::impl_::find_accessed_subdir::{closure#3}0
dylint::library_packages::impl_::for_each_subdir::<dylint::library_packages::impl_::find_accessed_subdir::{closure#2}>2
dylint::library_packages::impl_::for_each_subdir::<dylint::library_packages::impl_::find_accessed_subdir::{closure#2}>::{closure#0}0
dylint::library_packages::impl_::for_each_subdir::<dylint::library_packages::impl_::find_accessed_subdir::{closure#2}>::{closure#1}0
dylint::library_packages::impl_::for_each_subdir::<dylint::library_packages::impl_::find_accessed_subdir::{closure#2}>::{closure#2}0
dylint::library_packages::impl_::for_each_subdir::<dylint::library_packages::impl_::inject_dummy_dependencies::{closure#0}>9
dylint::library_packages::impl_::for_each_subdir::<dylint::library_packages::impl_::inject_dummy_dependencies::{closure#0}>::{closure#0}0
dylint::library_packages::impl_::for_each_subdir::<dylint::library_packages::impl_::inject_dummy_dependencies::{closure#0}>::{closure#1}0
dylint::library_packages::impl_::for_each_subdir::<dylint::library_packages::impl_::inject_dummy_dependencies::{closure#0}>::{closure#2}0
dylint::library_packages::impl_::git_dependency_root9
dylint::library_packages::impl_::git_dependency_root::{closure#0}0
dylint::library_packages::impl_::git_dependency_root::{closure#1}0
dylint::library_packages::impl_::git_dependency_root::{closure#2}0
dylint::library_packages::impl_::git_dependency_root::{closure#3}2
dylint::library_packages::impl_::git_source_id9
dylint::library_packages::impl_::ident9
dylint::library_packages::impl_::ident::{closure#0}9
dylint::library_packages::impl_::inject_dummy_dependencies9
dylint::library_packages::impl_::inject_dummy_dependencies::{closure#0}18
dylint::library_packages::impl_::manifest_contents9
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/library_packages/cargo_cli/mod.rs.gcov.html b/coverage/dylint/src/library_packages/cargo_cli/mod.rs.gcov.html new file mode 100644 index 000000000..6be4a3cbb --- /dev/null +++ b/coverage/dylint/src/library_packages/cargo_cli/mod.rs.gcov.html @@ -0,0 +1,472 @@ + + + + + + + LCOV - unnamed - dylint/src/library_packages/cargo_cli/mod.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/library_packages/cargo_cli - mod.rs (source / functions)HitTotalCoverage
Test:unnamedLines:24825597.3 %
Date:2024-09-27 12:58:08Functions:254259.5 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : //! This module borrows an idea from [Marker]: to use `cargo fetch` to download a package into
+       2             : //! Cargo's cache. More specifically, this module creates a "dummy" project with a specified package
+       3             : //! as a dependency, and then calls `cargo fetch` to download the project's dependencies into
+       4             : //! Cargo's cache.
+       5             : //!
+       6             : //! There is a complication, however. Dylint does not require a workspace metadata entry to specify
+       7             : //! a lint library's package name. But the above idea, as applied in Marker, requires the package
+       8             : //! name.
+       9             : //!
+      10             : //! To work around this problem, this module creates a "dummy" dependency with a random name and
+      11             : //! "injects" it into each subdirectory of the relevant checkouts directory. If Cargo finds the
+      12             : //! dummy dependency in one of those subdirectories, then that subdirectory must have been updated
+      13             : //! by `cargo fetch`. On the other hand, if Cargo finds the dummy dependency in a completely new
+      14             : //! subdirectory, then that subdirectory must have been created by `cargo fetch`.
+      15             : //!
+      16             : //! [Marker]: https://github.com/rust-marker/marker
+      17             : 
+      18             : use crate::opts;
+      19             : use anyhow::{anyhow, bail, ensure, Context, Result};
+      20             : use cargo_metadata::{Metadata, MetadataCommand};
+      21             : use cargo_util_schemas::manifest::TomlDetailedDependency;
+      22             : use dylint_internal::{packaging::isolate, CommandExt};
+      23             : use home::cargo_home;
+      24             : use semver::Version;
+      25             : use serde::Serialize;
+      26             : use std::{
+      27             :     borrow::Cow,
+      28             :     collections::BTreeMap,
+      29             :     ffi::{OsStr, OsString},
+      30             :     fs::{create_dir_all, read_dir, remove_dir_all, write},
+      31             :     path::{Path, PathBuf},
+      32             :     process::{Output, Stdio},
+      33             : };
+      34             : use tempfile::{tempdir, Builder, TempDir};
+      35             : use url::Url;
+      36             : 
+      37             : mod util;
+      38             : use util::{short_hash, CanonicalUrl};
+      39             : 
+      40             : struct NamedTempDir(PathBuf);
+      41             : 
+      42             : impl Drop for NamedTempDir {
+      43          18 :     fn drop(&mut self) {
+      44          18 :         remove_dir_all(&self.0).unwrap_or_default();
+      45          18 :     }
+      46             : }
+      47             : 
+      48             : pub struct GlobalContext;
+      49             : 
+      50             : #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
+      51             : pub struct PackageId {
+      52             :     name: String,
+      53             :     version: Version,
+      54             :     source_id: String,
+      55             : }
+      56             : 
+      57             : pub type SourceId = String;
+      58             : 
+      59             : impl GlobalContext {
+      60             :     #[allow(clippy::unnecessary_wraps)]
+      61          27 :     pub const fn default() -> Result<Self> {
+      62          27 :         Ok(Self)
+      63          27 :     }
+      64             : }
+      65             : 
+      66             : impl PackageId {
+      67             :     #[allow(clippy::unnecessary_wraps)]
+      68          30 :     pub const fn new(name: String, version: Version, source_id: SourceId) -> Self {
+      69          30 :         Self {
+      70          30 :             name,
+      71          30 :             version,
+      72          30 :             source_id,
+      73          30 :         }
+      74          30 :     }
+      75             : 
+      76          21 :     pub fn name(&self) -> &str {
+      77          21 :         &self.name
+      78          21 :     }
+      79             : }
+      80             : 
+      81          33 : pub fn dependency_source_id_and_root(
+      82          33 :     _opts: &opts::Dylint,
+      83          33 :     metadata: &Metadata,
+      84          33 :     _gctx: &GlobalContext,
+      85          33 :     details: &TomlDetailedDependency,
+      86          33 : ) -> Result<(SourceId, PathBuf)> {
+      87          33 :     if let Some(url) = &details.git {
+      88           9 :         ensure!(
+      89           9 :             details.path.is_none(),
+      90           0 :             "A dependency cannot have both git and path entries"
+      91             :         );
+      92           9 :         let source_id = git_source_id(url, details)?;
+      93           9 :         let root = git_dependency_root(url, details)?;
+      94           9 :         Ok((source_id, root))
+      95          24 :     } else if let Some(path) = &details.path {
+      96          24 :         let source_id = String::new();
+      97          24 :         let root = metadata
+      98          24 :             .workspace_root
+      99          24 :             .join(path)
+     100          24 :             .as_std_path()
+     101          24 :             .to_path_buf();
+     102          24 :         Ok((source_id, root))
+     103             :     } else {
+     104           0 :         bail!("Only git and path entries are supported")
+     105             :     }
+     106          33 : }
+     107             : 
+     108           9 : fn git_source_id(url: &str, details: &TomlDetailedDependency) -> Result<String> {
+     109             :     #[derive(Serialize)]
+     110             :     struct GitReference<'a> {
+     111             :         url: &'a str,
+     112             :         branch: Option<&'a str>,
+     113             :         tag: Option<&'a str>,
+     114             :         rev: Option<&'a str>,
+     115             :     }
+     116           9 :     let json = serde_json::to_string(&GitReference {
+     117           9 :         url,
+     118           9 :         branch: details.branch.as_deref(),
+     119           9 :         tag: details.tag.as_deref(),
+     120           9 :         rev: details.rev.as_deref(),
+     121           9 :     })?;
+     122           9 :     Ok(json)
+     123           9 : }
+     124             : 
+     125           9 : fn git_dependency_root(url: &str, details: &TomlDetailedDependency) -> Result<PathBuf> {
+     126           9 :     let dependency = create_dummy_dependency()?;
+     127           9 :     let filename = dependency
+     128           9 :         .path()
+     129           9 :         .file_name()
+     130           9 :         .ok_or_else(|| anyhow!("Could not get file name"))?;
+     131           9 :     let dep_name = filename.to_string_lossy();
+     132             : 
+     133           9 :     let package = create_dummy_package(&dep_name, details)?;
+     134             : 
+     135           9 :     let cargo_home = cargo_home().with_context(|| "Could not determine `CARGO_HOME`")?;
+     136           9 :     let ident = ident(url)?;
+     137           9 :     let checkout_path = cargo_home.join("git/checkouts").join(ident);
+     138           9 : 
+     139           9 :     let mut errors = Vec::new();
+     140             :     // smoelius: It should take at most two attempts to find the git dependency root. The first
+     141             :     // attempt may fail because a new checkouts subdirectory had to be created. But the second
+     142             :     // attempt should then succeed.
+     143          11 :     for _ in [false, true] {
+     144             :         // smoelius: `checkout_path` might not exist, e.g., if the url has never been cloned.
+     145          11 :         let injected_dependencies = if checkout_path
+     146          11 :             .try_exists()
+     147          11 :             .with_context(|| format!("Could not determine whether {checkout_path:?} exists"))?
+     148             :         {
+     149           9 :             inject_dummy_dependencies(dependency.path(), &dep_name, &checkout_path)?
+     150             :         } else {
+     151           2 :             BTreeMap::new()
+     152             :         };
+     153             : 
+     154          11 :         let output = cargo_fetch(package.path())?;
+     155             : 
+     156             :         // smoelius: `cargo metadata` will fail if `cargo fetch` had to create a new checkouts
+     157             :         // subdirectory.
+     158          11 :         let metadata = cargo_metadata(package.path()).ok();
+     159          11 : 
+     160          11 :         match find_accessed_subdir(
+     161          11 :             &dep_name,
+     162          11 :             &checkout_path,
+     163          11 :             &injected_dependencies,
+     164          11 :             metadata.as_ref(),
+     165          11 :         ) {
+     166           9 :             Ok(path) => {
+     167           9 :                 return Ok(path.to_path_buf());
+     168             :             }
+     169           2 :             Err(error) => {
+     170           2 :                 let s = if output.status.success() {
+     171           0 :                     error.to_string()
+     172             :                 } else {
+     173           2 :                     format!(
+     174           2 :                         "{:?}",
+     175           2 :                         Result::<PathBuf>::Err(error).with_context(|| {
+     176           2 :                             format!(
+     177           2 :                                 "fetching packages failed\nstdout: {:?}\nstderr: {:?}",
+     178           2 :                                 String::from_utf8(output.stdout).unwrap_or_default(),
+     179           2 :                                 dummy_dependency_free_suffix(
+     180           2 :                                     &dep_name,
+     181           2 :                                     &String::from_utf8(output.stderr).unwrap_or_default()
+     182           2 :                                 )
+     183           2 :                             )
+     184           2 :                         })
+     185           2 :                     )
+     186             :                 };
+     187           2 :                 errors.push(s);
+     188             :             }
+     189             :         }
+     190             :     }
+     191             : 
+     192             :     // smoelius: If we get here, it should be because `find_accessed_subdir` failed twice.
+     193           0 :     debug_assert!(errors.len() >= 2);
+     194             : 
+     195           0 :     Err(anyhow!("Could not find git dependency root: {errors:#?}"))
+     196           9 : }
+     197             : 
+     198             : /// Creates a dummy dependency in a temporary directory, and returns the temporary directory if
+     199             : /// everything was successful.
+     200           9 : fn create_dummy_dependency() -> Result<TempDir> {
+     201           9 :     let tempdir = Builder::new()
+     202           9 :         .prefix("tmp")
+     203           9 :         .tempdir()
+     204           9 :         .with_context(|| "Could not create temporary directory")?;
+     205             : 
+     206           9 :     dylint_internal::cargo::init("dummy dependency")
+     207           9 :         .quiet(true)
+     208           9 :         .stable(true)
+     209           9 :         .build()
+     210           9 :         .current_dir(&tempdir)
+     211           9 :         .args(["--lib", "--vcs=none"])
+     212           9 :         .success()?;
+     213             : 
+     214           9 :     isolate(tempdir.path())?;
+     215             : 
+     216           9 :     Ok(tempdir)
+     217           9 : }
+     218             : 
+     219             : /// Creates a dummy package in a temporary directory, and returns the temporary directory if
+     220             : /// everything was successful.
+     221           9 : fn create_dummy_package(dep_name: &str, details: &TomlDetailedDependency) -> Result<TempDir> {
+     222           9 :     let tempdir = tempdir().with_context(|| "Could not create temporary directory")?;
+     223             : 
+     224           9 :     let manifest_contents = manifest_contents(dep_name, details)?;
+     225           9 :     let manifest_path = tempdir.path().join("Cargo.toml");
+     226           9 :     write(&manifest_path, manifest_contents)
+     227           9 :         .with_context(|| format!("Could not write to {manifest_path:?}"))?;
+     228             : 
+     229           9 :     let src_path = tempdir.path().join("src");
+     230           9 : 
+     231           9 :     create_dir_all(&src_path)
+     232           9 :         .with_context(|| format!("`create_dir_all` failed for `{src_path:?}`"))?;
+     233             : 
+     234           9 :     let main_rs_path = src_path.join("main.rs");
+     235           9 :     write(&main_rs_path, "fn main() {}")
+     236           9 :         .with_context(|| format!("Could not write to {main_rs_path:?}"))?;
+     237             : 
+     238           9 :     Ok(tempdir)
+     239           9 : }
+     240             : 
+     241           9 : fn manifest_contents(dep_name: &str, details: &TomlDetailedDependency) -> Result<String> {
+     242           9 :     let details = toml::to_string(details)?;
+     243             : 
+     244           9 :     Ok(format!(
+     245           9 :         r#"
+     246           9 : [package]
+     247           9 : name = "dummy-package"
+     248           9 : version = "0.1.0"
+     249           9 : edition = "2021"
+     250           9 : publish = false
+     251           9 : 
+     252           9 : [dependencies.{dep_name}]
+     253           9 : {details}
+     254           9 : "#
+     255           9 :     ))
+     256           9 : }
+     257             : 
+     258           9 : fn inject_dummy_dependencies(
+     259           9 :     dep_path: &Path,
+     260           9 :     dep_name: &str,
+     261           9 :     checkout_path: &Path,
+     262           9 : ) -> Result<BTreeMap<OsString, NamedTempDir>> {
+     263           9 :     let mut injected_dependencies = BTreeMap::new();
+     264           9 :     #[cfg_attr(dylint_lib = "general", allow(non_local_effect_before_error_return))]
+     265          18 :     for_each_subdir(checkout_path, |subdir, path| {
+     266          18 :         injected_dependencies.insert(subdir.to_owned(), NamedTempDir(path.join(dep_name)));
+     267          18 :         fs_extra::dir::copy(dep_path, path, &fs_extra::dir::CopyOptions::default())?;
+     268          18 :         Ok(())
+     269          18 :     })?;
+     270           9 :     Ok(injected_dependencies)
+     271           9 : }
+     272             : 
+     273          11 : fn cargo_fetch(path: &Path) -> Result<Output> {
+     274          11 :     // smoelius: `cargo fetch` could fail, e.g., if a new checkouts subdirectory had to be created.
+     275          11 :     // But the command should still be executed.
+     276          11 :     // smoelius: Since stdout and stderr are captured, there is no need to use `.quiet(true)`.
+     277          11 :     // smoelius: We still want to hide the "Fetching ..." message, though.
+     278          11 :     dylint_internal::cargo::fetch("dummy package")
+     279          11 :         .quiet(dylint_internal::cargo::Quiet::MESSAGE)
+     280          11 :         .stable(true)
+     281          11 :         .build()
+     282          11 :         .args([
+     283          11 :             "--manifest-path",
+     284          11 :             &path.join("Cargo.toml").to_string_lossy(),
+     285          11 :         ])
+     286          11 :         .stdout(Stdio::piped())
+     287          11 :         .stderr(Stdio::piped())
+     288          11 :         .logged_output(false)
+     289          11 : }
+     290             : 
+     291          11 : fn cargo_metadata(path: &Path) -> Result<Metadata> {
+     292          11 :     MetadataCommand::new()
+     293          11 :         .current_dir(path)
+     294          11 :         .exec()
+     295          11 :         .map_err(Into::into)
+     296          11 : }
+     297             : 
+     298             : // smoelius: `ident` is based on the function of the same name at:
+     299             : // https://github.com/rust-lang/cargo/blob/1a498b6c1c119a79d677553862bffae96b97ad7f/src/cargo/sources/git/source.rs#L136-L147
+     300             : #[allow(clippy::manual_next_back)]
+     301             : #[cfg_attr(dylint_lib = "overscoped_allow", allow(overscoped_allow))]
+     302           9 : fn ident(url: &str) -> Result<String> {
+     303           9 :     let url = Url::parse(url)?;
+     304             : 
+     305           9 :     let canonical_url = CanonicalUrl::new(&url)?;
+     306             : 
+     307           9 :     let ident = canonical_url
+     308           9 :         .raw_canonicalized_url()
+     309           9 :         .path_segments()
+     310           9 :         .and_then(|s| s.rev().next())
+     311           9 :         .unwrap_or("");
+     312             : 
+     313           9 :     let ident = if ident.is_empty() { "_empty" } else { ident };
+     314             : 
+     315           9 :     Ok(format!("{}-{}", ident, short_hash(&canonical_url)))
+     316           9 : }
+     317             : 
+     318          11 : fn find_accessed_subdir<'a>(
+     319          11 :     dep_name: &str,
+     320          11 :     checkout_path: &Path,
+     321          11 :     injected_dependencies: &BTreeMap<OsString, NamedTempDir>,
+     322          11 :     metadata: Option<&'a Metadata>,
+     323          11 : ) -> Result<Cow<'a, Path>> {
+     324          11 :     let mut accessed = metadata
+     325          11 :         .map_or::<&[_], _>(&[], |metadata| &metadata.packages)
+     326          11 :         .iter()
+     327          18 :         .map(|package| {
+     328          18 :             if package.name == dep_name {
+     329           9 :                 let parent = package
+     330           9 :                     .manifest_path
+     331           9 :                     .parent()
+     332           9 :                     .ok_or_else(|| anyhow!("Could not get parent directory"))?;
+     333           9 :                 let grandparent = parent
+     334           9 :                     .parent()
+     335           9 :                     .ok_or_else(|| anyhow!("Could not get grandparent directory"))?;
+     336           9 :                 Ok(Some(Cow::Borrowed(grandparent.as_std_path())))
+     337             :             } else {
+     338           9 :                 Ok(None)
+     339             :             }
+     340          18 :         })
+     341          11 :         .filter_map(Result::transpose)
+     342          11 :         .collect::<Result<Vec<_>>>()?;
+     343             : 
+     344             :     // smoelius: If no subdirectories were accessed, then some checkouts subdirectory should have
+     345             :     // been created.
+     346          11 :     if accessed.is_empty() {
+     347           4 :         for_each_subdir(checkout_path, |subdir, path| {
+     348           4 :             if injected_dependencies.get(subdir).is_none() {
+     349           4 :                 accessed.push(Cow::Owned(path.to_path_buf()));
+     350           4 :             }
+     351           4 :             Ok(())
+     352           4 :         })?;
+     353           9 :     }
+     354             : 
+     355          11 :     ensure!(
+     356          11 :         accessed.len() <= 1,
+     357           2 :         "Multiple subdirectories were accessed: {:#?}",
+     358             :         accessed
+     359             :     );
+     360             : 
+     361           9 :     accessed
+     362           9 :         .into_iter()
+     363           9 :         .next()
+     364           9 :         .ok_or_else(|| anyhow!("Could not determine accessed subdirectory"))
+     365          11 : }
+     366             : 
+     367          11 : fn for_each_subdir(
+     368          11 :     checkout_path: &Path,
+     369          11 :     mut f: impl FnMut(&OsStr, &Path) -> Result<()>,
+     370          11 : ) -> Result<()> {
+     371          22 :     for entry in read_dir(checkout_path)
+     372          11 :         .with_context(|| format!("`read_dir` failed for {checkout_path:?}"))?
+     373             :     {
+     374          22 :         let entry = entry.with_context(|| format!("`read_dir` failed for {checkout_path:?}"))?;
+     375          22 :         let path = entry.path();
+     376          22 :         let file_name = path
+     377          22 :             .file_name()
+     378          22 :             .ok_or_else(|| anyhow!("Could not get file name"))?;
+     379          22 :         if !path.is_dir() {
+     380           0 :             continue;
+     381          22 :         }
+     382          22 :         f(file_name, &path)?;
+     383             :     }
+     384          11 :     Ok(())
+     385          11 : }
+     386             : 
+     387           2 : fn dummy_dependency_free_suffix(dep_name: &str, s: &str) -> String {
+     388           2 :     // smoelius: The `{..}` are a hack to prevent triggering `misleading_variable_name`.
+     389           2 :     let lines = { s.split_inclusive('\n') };
+     390           6 :     if let Some(i) = lines.clone().rev().position(|line| line.contains(dep_name)) {
+     391           2 :         let n = lines.clone().count();
+     392           2 :         lines.skip(n - i).collect()
+     393             :     } else {
+     394           0 :         s.to_owned()
+     395             :     }
+     396           2 : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/library_packages/cargo_cli/util/canonical_url.rs.func-sort-c.html b/coverage/dylint/src/library_packages/cargo_cli/util/canonical_url.rs.func-sort-c.html new file mode 100644 index 000000000..64b17346e --- /dev/null +++ b/coverage/dylint/src/library_packages/cargo_cli/util/canonical_url.rs.func-sort-c.html @@ -0,0 +1,84 @@ + + + + + + + LCOV - unnamed - dylint/src/library_packages/cargo_cli/util/canonical_url.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/library_packages/cargo_cli/util - canonical_url.rs (source / functions)HitTotalCoverage
Test:unnamedLines:293974.4 %
Date:2024-09-27 12:58:08Functions:33100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<dylint::library_packages::impl_::util::canonical_url::CanonicalUrl as core::hash::Hash>::hash::<core::hash::sip::SipHasher>9
<dylint::library_packages::impl_::util::canonical_url::CanonicalUrl>::new9
<dylint::library_packages::impl_::util::canonical_url::CanonicalUrl>::raw_canonicalized_url9
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/library_packages/cargo_cli/util/canonical_url.rs.func.html b/coverage/dylint/src/library_packages/cargo_cli/util/canonical_url.rs.func.html new file mode 100644 index 000000000..0f1f2cee0 --- /dev/null +++ b/coverage/dylint/src/library_packages/cargo_cli/util/canonical_url.rs.func.html @@ -0,0 +1,84 @@ + + + + + + + LCOV - unnamed - dylint/src/library_packages/cargo_cli/util/canonical_url.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/library_packages/cargo_cli/util - canonical_url.rs (source / functions)HitTotalCoverage
Test:unnamedLines:293974.4 %
Date:2024-09-27 12:58:08Functions:33100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<dylint::library_packages::impl_::util::canonical_url::CanonicalUrl as core::hash::Hash>::hash::<core::hash::sip::SipHasher>9
<dylint::library_packages::impl_::util::canonical_url::CanonicalUrl>::new9
<dylint::library_packages::impl_::util::canonical_url::CanonicalUrl>::raw_canonicalized_url9
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/library_packages/cargo_cli/util/canonical_url.rs.gcov.html b/coverage/dylint/src/library_packages/cargo_cli/util/canonical_url.rs.gcov.html new file mode 100644 index 000000000..3a28692b9 --- /dev/null +++ b/coverage/dylint/src/library_packages/cargo_cli/util/canonical_url.rs.gcov.html @@ -0,0 +1,168 @@ + + + + + + + LCOV - unnamed - dylint/src/library_packages/cargo_cli/util/canonical_url.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/library_packages/cargo_cli/util - canonical_url.rs (source / functions)HitTotalCoverage
Test:unnamedLines:293974.4 %
Date:2024-09-27 12:58:08Functions:33100.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : // smoelius: This file is a slight modification of:
+       2             : // https://github.com/rust-lang/cargo/blob/16ad1f2945dff5c7f3234257d5ab477ea86b7338/src/cargo/util/canonical_url.rs
+       3             : 
+       4             : #![allow(
+       5             :     clippy::case_sensitive_file_extension_comparisons,
+       6             :     clippy::missing_const_for_fn,
+       7             :     clippy::use_self,
+       8             :     clippy::unwrap_used
+       9             : )]
+      10             : #![cfg_attr(dylint_lib = "collapsible_unwrap", allow(collapsible_unwrap))]
+      11             : #![cfg_attr(
+      12             :     dylint_lib = "inconsistent_qualification",
+      13             :     allow(inconsistent_qualification)
+      14             : )]
+      15             : #![cfg_attr(dylint_lib = "overscoped_allow", allow(overscoped_allow))]
+      16             : 
+      17             : use anyhow::Result as CargoResult;
+      18             : 
+      19             : use std::hash::{self, Hash};
+      20             : use url::Url;
+      21             : 
+      22             : /// A newtype wrapper around `Url` which represents a "canonical" version of an
+      23             : /// original URL.
+      24             : ///
+      25             : /// A "canonical" url is only intended for internal comparison purposes in
+      26             : /// Cargo. It's to help paper over mistakes such as depending on
+      27             : /// `github.com/foo/bar` vs `github.com/foo/bar.git`. This is **only** for
+      28             : /// internal purposes within Cargo and provides no means to actually read the
+      29             : /// underlying string value of the `Url` it contains. This is intentional,
+      30             : /// because all fetching should still happen within the context of the original
+      31             : /// URL.
+      32             : #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
+      33             : pub struct CanonicalUrl(Url);
+      34             : 
+      35             : impl CanonicalUrl {
+      36           9 :     pub fn new(url: &Url) -> CargoResult<CanonicalUrl> {
+      37           9 :         let mut url = url.clone();
+      38           9 : 
+      39           9 :         // cannot-be-a-base-urls (e.g., `github.com:rust-lang/rustfmt.git`)
+      40           9 :         // are not supported.
+      41           9 :         if url.cannot_be_a_base() {
+      42           0 :             anyhow::bail!(
+      43           0 :                 "invalid url `{}`: cannot-be-a-base-URLs are not supported",
+      44           0 :                 url
+      45           0 :             )
+      46           9 :         }
+      47           9 : 
+      48           9 :         // Strip a trailing slash.
+      49           9 :         if url.path().ends_with('/') {
+      50           0 :             url.path_segments_mut().unwrap().pop_if_empty();
+      51           9 :         }
+      52             : 
+      53             :         // For GitHub URLs specifically, just lower-case everything. GitHub
+      54             :         // treats both the same, but they hash differently, and we're gonna be
+      55             :         // hashing them. This wants a more general solution, and also we're
+      56             :         // almost certainly not using the same case conversion rules that GitHub
+      57             :         // does. (See issue #84)
+      58           9 :         if url.host_str() == Some("github.com") {
+      59           9 :             url = format!("https{}", &url[url::Position::AfterScheme..])
+      60           9 :                 .parse()
+      61           9 :                 .unwrap();
+      62           9 :             let path = url.path().to_lowercase();
+      63           9 :             url.set_path(&path);
+      64           9 :         }
+      65             : 
+      66             :         // Repos can generally be accessed with or without `.git` extension.
+      67           9 :         let needs_chopping = url.path().ends_with(".git");
+      68           9 :         if needs_chopping {
+      69           0 :             let last = {
+      70           0 :                 let last = url.path_segments().unwrap().next_back().unwrap();
+      71           0 :                 last[..last.len() - 4].to_owned()
+      72           0 :             };
+      73           0 :             url.path_segments_mut().unwrap().pop().push(&last);
+      74           9 :         }
+      75             : 
+      76           9 :         Ok(CanonicalUrl(url))
+      77           9 :     }
+      78             : 
+      79             :     /// Returns the raw canonicalized URL, although beware that this should
+      80             :     /// never be used/displayed/etc, it should only be used for internal data
+      81             :     /// structures and hashes and such.
+      82           9 :     pub fn raw_canonicalized_url(&self) -> &Url {
+      83           9 :         &self.0
+      84           9 :     }
+      85             : }
+      86             : 
+      87             : // See comment in `source_id.rs` for why we explicitly use `as_str()` here.
+      88             : impl Hash for CanonicalUrl {
+      89           9 :     fn hash<S: hash::Hasher>(&self, into: &mut S) {
+      90           9 :         self.0.as_str().hash(into);
+      91           9 :     }
+      92             : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/library_packages/cargo_cli/util/hex.rs.func-sort-c.html b/coverage/dylint/src/library_packages/cargo_cli/util/hex.rs.func-sort-c.html new file mode 100644 index 000000000..737114870 --- /dev/null +++ b/coverage/dylint/src/library_packages/cargo_cli/util/hex.rs.func-sort-c.html @@ -0,0 +1,88 @@ + + + + + + + LCOV - unnamed - dylint/src/library_packages/cargo_cli/util/hex.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/library_packages/cargo_cli/util - hex.rs (source / functions)HitTotalCoverage
Test:unnamedLines:112152.4 %
Date:2024-09-27 12:58:08Functions:3475.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint::library_packages::impl_::util::hex::hash_u64_file0
dylint::library_packages::impl_::util::hex::hash_u64::<&dylint::library_packages::impl_::util::canonical_url::CanonicalUrl>9
dylint::library_packages::impl_::util::hex::short_hash::<dylint::library_packages::impl_::util::canonical_url::CanonicalUrl>9
dylint::library_packages::impl_::util::hex::to_hex9
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/library_packages/cargo_cli/util/hex.rs.func.html b/coverage/dylint/src/library_packages/cargo_cli/util/hex.rs.func.html new file mode 100644 index 000000000..b1b42b03a --- /dev/null +++ b/coverage/dylint/src/library_packages/cargo_cli/util/hex.rs.func.html @@ -0,0 +1,88 @@ + + + + + + + LCOV - unnamed - dylint/src/library_packages/cargo_cli/util/hex.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/library_packages/cargo_cli/util - hex.rs (source / functions)HitTotalCoverage
Test:unnamedLines:112152.4 %
Date:2024-09-27 12:58:08Functions:3475.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint::library_packages::impl_::util::hex::hash_u64::<&dylint::library_packages::impl_::util::canonical_url::CanonicalUrl>9
dylint::library_packages::impl_::util::hex::hash_u64_file0
dylint::library_packages::impl_::util::hex::short_hash::<dylint::library_packages::impl_::util::canonical_url::CanonicalUrl>9
dylint::library_packages::impl_::util::hex::to_hex9
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/library_packages/cargo_cli/util/hex.rs.gcov.html b/coverage/dylint/src/library_packages/cargo_cli/util/hex.rs.gcov.html new file mode 100644 index 000000000..88c9ca132 --- /dev/null +++ b/coverage/dylint/src/library_packages/cargo_cli/util/hex.rs.gcov.html @@ -0,0 +1,116 @@ + + + + + + + LCOV - unnamed - dylint/src/library_packages/cargo_cli/util/hex.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/library_packages/cargo_cli/util - hex.rs (source / functions)HitTotalCoverage
Test:unnamedLines:112152.4 %
Date:2024-09-27 12:58:08Functions:3475.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : // smoelius: This file is a slight modification of:
+       2             : // https://github.com/rust-lang/cargo/blob/aab416f6e68d555e8c9a0f02098a24946e0725fb/src/cargo/util/hex.rs
+       3             : 
+       4             : #![allow(deprecated)]
+       5             : #![allow(clippy::module_name_repetitions)]
+       6             : #![cfg_attr(dylint_lib = "overscoped_allow", allow(overscoped_allow))]
+       7             : #![cfg_attr(dylint_lib = "supplementary", allow(unnamed_constant))]
+       8             : 
+       9             : type StableHasher = std::hash::SipHasher;
+      10             : 
+      11             : use std::fs::File;
+      12             : use std::hash::{Hash, Hasher};
+      13             : use std::io::Read;
+      14             : 
+      15           9 : pub fn to_hex(num: u64) -> String {
+      16           9 :     hex::encode(num.to_le_bytes())
+      17           9 : }
+      18             : 
+      19           9 : pub fn hash_u64<H: Hash>(hashable: H) -> u64 {
+      20           9 :     let mut hasher = StableHasher::new();
+      21           9 :     hashable.hash(&mut hasher);
+      22           9 :     hasher.finish()
+      23           9 : }
+      24             : 
+      25           0 : pub fn hash_u64_file(mut file: &File) -> std::io::Result<u64> {
+      26           0 :     let mut hasher = StableHasher::new();
+      27           0 :     let mut buf = [0; 64 * 1024];
+      28             :     loop {
+      29           0 :         let n = file.read(&mut buf)?;
+      30           0 :         if n == 0 {
+      31           0 :             break;
+      32           0 :         }
+      33           0 :         hasher.write(&buf[..n]);
+      34             :     }
+      35           0 :     Ok(hasher.finish())
+      36           0 : }
+      37             : 
+      38           9 : pub fn short_hash<H: Hash>(hashable: &H) -> String {
+      39           9 :     to_hex(hash_u64(hashable))
+      40           9 : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/library_packages/cargo_cli/util/index-sort-f.html b/coverage/dylint/src/library_packages/cargo_cli/util/index-sort-f.html new file mode 100644 index 000000000..e4de16245 --- /dev/null +++ b/coverage/dylint/src/library_packages/cargo_cli/util/index-sort-f.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - unnamed - dylint/src/library_packages/cargo_cli/util + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/library_packages/cargo_cli/utilHitTotalCoverage
Test:unnamedLines:406066.7 %
Date:2024-09-27 12:58:08Functions:6785.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
hex.rs +
52.4%52.4%
+
52.4 %11 / 2175.0 %3 / 4
canonical_url.rs +
74.4%74.4%
+
74.4 %29 / 39100.0 %3 / 3
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/library_packages/cargo_cli/util/index-sort-l.html b/coverage/dylint/src/library_packages/cargo_cli/util/index-sort-l.html new file mode 100644 index 000000000..be57ce0cb --- /dev/null +++ b/coverage/dylint/src/library_packages/cargo_cli/util/index-sort-l.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - unnamed - dylint/src/library_packages/cargo_cli/util + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/library_packages/cargo_cli/utilHitTotalCoverage
Test:unnamedLines:406066.7 %
Date:2024-09-27 12:58:08Functions:6785.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
hex.rs +
52.4%52.4%
+
52.4 %11 / 2175.0 %3 / 4
canonical_url.rs +
74.4%74.4%
+
74.4 %29 / 39100.0 %3 / 3
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/library_packages/cargo_cli/util/index.html b/coverage/dylint/src/library_packages/cargo_cli/util/index.html new file mode 100644 index 000000000..7d0476dd5 --- /dev/null +++ b/coverage/dylint/src/library_packages/cargo_cli/util/index.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - unnamed - dylint/src/library_packages/cargo_cli/util + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/library_packages/cargo_cli/utilHitTotalCoverage
Test:unnamedLines:406066.7 %
Date:2024-09-27 12:58:08Functions:6785.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
canonical_url.rs +
74.4%74.4%
+
74.4 %29 / 39100.0 %3 / 3
hex.rs +
52.4%52.4%
+
52.4 %11 / 2175.0 %3 / 4
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/library_packages/index-sort-f.html b/coverage/dylint/src/library_packages/index-sort-f.html new file mode 100644 index 000000000..e156ae062 --- /dev/null +++ b/coverage/dylint/src/library_packages/index-sort-f.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - unnamed - dylint/src/library_packages + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/library_packagesHitTotalCoverage
Test:unnamedLines:26130186.7 %
Date:2024-09-27 12:58:08Functions:356157.4 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
mod.rs +
86.7%86.7%
+
86.7 %261 / 30157.4 %35 / 61
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/library_packages/index-sort-l.html b/coverage/dylint/src/library_packages/index-sort-l.html new file mode 100644 index 000000000..d284b9766 --- /dev/null +++ b/coverage/dylint/src/library_packages/index-sort-l.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - unnamed - dylint/src/library_packages + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/library_packagesHitTotalCoverage
Test:unnamedLines:26130186.7 %
Date:2024-09-27 12:58:08Functions:356157.4 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
mod.rs +
86.7%86.7%
+
86.7 %261 / 30157.4 %35 / 61
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/library_packages/index.html b/coverage/dylint/src/library_packages/index.html new file mode 100644 index 000000000..45a3f964b --- /dev/null +++ b/coverage/dylint/src/library_packages/index.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - unnamed - dylint/src/library_packages + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/library_packagesHitTotalCoverage
Test:unnamedLines:26130186.7 %
Date:2024-09-27 12:58:08Functions:356157.4 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
mod.rs +
86.7%86.7%
+
86.7 %261 / 30157.4 %35 / 61
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/library_packages/mod.rs.func-sort-c.html b/coverage/dylint/src/library_packages/mod.rs.func-sort-c.html new file mode 100644 index 000000000..70c299bdf --- /dev/null +++ b/coverage/dylint/src/library_packages/mod.rs.func-sort-c.html @@ -0,0 +1,316 @@ + + + + + + + LCOV - unnamed - dylint/src/library_packages/mod.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/library_packages - mod.rs (source / functions)HitTotalCoverage
Test:unnamedLines:26130186.7 %
Date:2024-09-27 12:58:08Functions:356157.4 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::expecting0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_bool::<toml::de::Error>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_borrowed_bytes::<_>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_borrowed_str::<serde_json::error::Error>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_bytes::<_>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_char::<_>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_f32::<_>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_f64::<toml::de::Error>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_i16::<_>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_i32::<_>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_i64::<toml::de::Error>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_i8::<_>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_u16::<_>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_u32::<_>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_u64::<_>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_u8::<_>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_unit::<_>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__Visitor as serde::de::Visitor>::expecting0
<dylint::library_packages::Package as core::cmp::Ord>::cmp0
<dylint::library_packages::Package as core::cmp::PartialEq>::eq0
<dylint::library_packages::Package as core::cmp::PartialOrd>::partial_cmp0
dylint::library_packages::build_library::{closure#0}0
dylint::library_packages::from_opts::{closure#0}0
dylint::library_packages::from_opts::{closure#1}0
dylint::library_packages::from_opts::{closure#2}0
dylint::library_packages::package_library_name::{closure#1}0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__Field as serde::de::Deserialize>::deserialize::<toml::value::Value>1
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_str::<toml::de::Error>1
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__Visitor as serde::de::Visitor>::visit_map::<&mut toml::value::MapDeserializer>1
dylint::library_packages::library_packages_from_dylint_toml1
dylint::library_packages::library_packages_from_dylint_toml::{closure#0}1
dylint::library_packages::library_packages_from_dylint_toml::{closure#1}1
dylint::library_packages::library_packages_from_dylint_toml::{closure#2}1
dylint::library_packages::toml_detailed_dependency::{closure#0}1
dylint::library_packages::from_opts2
dylint::library_packages::to_map_entry::{closure#0}2
dylint::library_packages::library_packages::{closure#1}5
dylint::library_packages::to_map_entry10
dylint::library_packages::build_library21
<dylint::library_packages::Package>::path24
dylint::library_packages::library_packages_from_dylint_metadata24
dylint::library_packages::library_packages_from_dylint_metadata::{closure#0}24
dylint::library_packages::library_packages27
dylint::library_packages::from_dylint_toml29
dylint::library_packages::library_package::{closure#0}30
dylint::library_packages::package_id30
dylint::library_packages::package_library_name30
dylint::library_packages::package_library_name::{closure#0}30
dylint::library_packages::package_library_name::{closure#0}::{closure#0}30
dylint::library_packages::package_with_root30
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__Visitor as serde::de::Visitor>::visit_map::<&mut serde_json::value::de::MapDeserializer>31
dylint::library_packages::from_workspace_metadata34
dylint::library_packages::library_package34
dylint::library_packages::library_packages::{closure#0}34
dylint::library_packages::toml_detailed_dependency34
dylint::library_packages::cargo_metadata::{closure#0}35
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__Field as serde::de::Deserialize>::deserialize::<serde_json::value::de::MapKeyDeserializer>45
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_str::<serde_json::error::Error>45
<dylint::library_packages::Package>::target_directory45
dylint::library_packages::dylint_metadata51
dylint::library_packages::cargo_metadata116
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/library_packages/mod.rs.func.html b/coverage/dylint/src/library_packages/mod.rs.func.html new file mode 100644 index 000000000..11f76b8bc --- /dev/null +++ b/coverage/dylint/src/library_packages/mod.rs.func.html @@ -0,0 +1,316 @@ + + + + + + + LCOV - unnamed - dylint/src/library_packages/mod.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/library_packages - mod.rs (source / functions)HitTotalCoverage
Test:unnamedLines:26130186.7 %
Date:2024-09-27 12:58:08Functions:356157.4 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__Field as serde::de::Deserialize>::deserialize::<serde_json::value::de::MapKeyDeserializer>45
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__Field as serde::de::Deserialize>::deserialize::<toml::value::Value>1
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::expecting0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_bool::<toml::de::Error>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_borrowed_bytes::<_>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_borrowed_str::<serde_json::error::Error>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_bytes::<_>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_char::<_>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_f32::<_>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_f64::<toml::de::Error>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_i16::<_>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_i32::<_>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_i64::<toml::de::Error>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_i8::<_>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_str::<serde_json::error::Error>45
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_str::<toml::de::Error>1
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_u16::<_>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_u32::<_>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_u64::<_>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_u8::<_>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__FieldVisitor as serde::de::Visitor>::visit_unit::<_>0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__Visitor as serde::de::Visitor>::expecting0
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__Visitor as serde::de::Visitor>::visit_map::<&mut serde_json::value::de::MapDeserializer>31
<<dylint::library_packages::Library as serde::de::Deserialize>::deserialize::__Visitor as serde::de::Visitor>::visit_map::<&mut toml::value::MapDeserializer>1
<dylint::library_packages::Package as core::cmp::Ord>::cmp0
<dylint::library_packages::Package as core::cmp::PartialEq>::eq0
<dylint::library_packages::Package as core::cmp::PartialOrd>::partial_cmp0
<dylint::library_packages::Package>::path24
<dylint::library_packages::Package>::target_directory45
dylint::library_packages::build_library21
dylint::library_packages::build_library::{closure#0}0
dylint::library_packages::cargo_metadata116
dylint::library_packages::cargo_metadata::{closure#0}35
dylint::library_packages::dylint_metadata51
dylint::library_packages::from_dylint_toml29
dylint::library_packages::from_opts2
dylint::library_packages::from_opts::{closure#0}0
dylint::library_packages::from_opts::{closure#1}0
dylint::library_packages::from_opts::{closure#2}0
dylint::library_packages::from_workspace_metadata34
dylint::library_packages::library_package34
dylint::library_packages::library_package::{closure#0}30
dylint::library_packages::library_packages27
dylint::library_packages::library_packages::{closure#0}34
dylint::library_packages::library_packages::{closure#1}5
dylint::library_packages::library_packages_from_dylint_metadata24
dylint::library_packages::library_packages_from_dylint_metadata::{closure#0}24
dylint::library_packages::library_packages_from_dylint_toml1
dylint::library_packages::library_packages_from_dylint_toml::{closure#0}1
dylint::library_packages::library_packages_from_dylint_toml::{closure#1}1
dylint::library_packages::library_packages_from_dylint_toml::{closure#2}1
dylint::library_packages::package_id30
dylint::library_packages::package_library_name30
dylint::library_packages::package_library_name::{closure#0}30
dylint::library_packages::package_library_name::{closure#0}::{closure#0}30
dylint::library_packages::package_library_name::{closure#1}0
dylint::library_packages::package_with_root30
dylint::library_packages::to_map_entry10
dylint::library_packages::to_map_entry::{closure#0}2
dylint::library_packages::toml_detailed_dependency34
dylint::library_packages::toml_detailed_dependency::{closure#0}1
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/library_packages/mod.rs.gcov.html b/coverage/dylint/src/library_packages/mod.rs.gcov.html new file mode 100644 index 000000000..e4a2eb6aa --- /dev/null +++ b/coverage/dylint/src/library_packages/mod.rs.gcov.html @@ -0,0 +1,566 @@ + + + + + + + LCOV - unnamed - dylint/src/library_packages/mod.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/library_packages - mod.rs (source / functions)HitTotalCoverage
Test:unnamedLines:26130186.7 %
Date:2024-09-27 12:58:08Functions:356157.4 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : use crate::{error::warn, opts};
+       2             : use anyhow::{anyhow, bail, ensure, Context, Result};
+       3             : use cargo_metadata::{Error, Metadata, MetadataCommand, Package as MetadataPackage};
+       4             : use cargo_util_schemas::manifest::{StringOrVec, TomlDetailedDependency};
+       5             : use dylint_internal::{config, env, library_filename, rustup::SanitizeEnvironment, CommandExt};
+       6             : use glob::glob;
+       7             : use if_chain::if_chain;
+       8             : use once_cell::sync::OnceCell;
+       9             : use serde::{de::IntoDeserializer, Deserialize};
+      10             : use std::path::{Path, PathBuf};
+      11             : 
+      12             : // smoelius: If both `__cargo_cli` and `__cargo_lib` are enabled, assume the user built
+      13             : // `cargo-dylint` with `--features=cargo-lib` and forgot `--no-default-features`.
+      14             : #[cfg(all(feature = "__cargo_cli", not(feature = "__cargo_lib")))]
+      15             : #[path = "cargo_cli/mod.rs"]
+      16             : mod impl_;
+      17             : 
+      18             : #[cfg(feature = "__cargo_lib")]
+      19             : #[path = "cargo_lib/mod.rs"]
+      20             : mod impl_;
+      21             : 
+      22             : use impl_::{dependency_source_id_and_root, GlobalContext, PackageId, SourceId};
+      23             : 
+      24             : type Object = serde_json::Map<String, serde_json::Value>;
+      25             : 
+      26             : #[derive(Clone, Debug)]
+      27             : pub struct Package {
+      28             :     metadata: &'static Metadata,
+      29             :     pub root: PathBuf,
+      30             :     pub id: PackageId,
+      31             :     pub lib_name: String,
+      32             :     pub toolchain: String,
+      33             : }
+      34             : 
+      35             : impl Eq for Package {}
+      36             : 
+      37             : impl PartialEq for Package {
+      38           0 :     fn eq(&self, other: &Self) -> bool {
+      39           0 :         (&self.root, &self.id, &self.lib_name, &self.toolchain)
+      40           0 :             == (&other.root, &other.id, &other.lib_name, &other.toolchain)
+      41           0 :     }
+      42             : }
+      43             : 
+      44             : impl Ord for Package {
+      45           0 :     fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+      46           0 :         (&self.root, &self.id, &self.lib_name, &self.toolchain).cmp(&(
+      47           0 :             &other.root,
+      48           0 :             &other.id,
+      49           0 :             &other.lib_name,
+      50           0 :             &other.toolchain,
+      51           0 :         ))
+      52           0 :     }
+      53             : }
+      54             : 
+      55             : impl PartialOrd for Package {
+      56           0 :     fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+      57           0 :         Some(self.cmp(other))
+      58           0 :     }
+      59             : }
+      60             : 
+      61             : impl Package {
+      62          45 :     pub fn target_directory(&self) -> PathBuf {
+      63          45 :         self.metadata
+      64          45 :             .target_directory
+      65          45 :             .join("dylint/libraries")
+      66          45 :             .join(&self.toolchain)
+      67          45 :             .into_std_path_buf()
+      68          45 :     }
+      69             : 
+      70          24 :     pub fn path(&self) -> PathBuf {
+      71          24 :         self.target_directory()
+      72          24 :             .join("release")
+      73          24 :             .join(library_filename(&self.lib_name, &self.toolchain))
+      74          24 :     }
+      75             : }
+      76             : 
+      77          78 : #[derive(Debug, Deserialize)]
+      78             : struct Library {
+      79             :     pattern: Option<StringOrVec>,
+      80             :     #[serde(flatten)]
+      81             :     details: TomlDetailedDependency,
+      82             : }
+      83             : 
+      84           2 : pub fn from_opts(opts: &opts::Dylint) -> Result<Vec<Package>> {
+      85           2 :     let lib_sel = opts.library_selection();
+      86             : 
+      87           2 :     let maybe_metadata = cargo_metadata(opts)?;
+      88             : 
+      89           2 :     let metadata = maybe_metadata.ok_or_else(|| anyhow!("Could not read cargo metadata"))?;
+      90             : 
+      91           2 :     ensure!(
+      92           2 :         lib_sel.paths.len() <= 1,
+      93           0 :         "At most one library package can be named with `--path`"
+      94             :     );
+      95             : 
+      96           2 :     let path = if let Some(path) = lib_sel.paths.first() {
+      97           2 :         let canonical_path = dunce::canonicalize(path)
+      98           2 :             .with_context(|| format!("Could not canonicalize {path:?}"))?;
+      99           2 :         Some(canonical_path.to_string_lossy().to_string())
+     100             :     } else {
+     101           0 :         None
+     102             :     };
+     103             : 
+     104           2 :     let toml: toml::map::Map<_, _> = vec![
+     105           2 :         to_map_entry("path", path.as_ref()),
+     106           2 :         to_map_entry("git", lib_sel.git.as_ref()),
+     107           2 :         to_map_entry("branch", lib_sel.branch.as_ref()),
+     108           2 :         to_map_entry("tag", lib_sel.tag.as_ref()),
+     109           2 :         to_map_entry("rev", lib_sel.rev.as_ref()),
+     110           2 :     ]
+     111           2 :     .into_iter()
+     112           2 :     .flatten()
+     113           2 :     .collect();
+     114             : 
+     115           2 :     let details = TomlDetailedDependency::deserialize(toml.into_deserializer())?;
+     116             : 
+     117           2 :     let library = Library {
+     118           2 :         details,
+     119           2 :         pattern: lib_sel
+     120           2 :             .pattern
+     121           2 :             .as_ref()
+     122           2 :             .map(|pattern| StringOrVec(vec![pattern.clone()])),
+     123           2 :     };
+     124           2 : 
+     125           2 :     library_packages(opts, metadata, &[library])
+     126           2 : }
+     127             : 
+     128          10 : fn to_map_entry(key: &str, value: Option<&String>) -> Option<(String, toml::Value)> {
+     129          10 :     value
+     130          10 :         .cloned()
+     131          10 :         .map(|s| (String::from(key), toml::Value::from(s)))
+     132          10 : }
+     133             : 
+     134          34 : pub fn from_workspace_metadata(opts: &opts::Dylint) -> Result<Vec<Package>> {
+     135             :     if_chain! {
+     136          34 :         if let Some(metadata) = cargo_metadata(opts)?;
+     137          29 :         if let Some(object) = dylint_metadata(opts)?;
+     138             :         then {
+     139          24 :             library_packages_from_dylint_metadata(opts, metadata, object)
+     140             :         } else {
+     141           5 :             Ok(vec![])
+     142             :         }
+     143             :     }
+     144          34 : }
+     145             : 
+     146             : #[allow(clippy::module_name_repetitions)]
+     147          51 : pub fn dylint_metadata(opts: &opts::Dylint) -> Result<Option<&'static Object>> {
+     148             :     if_chain! {
+     149          51 :         if let Some(metadata) = cargo_metadata(opts)?;
+     150          48 :         if let serde_json::Value::Object(object) = &metadata.workspace_metadata;
+     151          41 :         if let Some(value) = object.get("dylint");
+     152             :         then {
+     153          41 :             if let serde_json::Value::Object(subobject) = value {
+     154          41 :                 Ok(Some(subobject))
+     155             :             } else {
+     156           0 :                 bail!("`dylint` value must be a map")
+     157             :             }
+     158             :         } else {
+     159           0 :             Ok(None)
+     160             :         }
+     161             :     }
+     162          51 : }
+     163             : 
+     164             : static CARGO_METADATA: OnceCell<Option<Metadata>> = OnceCell::new();
+     165             : 
+     166         116 : fn cargo_metadata(opts: &opts::Dylint) -> Result<Option<&'static Metadata>> {
+     167         116 :     CARGO_METADATA
+     168         116 :         .get_or_try_init(|| {
+     169          35 :             let lib_sel = opts.library_selection();
+     170          35 : 
+     171          35 :             if lib_sel.no_metadata {
+     172           4 :                 return Ok(None);
+     173          31 :             }
+     174          31 : 
+     175          31 :             let mut command = MetadataCommand::new();
+     176             : 
+     177          31 :             if let Some(path) = &lib_sel.manifest_path {
+     178           5 :                 command.manifest_path(path);
+     179          26 :             }
+     180             : 
+     181          31 :             match command.exec() {
+     182          31 :                 Ok(metadata) => Ok(Some(metadata)),
+     183           0 :                 Err(err) => {
+     184           0 :                     if lib_sel.manifest_path.is_none() {
+     185           0 :                         if_chain! {
+     186           0 :                             if let Error::CargoMetadata { stderr } = err;
+     187           0 :                             if let Some(line) = stderr.lines().next();
+     188           0 :                             if !line.starts_with("error: could not find `Cargo.toml`");
+     189             :                             then {
+     190           0 :                                 warn(opts, line.strip_prefix("error: ").unwrap_or(line));
+     191             :                             }
+     192             :                         }
+     193           0 :                         Ok(None)
+     194             :                     } else {
+     195           0 :                         Err(err.into())
+     196             :                     }
+     197             :                 }
+     198             :             }
+     199         116 :         })
+     200         116 :         .map(Option::as_ref)
+     201         116 : }
+     202             : 
+     203          24 : fn library_packages_from_dylint_metadata(
+     204          24 :     opts: &opts::Dylint,
+     205          24 :     metadata: &'static Metadata,
+     206          24 :     object: &Object,
+     207          24 : ) -> Result<Vec<Package>> {
+     208          24 :     let libraries = object
+     209          24 :         .iter()
+     210          24 :         .map(|(key, value)| {
+     211          24 :             if key == "libraries" {
+     212          24 :                 let libraries = serde_json::from_value::<Vec<Library>>(value.clone())?;
+     213          24 :                 library_packages(opts, metadata, &libraries)
+     214             :             } else {
+     215           0 :                 bail!("Unknown key `{}`", key)
+     216             :             }
+     217          24 :         })
+     218          24 :         .collect::<Result<Vec<_>>>()?;
+     219          19 :     Ok(libraries.into_iter().flatten().collect())
+     220          24 : }
+     221             : 
+     222          29 : pub fn from_dylint_toml(opts: &opts::Dylint) -> Result<Vec<Package>> {
+     223             :     if_chain! {
+     224          29 :         if let Some(metadata) = cargo_metadata(opts)?;
+     225          24 :         let _ = config::try_init_with_metadata(metadata)?;
+     226          24 :         if let Some(table) = config::get();
+     227             :         then {
+     228           1 :             library_packages_from_dylint_toml(opts, metadata, table)
+     229             :         } else {
+     230           5 :             Ok(vec![])
+     231             :         }
+     232             :     }
+     233          29 : }
+     234             : 
+     235           1 : fn library_packages_from_dylint_toml(
+     236           1 :     opts: &opts::Dylint,
+     237           1 :     metadata: &'static Metadata,
+     238           1 :     table: &toml::Table,
+     239           1 : ) -> Result<Vec<Package>> {
+     240           1 :     let Some(config_metadata) = table
+     241           1 :         .get("workspace")
+     242           1 :         .and_then(toml::Value::as_table)
+     243           1 :         .and_then(|table| table.get("metadata"))
+     244           1 :         .and_then(toml::Value::as_table)
+     245           1 :         .and_then(|table| table.get("dylint"))
+     246             :     else {
+     247           0 :         return Ok(Vec::new());
+     248             :     };
+     249             : 
+     250           1 :     let Some(table) = config_metadata.as_table() else {
+     251           0 :         bail!("`dylint` value must be a table");
+     252             :     };
+     253             : 
+     254           1 :     let libraries = table
+     255           1 :         .iter()
+     256           1 :         .map(|(key, value)| {
+     257           1 :             if key == "libraries" {
+     258           1 :                 let libraries = Vec::<Library>::deserialize(value.clone().into_deserializer())?;
+     259           1 :                 library_packages(opts, metadata, &libraries)
+     260             :             } else {
+     261           0 :                 bail!("Unknown key `{}`", key)
+     262             :             }
+     263           1 :         })
+     264           1 :         .collect::<Result<Vec<_>>>()?;
+     265           1 :     Ok(libraries.into_iter().flatten().collect())
+     266           1 : }
+     267             : 
+     268          27 : fn library_packages(
+     269          27 :     opts: &opts::Dylint,
+     270          27 :     metadata: &'static Metadata,
+     271          27 :     libraries: &[Library],
+     272          27 : ) -> Result<Vec<Package>> {
+     273          27 :     let gctx = GlobalContext::default()?;
+     274             : 
+     275          27 :     let packages = libraries
+     276          27 :         .iter()
+     277          34 :         .map(|library| library_package(opts, metadata, &gctx, library))
+     278          27 :         .collect::<Result<Vec<_>>>()
+     279          27 :         .with_context(|| "Could not build metadata entries")?;
+     280             : 
+     281          22 :     Ok(packages.into_iter().flatten().collect())
+     282          27 : }
+     283             : 
+     284          34 : fn library_package(
+     285          34 :     opts: &opts::Dylint,
+     286          34 :     metadata: &'static Metadata,
+     287          34 :     gctx: &GlobalContext,
+     288          34 :     library: &Library,
+     289          34 : ) -> Result<Vec<Package>> {
+     290          34 :     let details = toml_detailed_dependency(library)?;
+     291             : 
+     292             :     // smoelius: The dependency root cannot be canonicalized here. It could contain a `glob` pattern
+     293             :     // (e.g., `*`), because Dylint allows `path` entries to contain `glob` patterns.
+     294          33 :     let (source_id, dependency_root) =
+     295          33 :         dependency_source_id_and_root(opts, metadata, gctx, details)?;
+     296             : 
+     297          33 :     let patterns = if let Some(StringOrVec(patterns)) = &library.pattern {
+     298          10 :         patterns.clone()
+     299             :     } else {
+     300          23 :         vec![String::new()]
+     301             :     };
+     302             : 
+     303          33 :     let mut paths = Vec::new();
+     304          63 :     for pattern in patterns {
+     305          34 :         let results = glob(&dependency_root.join(&pattern).to_string_lossy())?;
+     306             : 
+     307          34 :         let mut matched = false;
+     308          64 :         for result in results {
+     309          32 :             let path = result?;
+     310             : 
+     311             :             // smoelius: Because `dependency_root` might not be absolute, `path` might not be
+     312             :             // absolute. So `path` must be normalized.
+     313          32 :             let path_buf = cargo_util::paths::normalize_path(&path);
+     314          32 : 
+     315          32 :             // smoelius: If `library.pattern` is set, verify the `path` that it matched is in
+     316          32 :             // `dependency_root`.
+     317          32 :             //
+     318          32 :             // Note that even if `library.pattern` is not set, the current loop must still be
+     319          32 :             // traversed. Recall, `dependency_root` could be a `glob` pattern. In such a
+     320          32 :             // case, the paths that it matches must be pushed onto `paths`.
+     321          32 :             if library.pattern.is_some() {
+     322             :                 // smoelius: Use `cargo_util::paths::normalize_path` instead of `canonicalize`
+     323             :                 // so as not to "taint" the path with a path prefix on Windows.
+     324             :                 //
+     325             :                 // This problem keeps coming up. For example, it recently came up in:
+     326             :                 // https://github.com/trailofbits/dylint/pull/944
+     327          10 :                 let dependency_root = cargo_util::paths::normalize_path(&dependency_root);
+     328          10 :                 ensure!(
+     329          10 :                     path_buf.starts_with(&dependency_root),
+     330           2 :                     "Pattern `{pattern}` could refer to `{}`, which is outside of `{}`",
+     331           2 :                     path_buf.to_string_lossy(),
+     332           2 :                     dependency_root.to_string_lossy()
+     333             :                 );
+     334          22 :             }
+     335             : 
+     336          30 :             paths.push(path_buf);
+     337          30 :             matched = true;
+     338             :         }
+     339             : 
+     340          32 :         ensure!(matched, "No paths matched `{}`", pattern);
+     341             :     }
+     342             : 
+     343             :     // smoelius: Collecting the package ids before building reveals missing/unparsable `Cargo.toml`
+     344             :     // files sooner.
+     345             : 
+     346             :     // smoelius: Why are we doing this complicated dance at all? Because we want to leverage Cargo's
+     347             :     // download cache. But we also want to support git repositories with libraries that use
+     348             :     // different compiler versions. And we have to work around the fact that "all projects within a
+     349             :     // workspace are intended to be built with the same version of the compiler"
+     350             :     // (https://github.com/rust-lang/rustup/issues/1399#issuecomment-383376082).
+     351             : 
+     352             :     // smoelius: Experiments suggest that a considerable amount of Dylint's start up time is spent
+     353             :     // in the following "loop," and a considerable (though not necessarily dominant) fraction of
+     354             :     // that is spent in `active_toolchain`.
+     355          29 :     let packages = paths
+     356          29 :         .into_iter()
+     357          30 :         .map(|path| {
+     358          30 :             if path.is_dir() {
+     359             :                 // smoelius: Ignore subdirectories that do not contain packages.
+     360          30 :                 let Ok(package) = package_with_root(&path) else {
+     361           0 :                     return Ok(None);
+     362             :                 };
+     363             :                 // smoelius: When `__cargo_cli` is enabled, `source_id`'s type is `String`.
+     364             :                 #[allow(clippy::clone_on_copy)]
+     365          30 :                 let package_id = package_id(&package, source_id.clone());
+     366          30 :                 let lib_name = package_library_name(&package)?;
+     367          30 :                 let toolchain = dylint_internal::rustup::active_toolchain(&path)?;
+     368          30 :                 Ok(Some(Package {
+     369          30 :                     metadata,
+     370          30 :                     root: path,
+     371          30 :                     id: package_id,
+     372          30 :                     lib_name,
+     373          30 :                     toolchain,
+     374          30 :                 }))
+     375             :             } else {
+     376           0 :                 Ok(None)
+     377             :             }
+     378          30 :         })
+     379          29 :         .collect::<Result<Vec<_>>>()?;
+     380             : 
+     381          29 :     Ok(packages.into_iter().flatten().collect())
+     382          34 : }
+     383             : 
+     384          34 : fn toml_detailed_dependency(library: &Library) -> Result<&TomlDetailedDependency> {
+     385          34 :     let mut unused_keys = library
+     386          34 :         .details
+     387          34 :         ._unused_keys
+     388          34 :         .keys()
+     389          34 :         .cloned()
+     390          34 :         .collect::<Vec<_>>();
+     391          34 : 
+     392          34 :     #[allow(clippy::format_collect)]
+     393          34 :     if !unused_keys.is_empty() {
+     394           1 :         unused_keys.sort_unstable();
+     395           1 :         bail!(
+     396           1 :             "Unknown library keys:{}",
+     397           1 :             unused_keys
+     398           1 :                 .iter()
+     399           1 :                 .map(|name| format!("\n    {name}"))
+     400           1 :                 .collect::<String>()
+     401           1 :         );
+     402          33 :     }
+     403          33 : 
+     404          33 :     Ok(&library.details)
+     405          34 : }
+     406             : 
+     407          30 : fn package_with_root(package_root: &Path) -> Result<MetadataPackage> {
+     408             :     // smoelius: For the long term, we should investigate having a "cache" that maps paths to
+     409             :     // `cargo_metadata::Metadata`.
+     410          30 :     let metadata = MetadataCommand::new()
+     411          30 :         .current_dir(package_root)
+     412          30 :         .no_deps()
+     413          30 :         .exec()?;
+     414             : 
+     415          30 :     dylint_internal::cargo::package_with_root(&metadata, package_root)
+     416          30 : }
+     417             : 
+     418          30 : fn package_id(package: &MetadataPackage, source_id: SourceId) -> PackageId {
+     419          30 :     PackageId::new(
+     420          30 :         #[allow(clippy::useless_conversion)]
+     421          30 :         package.name.clone().into(),
+     422          30 :         package.version.clone(),
+     423          30 :         source_id,
+     424          30 :     )
+     425          30 : }
+     426             : 
+     427          30 : pub fn package_library_name(package: &MetadataPackage) -> Result<String> {
+     428          30 :     package
+     429          30 :         .targets
+     430          30 :         .iter()
+     431          30 :         .find_map(|target| {
+     432          30 :             if target.kind.iter().any(|kind| kind == "cdylib") {
+     433          30 :                 Some(target.name.clone())
+     434             :             } else {
+     435           0 :                 None
+     436             :             }
+     437          30 :         })
+     438          30 :         .ok_or_else(|| {
+     439           0 :             anyhow!(
+     440           0 :                 "Could not find `cdylib` target for package `{}`",
+     441           0 :                 package.id
+     442           0 :             )
+     443          30 :         })
+     444          30 : }
+     445             : 
+     446          21 : pub fn build_library(opts: &opts::Dylint, package: &Package) -> Result<PathBuf> {
+     447          21 :     let target_dir = package.target_directory();
+     448          21 : 
+     449          21 :     let path = package.path();
+     450          21 : 
+     451          21 :     if !opts.library_selection().no_build {
+     452             :         // smoelius: Clear `RUSTFLAGS` so that changes to it do not cause workspace metadata entries
+     453             :         // to be rebuilt.
+     454          21 :         dylint_internal::cargo::build(&format!("workspace metadata entry `{}`", package.id.name()))
+     455          21 :             .quiet(opts.quiet)
+     456          21 :             .build()
+     457          21 :             .sanitize_environment()
+     458          21 :             .env_remove(env::RUSTFLAGS)
+     459          21 :             .current_dir(&package.root)
+     460          21 :             .args(["--release", "--target-dir", &target_dir.to_string_lossy()])
+     461          21 :             .success()?;
+     462             : 
+     463          21 :         let exists = path
+     464          21 :             .try_exists()
+     465          21 :             .with_context(|| format!("Could not determine whether {path:?} exists"))?;
+     466             : 
+     467          21 :         ensure!(exists, "Could not find {path:?} despite successful build");
+     468           0 :     }
+     469             : 
+     470          21 :     Ok(path)
+     471          21 : }
+     472             : 
+     473             : // smoelius: `pkg_dir` and `target_short_hash` are based on functions with the same names in
+     474             : // https://github.com/rust-lang/cargo/blob/master/src/cargo/core/compiler/context/compilation_files.rs
+     475             : 
+     476             : #[cfg(any())]
+     477             : mod disabled {
+     478             :     fn pkg_dir(package_root: &Path, pkg_id: PackageId) -> String {
+     479             :         let name = pkg_id.name();
+     480             :         format!("{}-{}", name, target_short_hash(package_root, pkg_id))
+     481             :     }
+     482             : 
+     483             :     const METADATA_VERSION: u8 = 2;
+     484             : 
+     485             :     fn target_short_hash(package_root: &Path, pkg_id: PackageId) -> String {
+     486             :         // smoelius: For now, the package root is the workspace root.
+     487             :         let hashable = pkg_id.stable_hash(package_root);
+     488             :         cargo::util::short_hash(&(METADATA_VERSION, hashable))
+     489             :     }
+     490             : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/name_toolchain_map/index-sort-f.html b/coverage/dylint/src/name_toolchain_map/index-sort-f.html new file mode 100644 index 000000000..faa4d20b4 --- /dev/null +++ b/coverage/dylint/src/name_toolchain_map/index-sort-f.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - unnamed - dylint/src/name_toolchain_map + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/name_toolchain_mapHitTotalCoverage
Test:unnamedLines:10010793.5 %
Date:2024-09-27 12:58:08Functions:131586.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
mod.rs +
91.4%91.4%
+
91.4 %74 / 8177.8 %7 / 9
maybe_library.rs +
100.0%
+
100.0 %26 / 26100.0 %6 / 6
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/name_toolchain_map/index-sort-l.html b/coverage/dylint/src/name_toolchain_map/index-sort-l.html new file mode 100644 index 000000000..ae45a908e --- /dev/null +++ b/coverage/dylint/src/name_toolchain_map/index-sort-l.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - unnamed - dylint/src/name_toolchain_map + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/name_toolchain_mapHitTotalCoverage
Test:unnamedLines:10010793.5 %
Date:2024-09-27 12:58:08Functions:131586.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
mod.rs +
91.4%91.4%
+
91.4 %74 / 8177.8 %7 / 9
maybe_library.rs +
100.0%
+
100.0 %26 / 26100.0 %6 / 6
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/name_toolchain_map/index.html b/coverage/dylint/src/name_toolchain_map/index.html new file mode 100644 index 000000000..f9b52c594 --- /dev/null +++ b/coverage/dylint/src/name_toolchain_map/index.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - unnamed - dylint/src/name_toolchain_map + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/name_toolchain_mapHitTotalCoverage
Test:unnamedLines:10010793.5 %
Date:2024-09-27 12:58:08Functions:131586.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
maybe_library.rs +
100.0%
+
100.0 %26 / 26100.0 %6 / 6
mod.rs +
91.4%91.4%
+
91.4 %74 / 8177.8 %7 / 9
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/name_toolchain_map/maybe_library.rs.func-sort-c.html b/coverage/dylint/src/name_toolchain_map/maybe_library.rs.func-sort-c.html new file mode 100644 index 000000000..eb8e7843d --- /dev/null +++ b/coverage/dylint/src/name_toolchain_map/maybe_library.rs.func-sort-c.html @@ -0,0 +1,96 @@ + + + + + + + LCOV - unnamed - dylint/src/name_toolchain_map/maybe_library.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/name_toolchain_map - maybe_library.rs (source / functions)HitTotalCoverage
Test:unnamedLines:2626100.0 %
Date:2024-09-27 12:58:08Functions:66100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<dylint::name_toolchain_map::maybe_library::Inner>::path5
<dylint::name_toolchain_map::maybe_library::MaybeLibrary>::path5
<dylint::name_toolchain_map::maybe_library::MaybeLibrary as core::convert::From<dylint::library_packages::Package>>::from26
<dylint::name_toolchain_map::maybe_library::Inner>::build30
<dylint::name_toolchain_map::maybe_library::MaybeLibrary>::build30
<dylint::name_toolchain_map::maybe_library::MaybeLibrary as core::convert::From<std::path::PathBuf>>::from75
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/name_toolchain_map/maybe_library.rs.func.html b/coverage/dylint/src/name_toolchain_map/maybe_library.rs.func.html new file mode 100644 index 000000000..72c4bfa03 --- /dev/null +++ b/coverage/dylint/src/name_toolchain_map/maybe_library.rs.func.html @@ -0,0 +1,96 @@ + + + + + + + LCOV - unnamed - dylint/src/name_toolchain_map/maybe_library.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/name_toolchain_map - maybe_library.rs (source / functions)HitTotalCoverage
Test:unnamedLines:2626100.0 %
Date:2024-09-27 12:58:08Functions:66100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<dylint::name_toolchain_map::maybe_library::Inner>::build30
<dylint::name_toolchain_map::maybe_library::Inner>::path5
<dylint::name_toolchain_map::maybe_library::MaybeLibrary as core::convert::From<dylint::library_packages::Package>>::from26
<dylint::name_toolchain_map::maybe_library::MaybeLibrary as core::convert::From<std::path::PathBuf>>::from75
<dylint::name_toolchain_map::maybe_library::MaybeLibrary>::build30
<dylint::name_toolchain_map::maybe_library::MaybeLibrary>::path5
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/name_toolchain_map/maybe_library.rs.gcov.html b/coverage/dylint/src/name_toolchain_map/maybe_library.rs.gcov.html new file mode 100644 index 000000000..b0a2c3913 --- /dev/null +++ b/coverage/dylint/src/name_toolchain_map/maybe_library.rs.gcov.html @@ -0,0 +1,139 @@ + + + + + + + LCOV - unnamed - dylint/src/name_toolchain_map/maybe_library.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/name_toolchain_map - maybe_library.rs (source / functions)HitTotalCoverage
Test:unnamedLines:2626100.0 %
Date:2024-09-27 12:58:08Functions:66100.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : use anyhow::Result;
+       2             : use std::path::PathBuf;
+       3             : 
+       4             : #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
+       5             : pub struct MaybeLibrary {
+       6             :     inner: Inner,
+       7             : }
+       8             : 
+       9             : impl MaybeLibrary {
+      10           5 :     pub fn path(&self) -> PathBuf {
+      11           5 :         self.inner.path()
+      12           5 :     }
+      13             : 
+      14          30 :     pub fn build(&self, opts: &crate::opts::Dylint) -> Result<PathBuf> {
+      15          30 :         self.inner.build(opts)
+      16          30 :     }
+      17             : }
+      18             : 
+      19             : impl From<PathBuf> for MaybeLibrary {
+      20          75 :     fn from(path: PathBuf) -> Self {
+      21          75 :         Self {
+      22          75 :             inner: Inner::Path(path),
+      23          75 :         }
+      24          75 :     }
+      25             : }
+      26             : 
+      27             : #[cfg(__library_packages)]
+      28             : impl From<crate::library_packages::Package> for MaybeLibrary {
+      29          26 :     fn from(package: crate::library_packages::Package) -> Self {
+      30          26 :         Self {
+      31          26 :             inner: Inner::Package(package),
+      32          26 :         }
+      33          26 :     }
+      34             : }
+      35             : 
+      36             : #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
+      37             : pub enum Inner {
+      38             :     Path(PathBuf),
+      39             : 
+      40             :     #[cfg(__library_packages)]
+      41             :     Package(crate::library_packages::Package),
+      42             : }
+      43             : 
+      44             : impl Inner {
+      45           5 :     pub fn path(&self) -> PathBuf {
+      46           5 :         match self {
+      47           2 :             Self::Path(path) => path.clone(),
+      48             : 
+      49             :             #[cfg(__library_packages)]
+      50           3 :             Self::Package(package) => package.path(),
+      51             :         }
+      52           5 :     }
+      53             : 
+      54             :     #[cfg_attr(not(__library_packages), allow(unused_variables))]
+      55          30 :     fn build(&self, opts: &crate::opts::Dylint) -> Result<PathBuf> {
+      56          30 :         match self {
+      57           9 :             Self::Path(path) => Ok(path.clone()),
+      58             : 
+      59             :             #[cfg(__library_packages)]
+      60          21 :             Self::Package(package) => crate::library_packages::build_library(opts, package),
+      61             :         }
+      62          30 :     }
+      63             : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/name_toolchain_map/mod.rs.func-sort-c.html b/coverage/dylint/src/name_toolchain_map/mod.rs.func-sort-c.html new file mode 100644 index 000000000..0a7cd213c --- /dev/null +++ b/coverage/dylint/src/name_toolchain_map/mod.rs.func-sort-c.html @@ -0,0 +1,108 @@ + + + + + + + LCOV - unnamed - dylint/src/name_toolchain_map/mod.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/name_toolchain_map - mod.rs (source / functions)HitTotalCoverage
Test:unnamedLines:748191.4 %
Date:2024-09-27 12:58:08Functions:7977.8 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint::name_toolchain_map::dylint_libraries_in::{closure#0}0
dylint::name_toolchain_map::dylint_libraries_in::{closure#1}::{closure#0}0
dylint::name_toolchain_map::dylint_libraries_in10
dylint::name_toolchain_map::dylint_library_paths29
<dylint::name_toolchain_map::Lazy>::get_or_try_init::{closure#0}36
<dylint::name_toolchain_map::Lazy>::new39
<dylint::name_toolchain_map::Lazy>::get_or_try_init46
dylint::name_toolchain_map::dylint_libraries_in::{closure#1}::{closure#1}75
dylint::name_toolchain_map::dylint_libraries_in::{closure#1}227
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/name_toolchain_map/mod.rs.func.html b/coverage/dylint/src/name_toolchain_map/mod.rs.func.html new file mode 100644 index 000000000..ddc696f12 --- /dev/null +++ b/coverage/dylint/src/name_toolchain_map/mod.rs.func.html @@ -0,0 +1,108 @@ + + + + + + + LCOV - unnamed - dylint/src/name_toolchain_map/mod.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/name_toolchain_map - mod.rs (source / functions)HitTotalCoverage
Test:unnamedLines:748191.4 %
Date:2024-09-27 12:58:08Functions:7977.8 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<dylint::name_toolchain_map::Lazy>::get_or_try_init46
<dylint::name_toolchain_map::Lazy>::get_or_try_init::{closure#0}36
<dylint::name_toolchain_map::Lazy>::new39
dylint::name_toolchain_map::dylint_libraries_in10
dylint::name_toolchain_map::dylint_libraries_in::{closure#0}0
dylint::name_toolchain_map::dylint_libraries_in::{closure#1}227
dylint::name_toolchain_map::dylint_libraries_in::{closure#1}::{closure#0}0
dylint::name_toolchain_map::dylint_libraries_in::{closure#1}::{closure#1}75
dylint::name_toolchain_map::dylint_library_paths29
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/name_toolchain_map/mod.rs.gcov.html b/coverage/dylint/src/name_toolchain_map/mod.rs.gcov.html new file mode 100644 index 000000000..197a8675d --- /dev/null +++ b/coverage/dylint/src/name_toolchain_map/mod.rs.gcov.html @@ -0,0 +1,214 @@ + + + + + + + LCOV - unnamed - dylint/src/name_toolchain_map/mod.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/name_toolchain_map - mod.rs (source / functions)HitTotalCoverage
Test:unnamedLines:748191.4 %
Date:2024-09-27 12:58:08Functions:7977.8 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : use anyhow::{ensure, Context, Result};
+       2             : use dylint_internal::{env, parse_path_filename};
+       3             : use once_cell::sync::OnceCell;
+       4             : use std::{
+       5             :     collections::{BTreeMap, BTreeSet},
+       6             :     env::split_paths,
+       7             :     fs::read_dir,
+       8             :     path::{Path, PathBuf},
+       9             : };
+      10             : 
+      11             : mod maybe_library;
+      12             : pub use maybe_library::MaybeLibrary;
+      13             : 
+      14             : pub type ToolchainMap = BTreeMap<String, BTreeSet<PathBuf>>;
+      15             : 
+      16             : #[allow(clippy::redundant_pub_crate)]
+      17             : pub(crate) type NameToolchainMap = BTreeMap<String, LazyToolchainMap>;
+      18             : 
+      19             : #[allow(clippy::redundant_pub_crate)]
+      20             : pub(crate) type LazyToolchainMap = BTreeMap<String, BTreeSet<MaybeLibrary>>;
+      21             : 
+      22             : #[cfg_attr(not(__library_packages), allow(dead_code))]
+      23             : struct Inner<'opts> {
+      24             :     opts: &'opts crate::opts::Dylint,
+      25             :     name_toolchain_map: OnceCell<NameToolchainMap>,
+      26             : }
+      27             : 
+      28             : pub struct Lazy<'opts> {
+      29             :     inner: Inner<'opts>,
+      30             : }
+      31             : 
+      32             : impl<'opts> Lazy<'opts> {
+      33             :     #[must_use]
+      34          39 :     pub const fn new(opts: &'opts crate::opts::Dylint) -> Self {
+      35          39 :         Self {
+      36          39 :             inner: Inner {
+      37          39 :                 opts,
+      38          39 :                 name_toolchain_map: OnceCell::new(),
+      39          39 :             },
+      40          39 :         }
+      41          39 :     }
+      42             : 
+      43          46 :     pub fn get_or_try_init(&self) -> Result<&NameToolchainMap> {
+      44          46 :         self.inner
+      45          46 :             .name_toolchain_map
+      46          46 :             .get_or_try_init(|| -> Result<_> {
+      47          36 :                 let mut name_toolchain_map = NameToolchainMap::new();
+      48             : 
+      49             :                 #[cfg(__library_packages)]
+      50             :                 {
+      51          36 :                     let library_packages = if self.inner.opts.git_or_path() {
+      52           2 :                         crate::library_packages::from_opts(self.inner.opts)?
+      53             :                     } else {
+      54          29 :                         let mut library_packages =
+      55          34 :                             crate::library_packages::from_workspace_metadata(self.inner.opts)?;
+      56          29 :                         let library_packages_other =
+      57          29 :                             crate::library_packages::from_dylint_toml(self.inner.opts)?;
+      58          29 :                         ensure!(
+      59          29 :                             library_packages.is_empty() || library_packages_other.is_empty(),
+      60           0 :                             "`workspace.metadata.dylint.libraries` cannot appear in both \
+      61           0 :                              Cargo.toml and dylint.toml"
+      62             :                         );
+      63          29 :                         library_packages.extend(library_packages_other);
+      64          29 :                         library_packages
+      65             :                     };
+      66             : 
+      67          57 :                     for package in library_packages {
+      68          26 :                         name_toolchain_map
+      69          26 :                             .entry(package.lib_name.clone())
+      70          26 :                             .or_default()
+      71          26 :                             .entry(package.toolchain.clone())
+      72          26 :                             .or_default()
+      73          26 :                             .insert(MaybeLibrary::from(package));
+      74          26 :                     }
+      75             :                 }
+      76             : 
+      77             :                 // smoelius: If `--git` or `--path` was passed, then do not look for libraries by
+      78             :                 // other means.
+      79          31 :                 if !self.inner.opts.git_or_path() {
+      80          29 :                     let dylint_library_paths = dylint_library_paths()?;
+      81             : 
+      82          39 :                     for path in dylint_library_paths {
+      83          75 :                         for entry in dylint_libraries_in(&path)? {
+      84          75 :                             let (name, toolchain, path) = entry?;
+      85          75 :                             name_toolchain_map
+      86          75 :                                 .entry(name)
+      87          75 :                                 .or_default()
+      88          75 :                                 .entry(toolchain)
+      89          75 :                                 .or_default()
+      90          75 :                                 .insert(MaybeLibrary::from(path));
+      91             :                         }
+      92             :                     }
+      93           2 :                 }
+      94             : 
+      95          31 :                 Ok(name_toolchain_map)
+      96          46 :             })
+      97          46 :     }
+      98             : }
+      99             : 
+     100          29 : fn dylint_library_paths() -> Result<Vec<PathBuf>> {
+     101          29 :     let mut paths = Vec::new();
+     102             : 
+     103          29 :     if let Ok(val) = env::var(env::DYLINT_LIBRARY_PATH) {
+     104          10 :         for path in split_paths(&val) {
+     105          10 :             ensure!(
+     106          10 :                 path.is_absolute(),
+     107           0 :                 "DYLINT_LIBRARY_PATH contains `{}`, which is not absolute",
+     108           0 :                 path.to_string_lossy()
+     109             :             );
+     110          10 :             ensure!(
+     111          10 :                 path.is_dir(),
+     112           0 :                 "DYLINT_LIBRARY_PATH contains `{}`, which is not a directory",
+     113           0 :                 path.to_string_lossy()
+     114             :             );
+     115          10 :             paths.push(path);
+     116             :         }
+     117          22 :     }
+     118             : 
+     119          29 :     Ok(paths)
+     120          29 : }
+     121             : 
+     122          10 : fn dylint_libraries_in(
+     123          10 :     path: &Path,
+     124          10 : ) -> Result<impl Iterator<Item = Result<(String, String, PathBuf)>>> {
+     125          10 :     let iter = read_dir(path)
+     126          10 :         .with_context(|| format!("`read_dir` failed for `{}`", path.to_string_lossy()))?;
+     127          10 :     let path_buf = path.to_path_buf();
+     128          10 :     Ok(iter
+     129         227 :         .map(move |entry| -> Result<Option<(String, String, PathBuf)>> {
+     130         227 :             let entry = entry.with_context(|| {
+     131           0 :                 format!("`read_dir` failed for `{}`", path_buf.to_string_lossy())
+     132         227 :             })?;
+     133         227 :             let path = entry.path();
+     134         227 : 
+     135         227 :             Ok(parse_path_filename(&path).map(|(lib_name, toolchain)| (lib_name, toolchain, path)))
+     136         227 :         })
+     137          10 :         .filter_map(Result::transpose))
+     138          10 : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/opts.rs.func-sort-c.html b/coverage/dylint/src/opts.rs.func-sort-c.html new file mode 100644 index 000000000..0b1adc835 --- /dev/null +++ b/coverage/dylint/src/opts.rs.func-sort-c.html @@ -0,0 +1,108 @@ + + + + + + + LCOV - unnamed - dylint/src/opts.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src - opts.rs (source / functions)HitTotalCoverage
Test:unnamedLines:334868.8 %
Date:2024-09-27 12:58:08Functions:99100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<dylint::opts::Dylint>::library_selection_mut37
<dylint::opts::Operation>::library_selection_mut37
<dylint::opts::Dylint>::has_library_selection41
<dylint::opts::Operation>::has_library_selection41
<dylint::opts::Operation as core::default::Default>::default48
<dylint::opts::Dylint>::git_or_path67
<dylint::opts::LibrarySelection>::git_or_path104
<dylint::opts::Dylint>::library_selection255
<dylint::opts::Operation>::library_selection255
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/opts.rs.func.html b/coverage/dylint/src/opts.rs.func.html new file mode 100644 index 000000000..1ee4b0038 --- /dev/null +++ b/coverage/dylint/src/opts.rs.func.html @@ -0,0 +1,108 @@ + + + + + + + LCOV - unnamed - dylint/src/opts.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src - opts.rs (source / functions)HitTotalCoverage
Test:unnamedLines:334868.8 %
Date:2024-09-27 12:58:08Functions:99100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<dylint::opts::Dylint>::git_or_path67
<dylint::opts::Dylint>::has_library_selection41
<dylint::opts::Dylint>::library_selection255
<dylint::opts::Dylint>::library_selection_mut37
<dylint::opts::LibrarySelection>::git_or_path104
<dylint::opts::Operation as core::default::Default>::default48
<dylint::opts::Operation>::has_library_selection41
<dylint::opts::Operation>::library_selection255
<dylint::opts::Operation>::library_selection_mut37
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/opts.rs.gcov.html b/coverage/dylint/src/opts.rs.gcov.html new file mode 100644 index 000000000..19c806b0c --- /dev/null +++ b/coverage/dylint/src/opts.rs.gcov.html @@ -0,0 +1,268 @@ + + + + + + + LCOV - unnamed - dylint/src/opts.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src - opts.rs (source / functions)HitTotalCoverage
Test:unnamedLines:334868.8 %
Date:2024-09-27 12:58:08Functions:99100.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : //! Warning: Addition of public fields to the structs in this module is considered a non-breaking
+       2             : //! change.
+       3             : //!
+       4             : //! For this reason, we recommend using [struct update syntax] when initializing instances of the
+       5             : //! structs in this module.
+       6             : //!
+       7             : //! Example:
+       8             : //!
+       9             : //! ```
+      10             : //! # use crate::dylint::opts::Dylint;
+      11             : //! let opts = Dylint {
+      12             : //!     quiet: true,
+      13             : //!     ..Default::default()
+      14             : //! };
+      15             : //! ```
+      16             : //!
+      17             : //! [struct update syntax]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html#creating-instances-from-other-instances-with-struct-update-syntax
+      18             : 
+      19             : #[cfg(feature = "package_options")]
+      20             : use once_cell::sync::Lazy;
+      21             : 
+      22             : #[allow(clippy::struct_excessive_bools)]
+      23             : #[derive(Clone, Debug, Default)]
+      24             : pub struct Dylint {
+      25             :     pub pipe_stderr: Option<String>,
+      26             : 
+      27             :     pub pipe_stdout: Option<String>,
+      28             : 
+      29             :     pub quiet: bool,
+      30             : 
+      31             :     pub operation: Operation,
+      32             : }
+      33             : 
+      34             : #[derive(Clone, Debug, Default)]
+      35             : pub struct LibrarySelection {
+      36             :     pub all: bool,
+      37             : 
+      38             :     pub branch: Option<String>,
+      39             : 
+      40             :     pub git: Option<String>,
+      41             : 
+      42             :     pub lib_paths: Vec<String>,
+      43             : 
+      44             :     pub libs: Vec<String>,
+      45             : 
+      46             :     pub manifest_path: Option<String>,
+      47             : 
+      48             :     pub no_build: bool,
+      49             : 
+      50             :     pub no_metadata: bool,
+      51             : 
+      52             :     pub paths: Vec<String>,
+      53             : 
+      54             :     pub pattern: Option<String>,
+      55             : 
+      56             :     pub rev: Option<String>,
+      57             : 
+      58             :     pub tag: Option<String>,
+      59             : }
+      60             : 
+      61             : #[derive(Clone, Debug)]
+      62             : #[non_exhaustive]
+      63             : pub enum Operation {
+      64             :     Check(Check),
+      65             :     List(List),
+      66             :     #[cfg(feature = "package_options")]
+      67             :     New(New),
+      68             :     #[cfg(feature = "package_options")]
+      69             :     Upgrade(Upgrade),
+      70             : }
+      71             : 
+      72             : #[allow(clippy::struct_excessive_bools)]
+      73             : #[derive(Clone, Debug, Default)]
+      74             : pub struct Check {
+      75             :     pub lib_sel: LibrarySelection,
+      76             : 
+      77             :     pub fix: bool,
+      78             : 
+      79             :     pub keep_going: bool,
+      80             : 
+      81             :     pub no_deps: bool,
+      82             : 
+      83             :     pub packages: Vec<String>,
+      84             : 
+      85             :     pub workspace: bool,
+      86             : 
+      87             :     pub args: Vec<String>,
+      88             : }
+      89             : 
+      90             : #[derive(Clone, Debug, Default)]
+      91             : pub struct List {
+      92             :     pub lib_sel: LibrarySelection,
+      93             : }
+      94             : 
+      95             : #[cfg(feature = "package_options")]
+      96             : #[derive(Clone, Debug, Default)]
+      97             : pub struct New {
+      98             :     pub isolate: bool,
+      99             : 
+     100             :     pub path: String,
+     101             : }
+     102             : 
+     103             : #[cfg(feature = "package_options")]
+     104             : #[derive(Clone, Debug, Default)]
+     105             : pub struct Upgrade {
+     106             :     pub allow_downgrade: bool,
+     107             : 
+     108             :     pub rust_version: Option<String>,
+     109             : 
+     110             :     pub path: String,
+     111             : }
+     112             : 
+     113             : impl Dylint {
+     114             :     #[must_use]
+     115          41 :     pub const fn has_library_selection(&self) -> bool {
+     116          41 :         self.operation.has_library_selection()
+     117          41 :     }
+     118             : 
+     119             :     #[must_use]
+     120         255 :     pub fn library_selection(&self) -> &LibrarySelection {
+     121         255 :         self.operation.library_selection()
+     122         255 :     }
+     123             : 
+     124          37 :     pub fn library_selection_mut(&mut self) -> &mut LibrarySelection {
+     125          37 :         self.operation.library_selection_mut()
+     126          37 :     }
+     127             : 
+     128          67 :     pub(crate) fn git_or_path(&self) -> bool {
+     129          67 :         self.library_selection().git_or_path()
+     130          67 :     }
+     131             : }
+     132             : 
+     133             : impl LibrarySelection {
+     134         104 :     pub(crate) fn git_or_path(&self) -> bool {
+     135         104 :         self.git.is_some() || !self.paths.is_empty()
+     136         104 :     }
+     137             : }
+     138             : 
+     139             : #[cfg(feature = "package_options")]
+     140             : static LIBRARY_SELECTION: Lazy<LibrarySelection> = Lazy::new(LibrarySelection::default);
+     141             : 
+     142             : impl Operation {
+     143          41 :     const fn has_library_selection(&self) -> bool {
+     144          41 :         match self {
+     145          37 :             Self::Check(_) | Self::List(_) => true,
+     146             :             #[cfg(feature = "package_options")]
+     147           4 :             Self::New(_) | Self::Upgrade(_) => false,
+     148             :         }
+     149          41 :     }
+     150             : 
+     151         255 :     fn library_selection(&self) -> &LibrarySelection {
+     152         255 :         match self {
+     153         201 :             Self::Check(check) => &check.lib_sel,
+     154          54 :             Self::List(list) => &list.lib_sel,
+     155             :             #[cfg(feature = "package_options")]
+     156             :             Self::New(_) | Self::Upgrade(_) => {
+     157           0 :                 if cfg!(debug_assertions) {
+     158           0 :                     eprintln!(
+     159           0 :                         "[{}:{}] {}",
+     160           0 :                         file!(),
+     161           0 :                         line!(),
+     162           0 :                         "`library_selection` called on an `Operation` with no `LibrarySelection` \
+     163           0 :                          field"
+     164           0 :                     );
+     165           0 :                     eprintln!("{}", std::backtrace::Backtrace::force_capture());
+     166           0 :                 }
+     167           0 :                 &LIBRARY_SELECTION
+     168             :             }
+     169             :         }
+     170         255 :     }
+     171             : 
+     172             :     #[allow(clippy::panic)]
+     173          37 :     fn library_selection_mut(&mut self) -> &mut LibrarySelection {
+     174          37 :         match self {
+     175          27 :             Self::Check(check) => &mut check.lib_sel,
+     176          10 :             Self::List(list) => &mut list.lib_sel,
+     177             :             #[cfg(feature = "package_options")]
+     178             :             Self::New(_) | Self::Upgrade(_) => {
+     179           0 :                 panic!(
+     180           0 :                     "`library_selection_mut` called on an `Operation` with no `LibrarySelection` \
+     181           0 :                      field"
+     182           0 :                 )
+     183             :             }
+     184             :         }
+     185          37 :     }
+     186             : }
+     187             : 
+     188             : impl Default for Operation {
+     189          48 :     fn default() -> Self {
+     190          48 :         Self::Check(Check::default())
+     191          48 :     }
+     192             : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/package_options/index-sort-f.html b/coverage/dylint/src/package_options/index-sort-f.html new file mode 100644 index 000000000..668833dcc --- /dev/null +++ b/coverage/dylint/src/package_options/index-sort-f.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - unnamed - dylint/src/package_options + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/package_optionsHitTotalCoverage
Test:unnamedLines:21523491.9 %
Date:2024-09-27 12:58:08Functions:163250.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
mod.rs +
86.6%86.6%
+
86.6 %103 / 11942.1 %8 / 19
revs.rs +
97.4%97.4%
+
97.4 %112 / 11561.5 %8 / 13
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/package_options/index-sort-l.html b/coverage/dylint/src/package_options/index-sort-l.html new file mode 100644 index 000000000..1b1a027a9 --- /dev/null +++ b/coverage/dylint/src/package_options/index-sort-l.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - unnamed - dylint/src/package_options + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/package_optionsHitTotalCoverage
Test:unnamedLines:21523491.9 %
Date:2024-09-27 12:58:08Functions:163250.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
mod.rs +
86.6%86.6%
+
86.6 %103 / 11942.1 %8 / 19
revs.rs +
97.4%97.4%
+
97.4 %112 / 11561.5 %8 / 13
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/package_options/index.html b/coverage/dylint/src/package_options/index.html new file mode 100644 index 000000000..7aeefa3cf --- /dev/null +++ b/coverage/dylint/src/package_options/index.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - unnamed - dylint/src/package_options + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/package_optionsHitTotalCoverage
Test:unnamedLines:21523491.9 %
Date:2024-09-27 12:58:08Functions:163250.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
mod.rs +
86.6%86.6%
+
86.6 %103 / 11942.1 %8 / 19
revs.rs +
97.4%97.4%
+
97.4 %112 / 11561.5 %8 / 13
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/package_options/mod.rs.func-sort-c.html b/coverage/dylint/src/package_options/mod.rs.func-sort-c.html new file mode 100644 index 000000000..bdd97d68c --- /dev/null +++ b/coverage/dylint/src/package_options/mod.rs.func-sort-c.html @@ -0,0 +1,148 @@ + + + + + + + LCOV - unnamed - dylint/src/package_options/mod.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/package_options - mod.rs (source / functions)HitTotalCoverage
Test:unnamedLines:10311986.6 %
Date:2024-09-27 12:58:08Functions:81942.1 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint::package_options::fill_in::{closure#0}0
dylint::package_options::fill_in::{closure#1}0
dylint::package_options::fill_in::{closure#2}0
dylint::package_options::new_package::{closure#1}0
dylint::package_options::new_package::{closure#2}0
dylint::package_options::upgrade_package::{closure#1}0
dylint::package_options::upgrade_package::{closure#2}0
dylint::package_options::upgrade_package::{closure#3}0
dylint::package_options::upgrade_package::{closure#4}0
dylint::package_options::upgrade_package::{closure#5}0
dylint::package_options::upgrade_package::{closure#6}0
dylint::package_options::fill_in1
dylint::package_options::new_package1
dylint::package_options::new_package::{closure#0}1
dylint::package_options::upgrade_package3
dylint::package_options::parse_as_nightly4
dylint::package_options::parse_date4
dylint::package_options::upgrade_package::{closure#0}14
dylint::package_options::upgrade_package::{closure#0}::{closure#0}14
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/package_options/mod.rs.func.html b/coverage/dylint/src/package_options/mod.rs.func.html new file mode 100644 index 000000000..1a120e6c3 --- /dev/null +++ b/coverage/dylint/src/package_options/mod.rs.func.html @@ -0,0 +1,148 @@ + + + + + + + LCOV - unnamed - dylint/src/package_options/mod.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/package_options - mod.rs (source / functions)HitTotalCoverage
Test:unnamedLines:10311986.6 %
Date:2024-09-27 12:58:08Functions:81942.1 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint::package_options::fill_in1
dylint::package_options::fill_in::{closure#0}0
dylint::package_options::fill_in::{closure#1}0
dylint::package_options::fill_in::{closure#2}0
dylint::package_options::new_package1
dylint::package_options::new_package::{closure#0}1
dylint::package_options::new_package::{closure#1}0
dylint::package_options::new_package::{closure#2}0
dylint::package_options::parse_as_nightly4
dylint::package_options::parse_date4
dylint::package_options::upgrade_package3
dylint::package_options::upgrade_package::{closure#0}14
dylint::package_options::upgrade_package::{closure#0}::{closure#0}14
dylint::package_options::upgrade_package::{closure#1}0
dylint::package_options::upgrade_package::{closure#2}0
dylint::package_options::upgrade_package::{closure#3}0
dylint::package_options::upgrade_package::{closure#4}0
dylint::package_options::upgrade_package::{closure#5}0
dylint::package_options::upgrade_package::{closure#6}0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/package_options/mod.rs.gcov.html b/coverage/dylint/src/package_options/mod.rs.gcov.html new file mode 100644 index 000000000..2bd848c6c --- /dev/null +++ b/coverage/dylint/src/package_options/mod.rs.gcov.html @@ -0,0 +1,250 @@ + + + + + + + LCOV - unnamed - dylint/src/package_options/mod.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/package_options - mod.rs (source / functions)HitTotalCoverage
Test:unnamedLines:10311986.6 %
Date:2024-09-27 12:58:08Functions:81942.1 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : use crate::opts;
+       2             : use anyhow::{anyhow, bail, Context, Result};
+       3             : use dylint_internal::{
+       4             :     clippy_utils::{
+       5             :         clippy_utils_version_from_rust_version, set_clippy_utils_dependency_revision,
+       6             :         set_toolchain_channel, toolchain_channel,
+       7             :     },
+       8             :     find_and_replace,
+       9             :     packaging::new_template,
+      10             : };
+      11             : use heck::{ToKebabCase, ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase};
+      12             : use if_chain::if_chain;
+      13             : use rewriter::Backup;
+      14             : use std::{
+      15             :     fs::{copy, create_dir_all},
+      16             :     path::Path,
+      17             : };
+      18             : use tempfile::tempdir;
+      19             : use walkdir::WalkDir;
+      20             : 
+      21             : mod revs;
+      22             : use revs::Revs;
+      23             : 
+      24           1 : pub fn new_package(_opts: &opts::Dylint, new_opts: &opts::New) -> Result<()> {
+      25           1 :     let path = Path::new(&new_opts.path);
+      26             : 
+      27           1 :     let name = path
+      28           1 :         .file_name()
+      29           1 :         .map(|s| s.to_string_lossy().to_string())
+      30           1 :         .ok_or_else(|| anyhow!("Could not determine library name from {:?}", path))?;
+      31             : 
+      32           1 :     let tempdir = tempdir().with_context(|| "`tempdir` failed")?;
+      33             : 
+      34           1 :     new_template(tempdir.path())?;
+      35             : 
+      36             :     // smoelius: Isolation is now the default.
+      37           1 :     if !new_opts.isolate {
+      38           0 :         find_and_replace(
+      39           0 :             &tempdir.path().join("Cargo.toml"),
+      40           0 :             r"\r?\n\[workspace\]\r?\n",
+      41           0 :             "",
+      42           0 :         )?;
+      43           1 :     }
+      44             : 
+      45             :     // smoelius: So is allowing unused extern crates.
+      46           1 :     find_and_replace(
+      47           1 :         &tempdir.path().join("src/lib.rs"),
+      48           1 :         r"(?m)^.. (#!\[warn\(unused_extern_crates\)\])$",
+      49           1 :         "${1}",
+      50           1 :     )?;
+      51             : 
+      52           1 :     fill_in(&name, tempdir.path(), path)?;
+      53             : 
+      54           1 :     Ok(())
+      55           1 : }
+      56             : 
+      57           1 : fn fill_in(name: &str, from: &Path, to: &Path) -> Result<()> {
+      58           1 :     let lower_snake_case = name.to_snake_case();
+      59           1 :     let upper_snake_case = name.to_shouty_snake_case();
+      60           1 :     let kebab_case = name.to_kebab_case();
+      61           1 :     let camel_case = name.to_upper_camel_case();
+      62             : 
+      63          12 :     for entry in WalkDir::new(from) {
+      64          12 :         let entry = entry?;
+      65          12 :         let abs_path = entry.path();
+      66          12 :         let rel_path = abs_path.strip_prefix(from)?;
+      67             : 
+      68          12 :         if !abs_path.is_file() {
+      69           4 :             continue;
+      70           8 :         }
+      71           8 : 
+      72           8 :         find_and_replace(&from.join(rel_path), r"\bfill_me_in\b", &lower_snake_case)?;
+      73           8 :         find_and_replace(&from.join(rel_path), r"\bFILL_ME_IN\b", &upper_snake_case)?;
+      74           8 :         find_and_replace(&from.join(rel_path), r"\bfill-me-in\b", &kebab_case)?;
+      75           8 :         find_and_replace(&from.join(rel_path), r"\bFillMeIn\b", &camel_case)?;
+      76             : 
+      77           8 :         let from_path = from.join(rel_path);
+      78           8 :         let to_path = to.join(rel_path);
+      79           8 :         let parent = to_path
+      80           8 :             .parent()
+      81           8 :             .ok_or_else(|| anyhow!("Could not get parent directory"))?;
+      82           8 :         create_dir_all(parent).with_context(|| {
+      83           0 :             format!("`create_dir_all` failed for `{}`", parent.to_string_lossy())
+      84           8 :         })?;
+      85           8 :         copy(&from_path, &to_path).with_context(|| {
+      86           0 :             format!(
+      87           0 :                 "Could not copy `{}` to `{}`",
+      88           0 :                 from_path.to_string_lossy(),
+      89           0 :                 to_path.to_string_lossy()
+      90           0 :             )
+      91           8 :         })?;
+      92             :     }
+      93             : 
+      94           1 :     Ok(())
+      95           1 : }
+      96             : 
+      97           3 : pub fn upgrade_package(opts: &opts::Dylint, upgrade_opts: &opts::Upgrade) -> Result<()> {
+      98           3 :     let path = Path::new(&upgrade_opts.path);
+      99             : 
+     100           3 :     let rev = {
+     101           3 :         let revs = Revs::new(opts.quiet)?;
+     102           3 :         let mut iter = revs.iter()?;
+     103           3 :         match &upgrade_opts.rust_version {
+     104           2 :             Some(rust_version) => {
+     105           2 :                 let clippy_utils_version = clippy_utils_version_from_rust_version(rust_version)?;
+     106          14 :                 iter.find(|result| {
+     107          14 :                     result
+     108          14 :                         .as_ref()
+     109          14 :                         .map_or(true, |rev| rev.version == clippy_utils_version)
+     110          14 :                 })
+     111           2 :                 .unwrap_or_else(|| {
+     112           0 :                     Err(anyhow!(
+     113           0 :                         "Could not find `clippy_utils` version `{}`",
+     114           0 :                         clippy_utils_version
+     115           0 :                     ))
+     116           2 :                 })?
+     117             :             }
+     118           1 :             None => iter.next().unwrap_or_else(|| {
+     119           0 :                 Err(anyhow!("Could not determine latest `clippy_utils` version"))
+     120           1 :             })?,
+     121             :         }
+     122             :     };
+     123             : 
+     124           3 :     let old_channel = toolchain_channel(path)?;
+     125             : 
+     126           1 :     if_chain! {
+     127           3 :         if !upgrade_opts.allow_downgrade;
+     128           2 :         if let Some(new_nightly) = parse_as_nightly(&rev.channel);
+     129           2 :         if let Some(old_nightly) = parse_as_nightly(&old_channel);
+     130           2 :         if new_nightly < old_nightly;
+     131             :         then {
+     132           1 :             bail!(
+     133           1 :                 "Refusing to downgrade toolchain from `{}` to `{}`. \
+     134           1 :                 Use `--allow-downgrade` to override.",
+     135           1 :                 old_channel,
+     136           1 :                 rev.channel
+     137           1 :             );
+     138             :         }
+     139             :     };
+     140             : 
+     141           2 :     let rust_toolchain_path = path.join("rust-toolchain");
+     142           2 :     let cargo_toml_path = path.join("Cargo.toml");
+     143             : 
+     144           2 :     let mut rust_toolchain_backup =
+     145           2 :         Backup::new(rust_toolchain_path).with_context(|| "Could not backup `rust-toolchain`")?;
+     146           2 :     let mut cargo_toml_backup =
+     147           2 :         Backup::new(cargo_toml_path).with_context(|| "Could not backup `Cargo.toml`")?;
+     148             : 
+     149           2 :     set_toolchain_channel(path, &rev.channel)?;
+     150           2 :     set_clippy_utils_dependency_revision(path, &rev.oid.to_string())?;
+     151             : 
+     152           2 :     cargo_toml_backup
+     153           2 :         .disable()
+     154           2 :         .with_context(|| "Could not disable `rust-toolchain` backup")?;
+     155           2 :     rust_toolchain_backup
+     156           2 :         .disable()
+     157           2 :         .with_context(|| "Could not disable `Cargo.toml` backup")?;
+     158             : 
+     159           2 :     Ok(())
+     160           3 : }
+     161             : 
+     162           4 : fn parse_as_nightly(channel: &str) -> Option<[u32; 3]> {
+     163           4 :     channel.strip_prefix("nightly-").and_then(parse_date)
+     164           4 : }
+     165             : 
+     166           4 : fn parse_date(date_str: &str) -> Option<[u32; 3]> {
+     167           4 :     date_str
+     168           4 :         .split('-')
+     169           4 :         .map(str::parse::<u32>)
+     170           4 :         .map(Result::ok)
+     171           4 :         .collect::<Option<Vec<_>>>()
+     172           4 :         .map(<[u32; 3]>::try_from)
+     173           4 :         .and_then(Result::ok)
+     174           4 : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/package_options/revs.rs.func-sort-c.html b/coverage/dylint/src/package_options/revs.rs.func-sort-c.html new file mode 100644 index 000000000..623668ef9 --- /dev/null +++ b/coverage/dylint/src/package_options/revs.rs.func-sort-c.html @@ -0,0 +1,124 @@ + + + + + + + LCOV - unnamed - dylint/src/package_options/revs.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/package_options - revs.rs (source / functions)HitTotalCoverage
Test:unnamedLines:11211597.4 %
Date:2024-09-27 12:58:08Functions:81361.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<dylint::package_options::revs::RevIter as core::iter::traits::iterator::Iterator>::next::{closure#0}::{closure#0}0
<dylint::package_options::revs::RevIter as core::iter::traits::iterator::Iterator>::next::{closure#0}::{closure#1}0
<dylint::package_options::revs::Revs>::iter::{closure#0}0
<dylint::package_options::revs::Revs>::iter::{closure#1}0
<dylint::package_options::revs::Revs>::new::{closure#0}0
dylint::package_options::revs::test::EXAMPLES::{closure#0}1
dylint::package_options::revs::test::examples1
<dylint::package_options::revs::Revs>::iter9
<dylint::package_options::revs::Revs>::new9
dylint::package_options::revs::test::examples::{closure#0}137
dylint::package_options::revs::test::examples::{closure#0}::{closure#0}137
<dylint::package_options::revs::RevIter as core::iter::traits::iterator::Iterator>::next152
<dylint::package_options::revs::RevIter as core::iter::traits::iterator::Iterator>::next::{closure#0}152
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/package_options/revs.rs.func.html b/coverage/dylint/src/package_options/revs.rs.func.html new file mode 100644 index 000000000..dc1f2ff04 --- /dev/null +++ b/coverage/dylint/src/package_options/revs.rs.func.html @@ -0,0 +1,124 @@ + + + + + + + LCOV - unnamed - dylint/src/package_options/revs.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/package_options - revs.rs (source / functions)HitTotalCoverage
Test:unnamedLines:11211597.4 %
Date:2024-09-27 12:58:08Functions:81361.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<dylint::package_options::revs::RevIter as core::iter::traits::iterator::Iterator>::next152
<dylint::package_options::revs::RevIter as core::iter::traits::iterator::Iterator>::next::{closure#0}152
<dylint::package_options::revs::RevIter as core::iter::traits::iterator::Iterator>::next::{closure#0}::{closure#0}0
<dylint::package_options::revs::RevIter as core::iter::traits::iterator::Iterator>::next::{closure#0}::{closure#1}0
<dylint::package_options::revs::Revs>::iter9
<dylint::package_options::revs::Revs>::iter::{closure#0}0
<dylint::package_options::revs::Revs>::iter::{closure#1}0
<dylint::package_options::revs::Revs>::new9
<dylint::package_options::revs::Revs>::new::{closure#0}0
dylint::package_options::revs::test::EXAMPLES::{closure#0}1
dylint::package_options::revs::test::examples1
dylint::package_options::revs::test::examples::{closure#0}137
dylint::package_options::revs::test::examples::{closure#0}::{closure#0}137
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/dylint/src/package_options/revs.rs.gcov.html b/coverage/dylint/src/package_options/revs.rs.gcov.html new file mode 100644 index 000000000..310aafe94 --- /dev/null +++ b/coverage/dylint/src/package_options/revs.rs.gcov.html @@ -0,0 +1,260 @@ + + + + + + + LCOV - unnamed - dylint/src/package_options/revs.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - dylint/src/package_options - revs.rs (source / functions)HitTotalCoverage
Test:unnamedLines:11211597.4 %
Date:2024-09-27 12:58:08Functions:81361.5 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : use anyhow::{anyhow, Context, Result};
+       2             : use dylint_internal::{
+       3             :     clippy_utils::{clippy_utils_package_version, toolchain_channel},
+       4             :     clone,
+       5             :     git2::{Commit, ObjectType, Oid, Repository},
+       6             : };
+       7             : use if_chain::if_chain;
+       8             : use tempfile::{tempdir, TempDir};
+       9             : 
+      10             : const RUST_CLIPPY_URL: &str = "https://github.com/rust-lang/rust-clippy";
+      11             : 
+      12             : #[derive(Debug, Eq, PartialEq)]
+      13             : pub struct Rev {
+      14             :     pub version: String,
+      15             :     pub channel: String,
+      16             :     pub oid: Oid,
+      17             : }
+      18             : 
+      19             : pub struct Revs {
+      20             :     tempdir: TempDir,
+      21             :     repository: Repository,
+      22             : }
+      23             : 
+      24             : pub struct RevIter<'revs> {
+      25             :     revs: &'revs Revs,
+      26             :     commit: Commit<'revs>,
+      27             :     curr_rev: Option<Rev>,
+      28             : }
+      29             : 
+      30             : impl Revs {
+      31           9 :     pub fn new(quiet: bool) -> Result<Self> {
+      32           9 :         let tempdir = tempdir().with_context(|| "`tempdir` failed")?;
+      33             : 
+      34           9 :         let repository = clone(RUST_CLIPPY_URL, "master", tempdir.path(), quiet)?;
+      35             : 
+      36           9 :         Ok(Self {
+      37           9 :             tempdir,
+      38           9 :             repository,
+      39           9 :         })
+      40           9 :     }
+      41             : 
+      42             :     #[allow(clippy::iter_not_returning_iterator)]
+      43           9 :     pub fn iter(&self) -> Result<RevIter> {
+      44           9 :         let object = {
+      45           9 :             let head = self.repository.head()?;
+      46           9 :             let oid = head.target().ok_or_else(|| anyhow!("Could not get HEAD"))?;
+      47           9 :             self.repository.find_object(oid, Some(ObjectType::Commit))?
+      48             :         };
+      49           9 :         let commit = object
+      50           9 :             .as_commit()
+      51           9 :             .ok_or_else(|| anyhow!("Object is not a commit"))?;
+      52           9 :         let version = clippy_utils_package_version(self.tempdir.path())?;
+      53           9 :         let channel = toolchain_channel(self.tempdir.path())?;
+      54           9 :         let oid = commit.id();
+      55           9 :         Ok(RevIter {
+      56           9 :             revs: self,
+      57           9 :             commit: commit.clone(),
+      58           9 :             curr_rev: Some(Rev {
+      59           9 :                 version,
+      60           9 :                 channel,
+      61           9 :                 oid,
+      62           9 :             }),
+      63           9 :         })
+      64           9 :     }
+      65             : }
+      66             : 
+      67             : impl<'revs> Iterator for RevIter<'revs> {
+      68             :     type Item = Result<Rev>;
+      69             : 
+      70             :     // smoelius: I think it is okay to ignore the `non_local_effect_before_error_return` warning
+      71             :     // here. If `self.commit` were not updated, the same commits would be traversed the next time
+      72             :     // `next` was called.
+      73             :     #[cfg_attr(dylint_lib = "general", allow(non_local_effect_before_error_return))]
+      74             :     #[cfg_attr(dylint_lib = "overscoped_allow", allow(overscoped_allow))]
+      75         152 :     fn next(&mut self) -> Option<Self::Item> {
+      76         152 :         (|| -> Result<Option<Rev>> {
+      77         152 :             let mut prev_rev: Option<Rev> = None;
+      78             :             loop {
+      79       13743 :                 let curr_rev = if let Some(rev) = self.curr_rev.take() {
+      80         152 :                     rev
+      81             :                 } else {
+      82             :                     // smoelius: Note that this is not `git log`'s default behavior. Rather, this
+      83             :                     // behavior corresponds to:
+      84             :                     //   git log --first-parent
+      85       13591 :                     let commit = if let Some(commit) = self.commit.parents().next() {
+      86       13591 :                         self.commit = commit.clone();
+      87       13591 :                         commit
+      88             :                     } else {
+      89           0 :                         return Ok(None);
+      90             :                     };
+      91       13591 :                     self.revs
+      92       13591 :                         .repository
+      93       13591 :                         .checkout_tree(commit.as_object(), None)
+      94       13591 :                         .with_context(|| {
+      95           0 :                             format!("`checkout_tree` failed for `{:?}`", commit.as_object())
+      96       13591 :                         })?;
+      97       13591 :                     self.revs
+      98       13591 :                         .repository
+      99       13591 :                         .set_head_detached(commit.id())
+     100       13591 :                         .with_context(|| {
+     101           0 :                             format!("`set_head_detached` failed for `{}`", commit.id())
+     102       13591 :                         })?;
+     103       13591 :                     let version = clippy_utils_package_version(self.revs.tempdir.path())?;
+     104       13591 :                     let channel = toolchain_channel(self.revs.tempdir.path())?;
+     105       13591 :                     let oid = commit.id();
+     106       13591 :                     Rev {
+     107       13591 :                         version,
+     108       13591 :                         channel,
+     109       13591 :                         oid,
+     110       13591 :                     }
+     111             :                 };
+     112         152 :                 if_chain! {
+     113       13743 :                     if let Some(prev_rev) = prev_rev;
+     114       13591 :                     if prev_rev.version != curr_rev.version;
+     115             :                     then {
+     116         152 :                         self.curr_rev = Some(curr_rev);
+     117         152 :                         return Ok(Some(prev_rev));
+     118             :                     }
+     119             :                 }
+     120       13591 :                 prev_rev = Some(curr_rev);
+     121             :             }
+     122         152 :         })()
+     123         152 :         .transpose()
+     124         152 :     }
+     125             : }
+     126             : 
+     127             : #[allow(clippy::unwrap_used)]
+     128             : #[cfg(test)]
+     129             : mod test {
+     130             :     use super::*;
+     131             :     use once_cell::sync::Lazy;
+     132             : 
+     133           1 :     static EXAMPLES: Lazy<[Rev; 6]> = Lazy::new(|| {
+     134           1 :         [
+     135           1 :             Rev {
+     136           1 :                 version: "0.1.65".to_owned(),
+     137           1 :                 channel: "nightly-2022-08-11".to_owned(),
+     138           1 :                 oid: Oid::from_str("2b2190cb5667cdd276a24ef8b9f3692209c54a89").unwrap(),
+     139           1 :             },
+     140           1 :             Rev {
+     141           1 :                 version: "0.1.64".to_owned(),
+     142           1 :                 channel: "nightly-2022-06-30".to_owned(),
+     143           1 :                 oid: Oid::from_str("0cb0f7636851f9fcc57085cf80197a2ef6db098f").unwrap(),
+     144           1 :             },
+     145           1 :             // smoelius: 0.1.62 and 0.1.63 omitted (for no particular reason).
+     146           1 :             Rev {
+     147           1 :                 version: "0.1.61".to_owned(),
+     148           1 :                 channel: "nightly-2022-02-24".to_owned(),
+     149           1 :                 oid: Oid::from_str("7b2896a8fc9f0b275692677ee6d2d66a7cbde16a").unwrap(),
+     150           1 :             },
+     151           1 :             Rev {
+     152           1 :                 version: "0.1.60".to_owned(),
+     153           1 :                 channel: "nightly-2022-01-13".to_owned(),
+     154           1 :                 oid: Oid::from_str("97a5daa65908e59744e2bc625b14849352231c75").unwrap(),
+     155           1 :             },
+     156           1 :             Rev {
+     157           1 :                 version: "0.1.59".to_owned(),
+     158           1 :                 channel: "nightly-2021-12-02".to_owned(),
+     159           1 :                 oid: Oid::from_str("392b0c5c25ddbd36e4dc480afcf70ed01dce352d").unwrap(),
+     160           1 :             },
+     161           1 :             Rev {
+     162           1 :                 version: "0.1.58".to_owned(),
+     163           1 :                 channel: "nightly-2021-10-21".to_owned(),
+     164           1 :                 oid: Oid::from_str("91496c2ac6abf6454c413bb23e8becf6b6dc20ea").unwrap(),
+     165           1 :             },
+     166           1 :         ]
+     167           1 :     });
+     168             : 
+     169             :     #[test]
+     170           1 :     fn examples() {
+     171           6 :         for example in &*EXAMPLES {
+     172           6 :             let revs = Revs::new(false).unwrap();
+     173           6 :             let mut iter = revs.iter().unwrap();
+     174           6 :             let rev = iter
+     175         137 :                 .find(|rev| {
+     176         137 :                     rev.as_ref()
+     177         137 :                         .map_or(true, |rev| rev.version == example.version)
+     178         137 :                 })
+     179           6 :                 .unwrap()
+     180           6 :                 .unwrap();
+     181           6 :             assert_eq!(rev, *example);
+     182             :         }
+     183           1 :     }
+     184             : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/emerald.png b/coverage/emerald.png new file mode 100644 index 0000000000000000000000000000000000000000..38ad4f4068b935643d2486f323005fb294a9bd7e GIT binary patch literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)ga>?NMQuI!iC1^Jb!lvI6;R0X`wF(yt=9xVZRt1vCRixIA4P dLn>}1Cji+@42)0J?}79&c)I$ztaD0e0sy@GAL0N2 literal 0 HcmV?d00001 diff --git a/coverage/gcov.css b/coverage/gcov.css new file mode 100644 index 000000000..bfd0a83e1 --- /dev/null +++ b/coverage/gcov.css @@ -0,0 +1,519 @@ +/* All views: initial background and text color */ +body +{ + color: #000000; + background-color: #FFFFFF; +} + +/* All views: standard link format*/ +a:link +{ + color: #284FA8; + text-decoration: underline; +} + +/* All views: standard link - visited format */ +a:visited +{ + color: #00CB40; + text-decoration: underline; +} + +/* All views: standard link - activated format */ +a:active +{ + color: #FF0040; + text-decoration: underline; +} + +/* All views: main title format */ +td.title +{ + text-align: center; + padding-bottom: 10px; + font-family: sans-serif; + font-size: 20pt; + font-style: italic; + font-weight: bold; +} + +/* All views: header item format */ +td.headerItem +{ + text-align: right; + padding-right: 6px; + font-family: sans-serif; + font-weight: bold; + vertical-align: top; + white-space: nowrap; +} + +/* All views: header item value format */ +td.headerValue +{ + text-align: left; + color: #284FA8; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; +} + +/* All views: header item coverage table heading */ +td.headerCovTableHead +{ + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + font-size: 80%; + white-space: nowrap; +} + +/* All views: header item coverage table entry */ +td.headerCovTableEntry +{ + text-align: right; + color: #284FA8; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #DAE7FE; +} + +/* All views: header item coverage table entry for high coverage rate */ +td.headerCovTableEntryHi +{ + text-align: right; + color: #000000; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #A7FC9D; +} + +/* All views: header item coverage table entry for medium coverage rate */ +td.headerCovTableEntryMed +{ + text-align: right; + color: #000000; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #FFEA20; +} + +/* All views: header item coverage table entry for ow coverage rate */ +td.headerCovTableEntryLo +{ + text-align: right; + color: #000000; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #FF0000; +} + +/* All views: header legend value for legend entry */ +td.headerValueLeg +{ + text-align: left; + color: #000000; + font-family: sans-serif; + font-size: 80%; + white-space: nowrap; + padding-top: 4px; +} + +/* All views: color of horizontal ruler */ +td.ruler +{ + background-color: #6688D4; +} + +/* All views: version string format */ +td.versionInfo +{ + text-align: center; + padding-top: 2px; + font-family: sans-serif; + font-style: italic; +} + +/* Directory view/File view (all)/Test case descriptions: + table headline format */ +td.tableHead +{ + text-align: center; + color: #FFFFFF; + background-color: #6688D4; + font-family: sans-serif; + font-size: 120%; + font-weight: bold; + white-space: nowrap; + padding-left: 4px; + padding-right: 4px; +} + +span.tableHeadSort +{ + padding-right: 4px; +} + +/* Directory view/File view (all): filename entry format */ +td.coverFile +{ + text-align: left; + padding-left: 10px; + padding-right: 20px; + color: #284FA8; + background-color: #DAE7FE; + font-family: monospace; +} + +/* Directory view/File view (all): bar-graph entry format*/ +td.coverBar +{ + padding-left: 10px; + padding-right: 10px; + background-color: #DAE7FE; +} + +/* Directory view/File view (all): bar-graph outline color */ +td.coverBarOutline +{ + background-color: #000000; +} + +/* Directory view/File view (all): percentage entry for files with + high coverage rate */ +td.coverPerHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #A7FC9D; + font-weight: bold; + font-family: sans-serif; +} + +/* Directory view/File view (all): line count entry for files with + high coverage rate */ +td.coverNumHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #A7FC9D; + white-space: nowrap; + font-family: sans-serif; +} + +/* Directory view/File view (all): percentage entry for files with + medium coverage rate */ +td.coverPerMed +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #FFEA20; + font-weight: bold; + font-family: sans-serif; +} + +/* Directory view/File view (all): line count entry for files with + medium coverage rate */ +td.coverNumMed +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #FFEA20; + white-space: nowrap; + font-family: sans-serif; +} + +/* Directory view/File view (all): percentage entry for files with + low coverage rate */ +td.coverPerLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #FF0000; + font-weight: bold; + font-family: sans-serif; +} + +/* Directory view/File view (all): line count entry for files with + low coverage rate */ +td.coverNumLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #FF0000; + white-space: nowrap; + font-family: sans-serif; +} + +/* File view (all): "show/hide details" link format */ +a.detail:link +{ + color: #B8D0FF; + font-size:80%; +} + +/* File view (all): "show/hide details" link - visited format */ +a.detail:visited +{ + color: #B8D0FF; + font-size:80%; +} + +/* File view (all): "show/hide details" link - activated format */ +a.detail:active +{ + color: #FFFFFF; + font-size:80%; +} + +/* File view (detail): test name entry */ +td.testName +{ + text-align: right; + padding-right: 10px; + background-color: #DAE7FE; + font-family: sans-serif; +} + +/* File view (detail): test percentage entry */ +td.testPer +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #DAE7FE; + font-family: sans-serif; +} + +/* File view (detail): test lines count entry */ +td.testNum +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #DAE7FE; + font-family: sans-serif; +} + +/* Test case descriptions: test name format*/ +dt +{ + font-family: sans-serif; + font-weight: bold; +} + +/* Test case descriptions: description table body */ +td.testDescription +{ + padding-top: 10px; + padding-left: 30px; + padding-bottom: 10px; + padding-right: 30px; + background-color: #DAE7FE; +} + +/* Source code view: function entry */ +td.coverFn +{ + text-align: left; + padding-left: 10px; + padding-right: 20px; + color: #284FA8; + background-color: #DAE7FE; + font-family: monospace; +} + +/* Source code view: function entry zero count*/ +td.coverFnLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #FF0000; + font-weight: bold; + font-family: sans-serif; +} + +/* Source code view: function entry nonzero count*/ +td.coverFnHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #DAE7FE; + font-weight: bold; + font-family: sans-serif; +} + +/* Source code view: source code format */ +pre.source +{ + font-family: monospace; + white-space: pre; + margin-top: 2px; +} + +/* Source code view: line number format */ +span.lineNum +{ + background-color: #EFE383; +} + +/* Source code view: format for lines which were executed */ +td.lineCov, +span.lineCov +{ + background-color: #CAD7FE; +} + +/* Source code view: format for Cov legend */ +span.coverLegendCov +{ + padding-left: 10px; + padding-right: 10px; + padding-bottom: 2px; + background-color: #CAD7FE; +} + +/* Source code view: format for lines which were not executed */ +td.lineNoCov, +span.lineNoCov +{ + background-color: #FF6230; +} + +/* Source code view: format for NoCov legend */ +span.coverLegendNoCov +{ + padding-left: 10px; + padding-right: 10px; + padding-bottom: 2px; + background-color: #FF6230; +} + +/* Source code view (function table): standard link - visited format */ +td.lineNoCov > a:visited, +td.lineCov > a:visited +{ + color: black; + text-decoration: underline; +} + +/* Source code view: format for lines which were executed only in a + previous version */ +span.lineDiffCov +{ + background-color: #B5F7AF; +} + +/* Source code view: format for branches which were executed + * and taken */ +span.branchCov +{ + background-color: #CAD7FE; +} + +/* Source code view: format for branches which were executed + * but not taken */ +span.branchNoCov +{ + background-color: #FF6230; +} + +/* Source code view: format for branches which were not executed */ +span.branchNoExec +{ + background-color: #FF6230; +} + +/* Source code view: format for the source code heading line */ +pre.sourceHeading +{ + white-space: pre; + font-family: monospace; + font-weight: bold; + margin: 0px; +} + +/* All views: header legend value for low rate */ +td.headerValueLegL +{ + font-family: sans-serif; + text-align: center; + white-space: nowrap; + padding-left: 4px; + padding-right: 2px; + background-color: #FF0000; + font-size: 80%; +} + +/* All views: header legend value for med rate */ +td.headerValueLegM +{ + font-family: sans-serif; + text-align: center; + white-space: nowrap; + padding-left: 2px; + padding-right: 2px; + background-color: #FFEA20; + font-size: 80%; +} + +/* All views: header legend value for hi rate */ +td.headerValueLegH +{ + font-family: sans-serif; + text-align: center; + white-space: nowrap; + padding-left: 2px; + padding-right: 4px; + background-color: #A7FC9D; + font-size: 80%; +} + +/* All views except source code view: legend format for low coverage */ +span.coverLegendCovLo +{ + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + background-color: #FF0000; +} + +/* All views except source code view: legend format for med coverage */ +span.coverLegendCovMed +{ + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + background-color: #FFEA20; +} + +/* All views except source code view: legend format for hi coverage */ +span.coverLegendCovHi +{ + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + background-color: #A7FC9D; +} diff --git a/coverage/glass.png b/coverage/glass.png new file mode 100644 index 0000000000000000000000000000000000000000..e1abc00680a3093c49fdb775ae6bdb6764c95af2 GIT binary patch literal 167 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)gaEa{HEjtmSN`?>!lvI6;R0X`wF z|Ns97GD8ntt^-nxB|(0{3=Yq3q=7g|-tI089jvk*Kn`btM`SSr1Gf+eGhVt|_XjA* zUgGKN%6^Gmn4d%Ph(nkFP>9RZ#WAE}PI3Z}&BVayv3^M*kj3EX>gTe~DWM4f=_Dpv literal 0 HcmV?d00001 diff --git a/coverage/index-sort-f.html b/coverage/index-sort-f.html new file mode 100644 index 000000000..9b7ccb2f6 --- /dev/null +++ b/coverage/index-sort-f.html @@ -0,0 +1,203 @@ + + + + + + + LCOV - unnamed + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top levelHitTotalCoverage
Test:unnamedLines:2244325768.9 %
Date:2024-09-27 12:58:08Functions:24252346.3 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Directory Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
utils/linting/src +
0.0%
+
0.0 %0 / 920.0 %0 / 13
utils/testing/src +
0.0%
+
0.0 %0 / 2970.0 %0 / 45
driver/src +
23.7%23.7%
+
23.7 %69 / 29114.7 %5 / 34
dylint-link/src +
46.7%46.7%
+
46.7 %84 / 18020.8 %5 / 24
cargo-dylint/src +
92.0%92.0%
+
92.0 %150 / 16329.5 %13 / 44
dylint/src/package_options +
91.9%91.9%
+
91.9 %215 / 23450.0 %16 / 32
internal/src +
84.1%84.1%
+
84.1 %503 / 59857.2 %79 / 138
dylint/src/library_packages +
86.7%86.7%
+
86.7 %261 / 30157.4 %35 / 61
dylint/src/library_packages/cargo_cli +
97.3%97.3%
+
97.3 %248 / 25559.5 %25 / 42
dylint/src +
84.5%84.5%
+
84.5 %574 / 67966.2 %45 / 68
dylint/src/library_packages/cargo_cli/util +
66.7%66.7%
+
66.7 %40 / 6085.7 %6 / 7
dylint/src/name_toolchain_map +
93.5%93.5%
+
93.5 %100 / 10786.7 %13 / 15
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/index-sort-l.html b/coverage/index-sort-l.html new file mode 100644 index 000000000..5e2c91584 --- /dev/null +++ b/coverage/index-sort-l.html @@ -0,0 +1,203 @@ + + + + + + + LCOV - unnamed + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top levelHitTotalCoverage
Test:unnamedLines:2244325768.9 %
Date:2024-09-27 12:58:08Functions:24252346.3 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Directory Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
utils/linting/src +
0.0%
+
0.0 %0 / 920.0 %0 / 13
utils/testing/src +
0.0%
+
0.0 %0 / 2970.0 %0 / 45
driver/src +
23.7%23.7%
+
23.7 %69 / 29114.7 %5 / 34
dylint-link/src +
46.7%46.7%
+
46.7 %84 / 18020.8 %5 / 24
dylint/src/library_packages/cargo_cli/util +
66.7%66.7%
+
66.7 %40 / 6085.7 %6 / 7
internal/src +
84.1%84.1%
+
84.1 %503 / 59857.2 %79 / 138
dylint/src +
84.5%84.5%
+
84.5 %574 / 67966.2 %45 / 68
dylint/src/library_packages +
86.7%86.7%
+
86.7 %261 / 30157.4 %35 / 61
dylint/src/package_options +
91.9%91.9%
+
91.9 %215 / 23450.0 %16 / 32
cargo-dylint/src +
92.0%92.0%
+
92.0 %150 / 16329.5 %13 / 44
dylint/src/name_toolchain_map +
93.5%93.5%
+
93.5 %100 / 10786.7 %13 / 15
dylint/src/library_packages/cargo_cli +
97.3%97.3%
+
97.3 %248 / 25559.5 %25 / 42
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/index.html b/coverage/index.html new file mode 100644 index 000000000..c43d564c9 --- /dev/null +++ b/coverage/index.html @@ -0,0 +1,203 @@ + + + + + + + LCOV - unnamed + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top levelHitTotalCoverage
Test:unnamedLines:2244325768.9 %
Date:2024-09-27 12:58:08Functions:24252346.3 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Directory Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
cargo-dylint/src +
92.0%92.0%
+
92.0 %150 / 16329.5 %13 / 44
driver/src +
23.7%23.7%
+
23.7 %69 / 29114.7 %5 / 34
dylint-link/src +
46.7%46.7%
+
46.7 %84 / 18020.8 %5 / 24
dylint/src +
84.5%84.5%
+
84.5 %574 / 67966.2 %45 / 68
dylint/src/library_packages +
86.7%86.7%
+
86.7 %261 / 30157.4 %35 / 61
dylint/src/library_packages/cargo_cli +
97.3%97.3%
+
97.3 %248 / 25559.5 %25 / 42
dylint/src/library_packages/cargo_cli/util +
66.7%66.7%
+
66.7 %40 / 6085.7 %6 / 7
dylint/src/name_toolchain_map +
93.5%93.5%
+
93.5 %100 / 10786.7 %13 / 15
dylint/src/package_options +
91.9%91.9%
+
91.9 %215 / 23450.0 %16 / 32
internal/src +
84.1%84.1%
+
84.1 %503 / 59857.2 %79 / 138
utils/linting/src +
0.0%
+
0.0 %0 / 920.0 %0 / 13
utils/testing/src +
0.0%
+
0.0 %0 / 2970.0 %0 / 45
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/cargo.rs.func-sort-c.html b/coverage/internal/src/cargo.rs.func-sort-c.html new file mode 100644 index 000000000..cb9d2c1b9 --- /dev/null +++ b/coverage/internal/src/cargo.rs.func-sort-c.html @@ -0,0 +1,168 @@ + + + + + + + LCOV - unnamed - internal/src/cargo.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - cargo.rs (source / functions)HitTotalCoverage
Test:unnamedLines:10811792.3 %
Date:2024-09-27 12:58:08Functions:182475.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<dylint_internal::cargo::Builder>::quiet::<_>0
dylint_internal::cargo::package::{closure#1}0
dylint_internal::cargo::package_with_root::{closure#0}::{closure#0}0
dylint_internal::cargo::package_with_root::{closure#1}0
dylint_internal::cargo::run0
dylint_internal::cargo::update0
dylint_internal::cargo::fix1
dylint_internal::cargo::test3
dylint_internal::cargo::STABLE_CARGO::{closure#0}6
<dylint_internal::cargo::Builder>::quiet::<dylint_internal::cargo::Quiet>11
dylint_internal::cargo::current_metadata11
dylint_internal::cargo::fetch11
dylint_internal::cargo::init18
<dylint_internal::cargo::Builder>::stable20
dylint_internal::cargo::check21
dylint_internal::cargo::package_with_root30
<dylint_internal::cargo::Builder>::quiet::<bool>36
<dylint_internal::cargo::Quiet as core::convert::From<bool>>::from36
dylint_internal::cargo::build55
dylint_internal::cargo::package63
<dylint_internal::cargo::Builder>::build109
<dylint_internal::cargo::Builder>::new109
dylint_internal::cargo::package::{closure#0}252
dylint_internal::cargo::package_with_root::{closure#0}288
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/cargo.rs.func.html b/coverage/internal/src/cargo.rs.func.html new file mode 100644 index 000000000..5fc88c0a8 --- /dev/null +++ b/coverage/internal/src/cargo.rs.func.html @@ -0,0 +1,168 @@ + + + + + + + LCOV - unnamed - internal/src/cargo.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - cargo.rs (source / functions)HitTotalCoverage
Test:unnamedLines:10811792.3 %
Date:2024-09-27 12:58:08Functions:182475.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<dylint_internal::cargo::Builder>::build109
<dylint_internal::cargo::Builder>::new109
<dylint_internal::cargo::Builder>::quiet::<_>0
<dylint_internal::cargo::Builder>::quiet::<bool>36
<dylint_internal::cargo::Builder>::quiet::<dylint_internal::cargo::Quiet>11
<dylint_internal::cargo::Builder>::stable20
<dylint_internal::cargo::Quiet as core::convert::From<bool>>::from36
dylint_internal::cargo::STABLE_CARGO::{closure#0}6
dylint_internal::cargo::build55
dylint_internal::cargo::check21
dylint_internal::cargo::current_metadata11
dylint_internal::cargo::fetch11
dylint_internal::cargo::fix1
dylint_internal::cargo::init18
dylint_internal::cargo::package63
dylint_internal::cargo::package::{closure#0}252
dylint_internal::cargo::package::{closure#1}0
dylint_internal::cargo::package_with_root30
dylint_internal::cargo::package_with_root::{closure#0}288
dylint_internal::cargo::package_with_root::{closure#0}::{closure#0}0
dylint_internal::cargo::package_with_root::{closure#1}0
dylint_internal::cargo::run0
dylint_internal::cargo::test3
dylint_internal::cargo::update0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/cargo.rs.gcov.html b/coverage/internal/src/cargo.rs.gcov.html new file mode 100644 index 000000000..13f6ef99d --- /dev/null +++ b/coverage/internal/src/cargo.rs.gcov.html @@ -0,0 +1,281 @@ + + + + + + + LCOV - unnamed - internal/src/cargo.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - cargo.rs (source / functions)HitTotalCoverage
Test:unnamedLines:10811792.3 %
Date:2024-09-27 12:58:08Functions:182475.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : use crate::CommandExt;
+       2             : use ansi_term::Style;
+       3             : use anyhow::{anyhow, ensure, Result};
+       4             : use bitflags::bitflags;
+       5             : use cargo_metadata::{Metadata, MetadataCommand, Package, PackageId};
+       6             : use is_terminal::IsTerminal;
+       7             : use once_cell::sync::Lazy;
+       8             : use std::{
+       9             :     io::Write,
+      10             :     path::{Path, PathBuf},
+      11             :     process::{Command, Stdio},
+      12             : };
+      13             : 
+      14             : #[allow(clippy::module_name_repetitions)]
+      15             : pub use home::cargo_home;
+      16             : 
+      17           6 : static STABLE_CARGO: Lazy<PathBuf> = Lazy::new(|| {
+      18           6 :     let mut command = Command::new("rustup");
+      19           6 :     command.args(["+stable", "which", "cargo"]);
+      20           6 :     let output = command.logged_output(true).unwrap();
+      21           6 :     assert!(output.status.success());
+      22           6 :     let stdout = String::from_utf8(output.stdout).unwrap();
+      23           6 :     PathBuf::from(stdout.trim_end())
+      24           6 : });
+      25             : 
+      26             : bitflags! {
+      27             :     pub struct Quiet: u8 {
+      28             :         const MESSAGE = 1 << 0;
+      29             :         const STDERR = 1 << 1;
+      30             :     }
+      31             : }
+      32             : 
+      33             : impl From<bool> for Quiet {
+      34          36 :     fn from(value: bool) -> Self {
+      35          36 :         if value {
+      36           9 :             Self::all()
+      37             :         } else {
+      38          27 :             Self::empty()
+      39             :         }
+      40          36 :     }
+      41             : }
+      42             : 
+      43             : /// A `cargo` command builder
+      44             : ///
+      45             : /// Note that [`std::process::Command`]is itself a builder. So technically that makes this a
+      46             : /// "builder builder".
+      47             : pub struct Builder {
+      48             :     subcommand: String,
+      49             :     verb: String,
+      50             :     description: String,
+      51             :     quiet: Quiet,
+      52             :     stable: bool,
+      53             : }
+      54             : 
+      55             : #[must_use]
+      56          55 : pub fn build(description: &str) -> Builder {
+      57          55 :     Builder::new("build", "Building", description)
+      58          55 : }
+      59             : 
+      60             : #[must_use]
+      61          21 : pub fn check(description: &str) -> Builder {
+      62          21 :     Builder::new("check", "Checking", description)
+      63          21 : }
+      64             : 
+      65             : #[must_use]
+      66          11 : pub fn fetch(description: &str) -> Builder {
+      67          11 :     Builder::new("fetch", "Fetching", description)
+      68          11 : }
+      69             : 
+      70             : #[must_use]
+      71           1 : pub fn fix(description: &str) -> Builder {
+      72           1 :     Builder::new("fix", "Fixing", description)
+      73           1 : }
+      74             : 
+      75             : #[must_use]
+      76          18 : pub fn init(description: &str) -> Builder {
+      77          18 :     Builder::new("init", "Initializing", description)
+      78          18 : }
+      79             : 
+      80             : #[must_use]
+      81           0 : pub fn run(description: &str) -> Builder {
+      82           0 :     Builder::new("run", "Running", description)
+      83           0 : }
+      84             : 
+      85             : #[must_use]
+      86           3 : pub fn test(description: &str) -> Builder {
+      87           3 :     Builder::new("test", "Testing", description)
+      88           3 : }
+      89             : 
+      90             : #[must_use]
+      91           0 : pub fn update(description: &str) -> Builder {
+      92           0 :     Builder::new("update", "Updating", description)
+      93           0 : }
+      94             : 
+      95             : impl Builder {
+      96         109 :     fn new(subcommand: &str, verb: &str, description: &str) -> Self {
+      97         109 :         Self {
+      98         109 :             subcommand: subcommand.to_owned(),
+      99         109 :             verb: verb.to_owned(),
+     100         109 :             description: description.to_owned(),
+     101         109 :             quiet: Quiet::empty(),
+     102         109 :             stable: false,
+     103         109 :         }
+     104         109 :     }
+     105             : 
+     106             :     /// Whether to allow the command to write to standard error.
+     107          47 :     pub fn quiet(&mut self, value: impl Into<Quiet>) -> &mut Self {
+     108          47 :         let value = value.into();
+     109          47 :         // smoelius: `cargo check` and `cargo fix` are never silenced.
+     110          47 :         if !value.is_empty() {
+     111          20 :             assert!(!matches!(self.subcommand.as_str(), "check" | "fix"));
+     112          27 :         }
+     113          47 :         self.quiet = value;
+     114          47 :         self
+     115          47 :     }
+     116             : 
+     117             :     /// Whether to use a cached path to stable `cargo`. Using the cached path avoids repeated calls
+     118             :     /// to `rustup`.
+     119          20 :     pub fn stable(&mut self, value: bool) -> &mut Self {
+     120          20 :         self.stable = value;
+     121          20 :         self
+     122          20 :     }
+     123             : 
+     124             :     /// Consumes the builder and returns a [`std::process::Command`].
+     125             :     #[allow(clippy::needless_pass_by_ref_mut)]
+     126         109 :     pub fn build(&mut self) -> Command {
+     127         109 :         if !self.quiet.contains(Quiet::MESSAGE) {
+     128             :             // smoelius: Writing directly to `stderr` prevents capture by `libtest`.
+     129          89 :             let message = format!("{} {}", self.verb, self.description);
+     130          89 :             std::io::stderr()
+     131          89 :                 .write_fmt(format_args!(
+     132          89 :                     "{}\n",
+     133          89 :                     if std::io::stderr().is_terminal() {
+     134           0 :                         Style::new().bold()
+     135             :                     } else {
+     136          89 :                         Style::new()
+     137             :                     }
+     138          89 :                     .paint(message)
+     139          89 :                 ))
+     140          89 :                 .expect("Could not write to stderr");
+     141          20 :         }
+     142         109 :         let mut command = if self.stable {
+     143          20 :             Command::new(&*STABLE_CARGO)
+     144             :         } else {
+     145          89 :             Command::new("cargo")
+     146             :         };
+     147             :         #[cfg(windows)]
+     148             :         {
+     149             :             // smoelius: Work around: https://github.com/rust-lang/rustup/pull/2978
+     150             :             let cargo_home = cargo_home().unwrap();
+     151             :             let new_path = crate::prepend_path(Path::new(&cargo_home).join("bin")).unwrap();
+     152             :             command.envs(vec![(crate::env::PATH, new_path)]);
+     153             :         }
+     154         109 :         command.args([&self.subcommand]);
+     155         109 :         if self.quiet.contains(Quiet::STDERR) {
+     156           9 :             command.stderr(Stdio::null());
+     157         100 :         }
+     158         109 :         command
+     159         109 :     }
+     160             : }
+     161             : 
+     162             : /// Get metadata based on the current directory.
+     163          11 : pub fn current_metadata() -> Result<Metadata> {
+     164          11 :     MetadataCommand::new().no_deps().exec().map_err(Into::into)
+     165          11 : }
+     166             : 
+     167          30 : pub fn package_with_root(metadata: &Metadata, package_root: &Path) -> Result<Package> {
+     168          30 :     let packages = metadata
+     169          30 :         .packages
+     170          30 :         .iter()
+     171         288 :         .map(|package| {
+     172         288 :             let path = package
+     173         288 :                 .manifest_path
+     174         288 :                 .parent()
+     175         288 :                 .ok_or_else(|| anyhow!("Could not get parent directory"))?;
+     176         288 :             Ok(if path == package_root {
+     177          30 :                 Some(package)
+     178             :             } else {
+     179         258 :                 None
+     180             :             })
+     181         288 :         })
+     182          30 :         .filter_map(Result::transpose)
+     183          30 :         .collect::<Result<Vec<_>>>()?;
+     184             : 
+     185          30 :     ensure!(
+     186          30 :         packages.len() <= 1,
+     187           0 :         "Found multiple packages in `{}`",
+     188           0 :         package_root.to_string_lossy()
+     189             :     );
+     190             : 
+     191          30 :     packages
+     192          30 :         .into_iter()
+     193          30 :         .next()
+     194          30 :         .cloned()
+     195          30 :         .ok_or_else(|| anyhow!("Found no packages in `{}`", package_root.to_string_lossy()))
+     196          30 : }
+     197             : 
+     198          63 : pub fn package(metadata: &Metadata, package_id: &PackageId) -> Result<Package> {
+     199          63 :     metadata
+     200          63 :         .packages
+     201          63 :         .iter()
+     202         252 :         .find(|package| package.id == *package_id)
+     203          63 :         .cloned()
+     204          63 :         .ok_or_else(|| anyhow!("Could not find package"))
+     205          63 : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/clippy_utils.rs.func-sort-c.html b/coverage/internal/src/clippy_utils.rs.func-sort-c.html new file mode 100644 index 000000000..bea965f13 --- /dev/null +++ b/coverage/internal/src/clippy_utils.rs.func-sort-c.html @@ -0,0 +1,164 @@ + + + + + + + LCOV - unnamed - internal/src/clippy_utils.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - clippy_utils.rs (source / functions)HitTotalCoverage
Test:unnamedLines:689174.7 %
Date:2024-09-27 12:58:08Functions:132356.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint_internal::clippy_utils::clippy_utils_package_version::{closure#0}0
dylint_internal::clippy_utils::clippy_utils_package_version::{closure#2}0
dylint_internal::clippy_utils::set_clippy_utils_dependency_revision::{closure#0}0
dylint_internal::clippy_utils::set_clippy_utils_dependency_revision::{closure#2}0
dylint_internal::clippy_utils::set_clippy_utils_dependency_revision::{closure#3}0
dylint_internal::clippy_utils::set_clippy_utils_dependency_revision::{closure#6}0
dylint_internal::clippy_utils::set_toolchain_channel::{closure#0}0
dylint_internal::clippy_utils::set_toolchain_channel::{closure#3}0
dylint_internal::clippy_utils::toolchain_channel::{closure#0}0
dylint_internal::clippy_utils::toolchain_channel::{closure#2}0
dylint_internal::clippy_utils::clippy_utils_version_from_rust_version2
dylint_internal::clippy_utils::clippy_utils_version_from_rust_version::{closure#0}2
dylint_internal::clippy_utils::set_clippy_utils_dependency_revision4
dylint_internal::clippy_utils::set_clippy_utils_dependency_revision::{closure#1}4
dylint_internal::clippy_utils::set_clippy_utils_dependency_revision::{closure#4}4
dylint_internal::clippy_utils::set_clippy_utils_dependency_revision::{closure#5}4
dylint_internal::clippy_utils::set_toolchain_channel4
dylint_internal::clippy_utils::set_toolchain_channel::{closure#1}4
dylint_internal::clippy_utils::set_toolchain_channel::{closure#2}4
dylint_internal::clippy_utils::clippy_utils_package_version13600
dylint_internal::clippy_utils::clippy_utils_package_version::{closure#1}13600
dylint_internal::clippy_utils::toolchain_channel13603
dylint_internal::clippy_utils::toolchain_channel::{closure#1}13603
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/clippy_utils.rs.func.html b/coverage/internal/src/clippy_utils.rs.func.html new file mode 100644 index 000000000..d26ffcf4e --- /dev/null +++ b/coverage/internal/src/clippy_utils.rs.func.html @@ -0,0 +1,164 @@ + + + + + + + LCOV - unnamed - internal/src/clippy_utils.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - clippy_utils.rs (source / functions)HitTotalCoverage
Test:unnamedLines:689174.7 %
Date:2024-09-27 12:58:08Functions:132356.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint_internal::clippy_utils::clippy_utils_package_version13600
dylint_internal::clippy_utils::clippy_utils_package_version::{closure#0}0
dylint_internal::clippy_utils::clippy_utils_package_version::{closure#1}13600
dylint_internal::clippy_utils::clippy_utils_package_version::{closure#2}0
dylint_internal::clippy_utils::clippy_utils_version_from_rust_version2
dylint_internal::clippy_utils::clippy_utils_version_from_rust_version::{closure#0}2
dylint_internal::clippy_utils::set_clippy_utils_dependency_revision4
dylint_internal::clippy_utils::set_clippy_utils_dependency_revision::{closure#0}0
dylint_internal::clippy_utils::set_clippy_utils_dependency_revision::{closure#1}4
dylint_internal::clippy_utils::set_clippy_utils_dependency_revision::{closure#2}0
dylint_internal::clippy_utils::set_clippy_utils_dependency_revision::{closure#3}0
dylint_internal::clippy_utils::set_clippy_utils_dependency_revision::{closure#4}4
dylint_internal::clippy_utils::set_clippy_utils_dependency_revision::{closure#5}4
dylint_internal::clippy_utils::set_clippy_utils_dependency_revision::{closure#6}0
dylint_internal::clippy_utils::set_toolchain_channel4
dylint_internal::clippy_utils::set_toolchain_channel::{closure#0}0
dylint_internal::clippy_utils::set_toolchain_channel::{closure#1}4
dylint_internal::clippy_utils::set_toolchain_channel::{closure#2}4
dylint_internal::clippy_utils::set_toolchain_channel::{closure#3}0
dylint_internal::clippy_utils::toolchain_channel13603
dylint_internal::clippy_utils::toolchain_channel::{closure#0}0
dylint_internal::clippy_utils::toolchain_channel::{closure#1}13603
dylint_internal::clippy_utils::toolchain_channel::{closure#2}0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/clippy_utils.rs.gcov.html b/coverage/internal/src/clippy_utils.rs.gcov.html new file mode 100644 index 000000000..df50cc37d --- /dev/null +++ b/coverage/internal/src/clippy_utils.rs.gcov.html @@ -0,0 +1,182 @@ + + + + + + + LCOV - unnamed - internal/src/clippy_utils.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - clippy_utils.rs (source / functions)HitTotalCoverage
Test:unnamedLines:689174.7 %
Date:2024-09-27 12:58:08Functions:132356.5 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : use anyhow::{anyhow, Context, Result};
+       2             : use semver::Version;
+       3             : use std::{
+       4             :     fs::{read_to_string, write},
+       5             :     path::Path,
+       6             : };
+       7             : use toml_edit::{DocumentMut, Item, Value};
+       8             : 
+       9             : #[allow(clippy::module_name_repetitions)]
+      10           2 : pub fn clippy_utils_version_from_rust_version(rust_version: &str) -> Result<String> {
+      11           2 :     Version::parse(rust_version.strip_prefix("rust-").unwrap_or(rust_version))
+      12           2 :         .map(|version| Version::new(0, version.major, version.minor).to_string())
+      13           2 :         .map_err(Into::into)
+      14           2 : }
+      15             : 
+      16             : #[allow(clippy::module_name_repetitions)]
+      17       13600 : pub fn clippy_utils_package_version(path: &Path) -> Result<String> {
+      18       13600 :     let cargo_toml = path.join("clippy_utils/Cargo.toml");
+      19       13600 :     let contents = read_to_string(&cargo_toml).with_context(|| {
+      20           0 :         format!(
+      21           0 :             "`read_to_string` failed for `{}`",
+      22           0 :             cargo_toml.to_string_lossy(),
+      23           0 :         )
+      24       13600 :     })?;
+      25       13600 :     let document = contents.parse::<DocumentMut>()?;
+      26       13600 :     document
+      27       13600 :         .as_table()
+      28       13600 :         .get("package")
+      29       13600 :         .and_then(Item::as_table)
+      30       13600 :         .and_then(|table| table.get("version"))
+      31       13600 :         .and_then(Item::as_str)
+      32       13600 :         .map(ToOwned::to_owned)
+      33       13600 :         .ok_or_else(|| anyhow!("Could not determine `clippy_utils` version"))
+      34       13600 : }
+      35             : 
+      36           4 : pub fn set_clippy_utils_dependency_revision(path: &Path, rev: &str) -> Result<()> {
+      37           4 :     let cargo_toml = path.join("Cargo.toml");
+      38           4 :     let contents = read_to_string(&cargo_toml).with_context(|| {
+      39           0 :         format!(
+      40           0 :             "`read_to_string` failed for `{}`",
+      41           0 :             cargo_toml.to_string_lossy(),
+      42           0 :         )
+      43           4 :     })?;
+      44           4 :     let mut document = contents.parse::<DocumentMut>()?;
+      45             :     // smoelius: First check `dependencies` for `clippy_utils`.
+      46           4 :     let mut clippy_utils = document
+      47           4 :         .as_table_mut()
+      48           4 :         .get_mut("dependencies")
+      49           4 :         .and_then(Item::as_table_mut)
+      50           4 :         .and_then(|table| table.get_mut("clippy_utils"));
+      51           4 :     // smoelius: It it's not found there, check `workspace.dependencies`.
+      52           4 :     if clippy_utils.is_none() {
+      53           0 :         clippy_utils = document
+      54           0 :             .as_table_mut()
+      55           0 :             .get_mut("workspace")
+      56           0 :             .and_then(Item::as_table_mut)
+      57           0 :             .and_then(|table| table.get_mut("dependencies"))
+      58           0 :             .and_then(Item::as_table_mut)
+      59           0 :             .and_then(|table| table.get_mut("clippy_utils"));
+      60           4 :     };
+      61           4 :     clippy_utils
+      62           4 :         .and_then(Item::as_inline_table_mut)
+      63           4 :         .and_then(|table| table.get_mut("rev"))
+      64           4 :         .map(|value| *value = Value::from(rev))
+      65           4 :         .ok_or_else(|| anyhow!("Could not set `clippy_utils` revision"))?;
+      66           4 :     write(cargo_toml, document.to_string()).map_err(Into::into)
+      67           4 : }
+      68             : 
+      69       13603 : pub fn toolchain_channel(path: &Path) -> Result<String> {
+      70       13603 :     let rust_toolchain = path.join("rust-toolchain");
+      71       13603 :     let contents = read_to_string(&rust_toolchain).with_context(|| {
+      72           0 :         format!(
+      73           0 :             "`read_to_string` failed for `{}`",
+      74           0 :             rust_toolchain.to_string_lossy(),
+      75           0 :         )
+      76       13603 :     })?;
+      77       13603 :     let document = contents.parse::<DocumentMut>()?;
+      78       13603 :     document
+      79       13603 :         .as_table()
+      80       13603 :         .get("toolchain")
+      81       13603 :         .and_then(Item::as_table)
+      82       13603 :         .and_then(|table| table.get("channel"))
+      83       13603 :         .and_then(Item::as_str)
+      84       13603 :         .map(ToOwned::to_owned)
+      85       13603 :         .ok_or_else(|| anyhow!("Could not determine Rust toolchain channel"))
+      86       13603 : }
+      87             : 
+      88           4 : pub fn set_toolchain_channel(path: &Path, channel: &str) -> Result<()> {
+      89           4 :     let rust_toolchain = path.join("rust-toolchain");
+      90           4 :     let contents = read_to_string(&rust_toolchain).with_context(|| {
+      91           0 :         format!(
+      92           0 :             "`read_to_string` failed for `{}`",
+      93           0 :             rust_toolchain.to_string_lossy(),
+      94           0 :         )
+      95           4 :     })?;
+      96           4 :     let mut document = contents.parse::<DocumentMut>()?;
+      97           4 :     document
+      98           4 :         .as_table_mut()
+      99           4 :         .get_mut("toolchain")
+     100           4 :         .and_then(Item::as_table_mut)
+     101           4 :         .and_then(|table| table.get_mut("channel"))
+     102           4 :         .and_then(Item::as_value_mut)
+     103           4 :         .map(|value| *value = Value::from(channel))
+     104           4 :         .ok_or_else(|| anyhow!("Could not set Rust toolchain channel"))?;
+     105           4 :     write(rust_toolchain, document.to_string()).map_err(Into::into)
+     106           4 : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/command.rs.func-sort-c.html b/coverage/internal/src/command.rs.func-sort-c.html new file mode 100644 index 000000000..b3f53c7d2 --- /dev/null +++ b/coverage/internal/src/command.rs.func-sort-c.html @@ -0,0 +1,100 @@ + + + + + + + LCOV - unnamed - internal/src/command.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - command.rs (source / functions)HitTotalCoverage
Test:unnamedLines:335362.3 %
Date:2024-09-27 12:58:08Functions:3742.9 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<std::process::Command as dylint_internal::command::CommandExt>::logged_output::{closure#0}0
<std::process::Command as dylint_internal::command::CommandExt>::success::{closure#0}0
dylint_internal::command::prepend_path::<_>0
dylint_internal::command::prepend_toolchain_path::<_>0
dylint_internal::command::driver33
<std::process::Command as dylint_internal::command::CommandExt>::logged_output79
<std::process::Command as dylint_internal::command::CommandExt>::success125
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/command.rs.func.html b/coverage/internal/src/command.rs.func.html new file mode 100644 index 000000000..81e924d6d --- /dev/null +++ b/coverage/internal/src/command.rs.func.html @@ -0,0 +1,100 @@ + + + + + + + LCOV - unnamed - internal/src/command.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - command.rs (source / functions)HitTotalCoverage
Test:unnamedLines:335362.3 %
Date:2024-09-27 12:58:08Functions:3742.9 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<std::process::Command as dylint_internal::command::CommandExt>::logged_output79
<std::process::Command as dylint_internal::command::CommandExt>::logged_output::{closure#0}0
<std::process::Command as dylint_internal::command::CommandExt>::success125
<std::process::Command as dylint_internal::command::CommandExt>::success::{closure#0}0
dylint_internal::command::driver33
dylint_internal::command::prepend_path::<_>0
dylint_internal::command::prepend_toolchain_path::<_>0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/command.rs.gcov.html b/coverage/internal/src/command.rs.gcov.html new file mode 100644 index 000000000..8f5a132c7 --- /dev/null +++ b/coverage/internal/src/command.rs.gcov.html @@ -0,0 +1,163 @@ + + + + + + + LCOV - unnamed - internal/src/command.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - command.rs (source / functions)HitTotalCoverage
Test:unnamedLines:335362.3 %
Date:2024-09-27 12:58:08Functions:3742.9 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : use anyhow::{ensure, Context, Result};
+       2             : use std::{
+       3             :     ffi::{OsStr, OsString},
+       4             :     path::{Path, PathBuf},
+       5             :     process::{Command, Output},
+       6             : };
+       7             : 
+       8             : #[allow(clippy::module_name_repetitions)]
+       9             : pub trait CommandExt {
+      10             :     fn logged_output(&mut self, require_success: bool) -> Result<Output>;
+      11             :     fn success(&mut self) -> Result<()>;
+      12             : }
+      13             : 
+      14             : impl CommandExt for Command {
+      15             :     #[cfg_attr(dylint_lib = "general", allow(non_local_effect_before_error_return))]
+      16             :     #[cfg_attr(dylint_lib = "overscoped_allow", allow(overscoped_allow))]
+      17          79 :     fn logged_output(&mut self, require_success: bool) -> Result<Output> {
+      18          79 :         log::debug!("{:?}", self.get_envs().collect::<Vec<_>>());
+      19          79 :         log::debug!("{:?}", self.get_current_dir());
+      20          79 :         log::debug!("{:?}", self);
+      21             : 
+      22             :         #[allow(clippy::disallowed_methods)]
+      23          79 :         let output = self
+      24          79 :             .output()
+      25          79 :             .with_context(|| format!("Could not get output of `{self:?}`"))?;
+      26             : 
+      27          79 :         ensure!(
+      28          79 :             !require_success || output.status.success(),
+      29           0 :             "command failed: {:?}\nstdout: {:?}\nstderr: {:?}",
+      30           0 :             self,
+      31           0 :             std::str::from_utf8(&output.stdout).unwrap_or_default(),
+      32           0 :             std::str::from_utf8(&output.stderr).unwrap_or_default()
+      33             :         );
+      34             : 
+      35          79 :         Ok(output)
+      36          79 :     }
+      37             : 
+      38             :     // smoelius: Why not get the status by calling `self.output()`? Because we don't want stdout and
+      39             :     // stderr to be captured.
+      40             :     #[cfg_attr(dylint_lib = "general", allow(non_local_effect_before_error_return))]
+      41             :     #[cfg_attr(dylint_lib = "overscoped_allow", allow(overscoped_allow))]
+      42         125 :     fn success(&mut self) -> Result<()> {
+      43         125 :         log::debug!("{:?}", self.get_envs().collect::<Vec<_>>());
+      44         125 :         log::debug!("{:?}", self.get_current_dir());
+      45         125 :         log::debug!("{:?}", self);
+      46             : 
+      47         125 :         let status = self
+      48         125 :             .status()
+      49         125 :             .with_context(|| format!("Could not get status of `{self:?}`"))?;
+      50             : 
+      51         125 :         ensure!(status.success(), "command failed: {:?}", self);
+      52             : 
+      53         122 :         Ok(())
+      54         125 :     }
+      55             : }
+      56             : 
+      57             : #[allow(unused_variables)]
+      58          33 : pub fn driver(toolchain: &str, driver: &Path) -> Result<Command> {
+      59          33 :     #[allow(unused_mut)]
+      60          33 :     let mut command = Command::new(driver);
+      61          33 :     #[cfg(windows)]
+      62          33 :     {
+      63          33 :         // MinerSebas: To succesfully determine the dylint driver Version on Windows,
+      64          33 :         // it is neccesary to add some Libraries to the Path.
+      65          33 :         let new_path = prepend_toolchain_path(toolchain)?;
+      66          33 :         command.envs(vec![(crate::env::PATH, new_path)]);
+      67          33 :     }
+      68          33 :     Ok(command)
+      69          33 : }
+      70             : 
+      71           0 : pub fn prepend_toolchain_path(toolchain: impl AsRef<Path>) -> Result<OsString> {
+      72           0 :     let rustup_home = crate::env::var(crate::env::RUSTUP_HOME)?;
+      73           0 :     prepend_path(
+      74           0 :         Path::new(&rustup_home)
+      75           0 :             .join("toolchains")
+      76           0 :             .join(toolchain)
+      77           0 :             .join("bin"),
+      78           0 :     )
+      79           0 : }
+      80             : 
+      81           0 : pub fn prepend_path(path: impl AsRef<OsStr>) -> Result<OsString> {
+      82           0 :     let old_path = crate::env::var(crate::env::PATH)?;
+      83           0 :     let new_path = std::env::join_paths(
+      84           0 :         std::iter::once(PathBuf::from(path.as_ref())).chain(std::env::split_paths(&old_path)),
+      85           0 :     )?;
+      86           0 :     Ok(new_path)
+      87           0 : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/config.rs.func-sort-c.html b/coverage/internal/src/config.rs.func-sort-c.html new file mode 100644 index 000000000..29be1d49d --- /dev/null +++ b/coverage/internal/src/config.rs.func-sort-c.html @@ -0,0 +1,116 @@ + + + + + + + LCOV - unnamed - internal/src/config.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - config.rs (source / functions)HitTotalCoverage
Test:unnamedLines:355366.0 %
Date:2024-09-27 12:58:08Functions:31127.3 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<dylint_internal::config::Error as core::convert::From<_>>::from0
<dylint_internal::config::Error as core::convert::From<dylint_internal::config::Inner>>::from0
<dylint_internal::config::Error as core::convert::From<toml::de::Error>>::from0
<dylint_internal::config::Error as core::fmt::Display>::fmt0
<dylint_internal::config::Error>::other0
dylint_internal::config::init_from_string::{closure#0}0
dylint_internal::config::try_init_with_metadata::{closure#0}0
dylint_internal::config::try_init_with_metadata::{closure#1}0
dylint_internal::config::init_from_string1
dylint_internal::config::get24
dylint_internal::config::try_init_with_metadata24
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/config.rs.func.html b/coverage/internal/src/config.rs.func.html new file mode 100644 index 000000000..80511c5f5 --- /dev/null +++ b/coverage/internal/src/config.rs.func.html @@ -0,0 +1,116 @@ + + + + + + + LCOV - unnamed - internal/src/config.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - config.rs (source / functions)HitTotalCoverage
Test:unnamedLines:355366.0 %
Date:2024-09-27 12:58:08Functions:31127.3 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<dylint_internal::config::Error as core::convert::From<_>>::from0
<dylint_internal::config::Error as core::convert::From<dylint_internal::config::Inner>>::from0
<dylint_internal::config::Error as core::convert::From<toml::de::Error>>::from0
<dylint_internal::config::Error as core::fmt::Display>::fmt0
<dylint_internal::config::Error>::other0
dylint_internal::config::get24
dylint_internal::config::init_from_string1
dylint_internal::config::init_from_string::{closure#0}0
dylint_internal::config::try_init_with_metadata24
dylint_internal::config::try_init_with_metadata::{closure#0}0
dylint_internal::config::try_init_with_metadata::{closure#1}0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/config.rs.gcov.html b/coverage/internal/src/config.rs.gcov.html new file mode 100644 index 000000000..33917db9c --- /dev/null +++ b/coverage/internal/src/config.rs.gcov.html @@ -0,0 +1,181 @@ + + + + + + + LCOV - unnamed - internal/src/config.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - config.rs (source / functions)HitTotalCoverage
Test:unnamedLines:355366.0 %
Date:2024-09-27 12:58:08Functions:31127.3 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : use std::{fs::read_to_string, sync::OnceLock};
+       2             : use thiserror::Error as ThisError;
+       3             : 
+       4             : pub type Result<T> = std::result::Result<T, Error>;
+       5             : 
+       6             : #[derive(Debug, ThisError)]
+       7             : pub struct Error {
+       8             :     inner: Inner,
+       9             : }
+      10             : 
+      11             : impl Error {
+      12             :     #[must_use]
+      13           0 :     pub const fn other(value: String) -> Self {
+      14           0 :         Self {
+      15           0 :             inner: Inner::Other(value),
+      16           0 :         }
+      17           0 :     }
+      18             : }
+      19             : 
+      20             : impl std::fmt::Display for Error {
+      21           0 :     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+      22           0 :         write!(f, "{}", self.inner)
+      23           0 :     }
+      24             : }
+      25             : 
+      26             : impl<T> From<T> for Error
+      27             : where
+      28             :     Inner: From<T>,
+      29             : {
+      30           0 :     fn from(value: T) -> Self {
+      31           0 :         Self {
+      32           0 :             inner: Inner::from(value),
+      33           0 :         }
+      34           0 :     }
+      35             : }
+      36             : 
+      37             : #[derive(Debug, ThisError)]
+      38             : enum Inner {
+      39             :     #[error("cargo metadata error: {0}")]
+      40             :     CargoMetadata(#[from] cargo_metadata::Error),
+      41             :     #[error("io error: {0}: {1}")]
+      42             :     Io(String, std::io::Error),
+      43             :     #[error("toml error: {0}")]
+      44             :     Toml(#[from] toml::de::Error),
+      45             :     #[error("{0}")]
+      46             :     Other(String),
+      47             : }
+      48             : 
+      49             : static CONFIG_TABLE: OnceLock<toml::value::Table> = OnceLock::new();
+      50             : 
+      51          24 : pub fn get() -> Option<&'static toml::value::Table> {
+      52          24 :     CONFIG_TABLE.get()
+      53          24 : }
+      54             : 
+      55             : // smoelius: `try_init_with_metadata` returns a string so that `dylint_linting` can record it in
+      56             : // `file_depinfo`.
+      57          24 : pub fn try_init_with_metadata(metadata: &cargo_metadata::Metadata) -> Result<Option<String>> {
+      58          24 :     if CONFIG_TABLE.get().is_some() {
+      59           0 :         return Ok(None);
+      60          24 :     }
+      61          24 : 
+      62          24 :     let cargo_metadata::Metadata { workspace_root, .. } = metadata;
+      63          24 : 
+      64          24 :     let dylint_toml = workspace_root.join("dylint.toml");
+      65             : 
+      66          24 :     let value = if dylint_toml
+      67          24 :         .try_exists()
+      68          24 :         .map_err(|error| Inner::Io(format!("`try_exists` failed for {dylint_toml:?}"), error))?
+      69             :     {
+      70           1 :         let value = read_to_string(&dylint_toml).map_err(|error| {
+      71           0 :             Inner::Io(
+      72           0 :                 format!("`read_to_string` failed for {dylint_toml:?}"),
+      73           0 :                 error,
+      74           0 :             )
+      75           1 :         })?;
+      76           1 :         Some(value)
+      77             :     } else {
+      78          23 :         None
+      79             :     };
+      80             : 
+      81          24 :     if let Some(s) = &value {
+      82           1 :         init_from_string(s)?;
+      83          23 :     }
+      84             : 
+      85          24 :     Ok(value)
+      86          24 : }
+      87             : 
+      88           1 : pub fn init_from_string(s: &str) -> Result<()> {
+      89           1 :     assert!(CONFIG_TABLE.get().is_none());
+      90             : 
+      91           1 :     let toml: toml::Value = toml::from_str(s)?;
+      92             : 
+      93           1 :     let table = toml
+      94           1 :         .as_table()
+      95           1 :         .cloned()
+      96           1 :         .ok_or_else(|| Inner::Other("Value is not a table".into()))?;
+      97             : 
+      98             :     // smoelius: Rewrite this function (`init_from_string`) and eliminate the next `expect` once
+      99             :     // `get_or_try_init` stabilizes: https://github.com/rust-lang/rust/issues/109737
+     100           1 :     CONFIG_TABLE
+     101           1 :         .set(table)
+     102           1 :         .expect("`CONFIG_TABLE` was determined to be unset above");
+     103           1 : 
+     104           1 :     Ok(())
+     105           1 : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/env.rs.func-sort-c.html b/coverage/internal/src/env.rs.func-sort-c.html new file mode 100644 index 000000000..a2d49a0a7 --- /dev/null +++ b/coverage/internal/src/env.rs.func-sort-c.html @@ -0,0 +1,88 @@ + + + + + + + LCOV - unnamed - internal/src/env.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - env.rs (source / functions)HitTotalCoverage
Test:unnamedLines:3650.0 %
Date:2024-09-27 12:58:08Functions:2450.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint_internal::env::enabled0
dylint_internal::env::enabled::{closure#0}0
dylint_internal::env::var::{closure#0}80
dylint_internal::env::var87
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/env.rs.func.html b/coverage/internal/src/env.rs.func.html new file mode 100644 index 000000000..0243e9b44 --- /dev/null +++ b/coverage/internal/src/env.rs.func.html @@ -0,0 +1,88 @@ + + + + + + + LCOV - unnamed - internal/src/env.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - env.rs (source / functions)HitTotalCoverage
Test:unnamedLines:3650.0 %
Date:2024-09-27 12:58:08Functions:2450.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint_internal::env::enabled0
dylint_internal::env::enabled::{closure#0}0
dylint_internal::env::var87
dylint_internal::env::var::{closure#0}80
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/env.rs.gcov.html b/coverage/internal/src/env.rs.gcov.html new file mode 100644 index 000000000..09b2e8fb6 --- /dev/null +++ b/coverage/internal/src/env.rs.gcov.html @@ -0,0 +1,141 @@ + + + + + + + LCOV - unnamed - internal/src/env.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - env.rs (source / functions)HitTotalCoverage
Test:unnamedLines:3650.0 %
Date:2024-09-27 12:58:08Functions:2450.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : use anyhow::{anyhow, Result};
+       2             : 
+       3             : macro_rules! declare_const {
+       4             :     ($var: ident) => {
+       5             :         pub const $var: &str = stringify!($var);
+       6             :     };
+       7             : }
+       8             : 
+       9             : declare_const!(CARGO);
+      10             : declare_const!(CARGO_CRATE_NAME);
+      11             : declare_const!(CARGO_HOME);
+      12             : declare_const!(CARGO_INCREMENTAL);
+      13             : declare_const!(CARGO_MANIFEST_DIR);
+      14             : declare_const!(CARGO_PKG_NAME);
+      15             : declare_const!(CARGO_PRIMARY_PACKAGE);
+      16             : declare_const!(CARGO_TARGET_DIR);
+      17             : declare_const!(CARGO_TERM_COLOR);
+      18             : declare_const!(CI);
+      19             : declare_const!(CLIPPY_DISABLE_DOCS_LINKS);
+      20             : declare_const!(CLIPPY_DRIVER_PATH);
+      21             : declare_const!(DOCS_RS);
+      22             : declare_const!(DYLINT_DRIVER_PATH);
+      23             : declare_const!(DYLINT_LIBRARY_PATH);
+      24             : declare_const!(DYLINT_LIBS);
+      25             : declare_const!(DYLINT_LIST);
+      26             : declare_const!(DYLINT_METADATA);
+      27             : declare_const!(DYLINT_NO_DEPS);
+      28             : declare_const!(DYLINT_RUSTFLAGS);
+      29             : declare_const!(DYLINT_TOML);
+      30             : declare_const!(OUT_DIR);
+      31             : declare_const!(PATH);
+      32             : declare_const!(RUSTC);
+      33             : declare_const!(RUSTC_WORKSPACE_WRAPPER);
+      34             : declare_const!(RUSTFLAGS);
+      35             : declare_const!(RUSTUP_HOME);
+      36             : declare_const!(RUSTUP_TOOLCHAIN);
+      37             : declare_const!(RUST_BACKTRACE);
+      38             : declare_const!(TARGET);
+      39             : 
+      40             : /// Returns true if the environment variable `key` is set to a non-zero value.
+      41             : ///
+      42             : /// # Examples
+      43             : ///
+      44             : /// ```
+      45             : /// use dylint_internal::env::enabled;
+      46             : /// use std::env;
+      47             : ///
+      48             : /// env::set_var("FOO", "1");
+      49             : /// assert_eq!(enabled("FOO"), true);
+      50             : ///
+      51             : /// env::set_var("FOO", "0");
+      52             : /// assert_eq!(enabled("FOO"), false);
+      53             : ///
+      54             : /// env::remove_var("FOO");
+      55             : /// assert_eq!(enabled("FOO"), false);
+      56             : /// ```
+      57             : #[must_use]
+      58           0 : pub fn enabled(key: &str) -> bool {
+      59           0 :     std::env::var(key).map_or(false, |value| value != "0")
+      60           0 : }
+      61             : 
+      62             : /// A wrapper around `std::env::var` that converts the error into an `anyhow::Error`.
+      63          87 : pub fn var(key: &str) -> Result<String> {
+      64          87 :     std::env::var(key).map_err(|err| anyhow!(format!("{err}: {key}")))
+      65          87 : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/examples.rs.func-sort-c.html b/coverage/internal/src/examples.rs.func-sort-c.html new file mode 100644 index 000000000..003249065 --- /dev/null +++ b/coverage/internal/src/examples.rs.func-sort-c.html @@ -0,0 +1,100 @@ + + + + + + + LCOV - unnamed - internal/src/examples.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - examples.rs (source / functions)HitTotalCoverage
Test:unnamedLines:495490.7 %
Date:2024-09-27 12:58:08Functions:4757.1 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint_internal::examples::build::{closure#0}0
dylint_internal::examples::iter::{closure#1}::{closure#0}0
dylint_internal::examples::iter::{closure#1}::{closure#1}0
dylint_internal::examples::build2
dylint_internal::examples::iter2
dylint_internal::examples::iter::{closure#1}122
dylint_internal::examples::iter::{closure#0}432
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/examples.rs.func.html b/coverage/internal/src/examples.rs.func.html new file mode 100644 index 000000000..39ee5304b --- /dev/null +++ b/coverage/internal/src/examples.rs.func.html @@ -0,0 +1,100 @@ + + + + + + + LCOV - unnamed - internal/src/examples.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - examples.rs (source / functions)HitTotalCoverage
Test:unnamedLines:495490.7 %
Date:2024-09-27 12:58:08Functions:4757.1 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint_internal::examples::build2
dylint_internal::examples::build::{closure#0}0
dylint_internal::examples::iter2
dylint_internal::examples::iter::{closure#0}432
dylint_internal::examples::iter::{closure#1}122
dylint_internal::examples::iter::{closure#1}::{closure#0}0
dylint_internal::examples::iter::{closure#1}::{closure#1}0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/examples.rs.gcov.html b/coverage/internal/src/examples.rs.gcov.html new file mode 100644 index 000000000..a514e28ab --- /dev/null +++ b/coverage/internal/src/examples.rs.gcov.html @@ -0,0 +1,141 @@ + + + + + + + LCOV - unnamed - internal/src/examples.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - examples.rs (source / functions)HitTotalCoverage
Test:unnamedLines:495490.7 %
Date:2024-09-27 12:58:08Functions:4757.1 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : use crate::{rustup::SanitizeEnvironment, CommandExt};
+       2             : use anyhow::{anyhow, Context, Result};
+       3             : use std::path::{Path, PathBuf};
+       4             : use walkdir::WalkDir;
+       5             : 
+       6           2 : pub fn build() -> Result<()> {
+       7           2 :     // smoelius: The examples use `dylint-link` as the linker, so it must be built first.
+       8           2 :     #[cfg_attr(dylint_lib = "general", allow(abs_home_path))]
+       9           2 :     crate::cargo::build("dylint-link")
+      10           2 :         .build()
+      11           2 :         .sanitize_environment()
+      12           2 :         .current_dir(Path::new(env!("CARGO_MANIFEST_DIR")).join("../dylint-link"))
+      13           2 :         .success()?;
+      14             : 
+      15          16 :     for example in iter(true)? {
+      16          16 :         let example = example?;
+      17          16 :         let file_name = example
+      18          16 :             .file_name()
+      19          16 :             .ok_or_else(|| anyhow!("Could not get file name"))?;
+      20          16 :         crate::cargo::build(&format!("example `{}`", file_name.to_string_lossy()))
+      21          16 :             .build()
+      22          16 :             .sanitize_environment()
+      23          16 :             .current_dir(&example)
+      24          16 :             .success()?;
+      25             :     }
+      26             : 
+      27           2 :     Ok(())
+      28           2 : }
+      29             : 
+      30           2 : pub fn iter(workspace: bool) -> Result<impl Iterator<Item = Result<PathBuf>>> {
+      31           2 :     #[cfg_attr(dylint_lib = "general", allow(abs_home_path))]
+      32           2 :     let path_buf = Path::new(env!("CARGO_MANIFEST_DIR")).join("../examples");
+      33           2 :     // smoelius: Use `cargo_util::paths::normalize_path` instead of `canonicalize` so as not to
+      34           2 :     // "taint" the path with a path prefix on Windows.
+      35           2 :     let examples = cargo_util::paths::normalize_path(&path_buf);
+      36           2 :     let iter = WalkDir::new(examples)
+      37           2 :         .into_iter()
+      38         432 :         .filter_entry(|entry| entry.depth() <= 2);
+      39           2 :     Ok(iter
+      40         122 :         .map(move |entry| -> Result<Option<PathBuf>> {
+      41         122 :             let entry = entry?;
+      42         122 :             let path = entry.path();
+      43         122 :             let rust_toolchain_path = path.join("rust-toolchain");
+      44         122 :             let cargo_toml_path = path.join("Cargo.toml");
+      45         122 :             if entry.depth() < 1 || !path.is_dir() {
+      46          36 :                 return Ok(None);
+      47          86 :             }
+      48          86 :             if workspace
+      49          86 :                 && rust_toolchain_path.try_exists().with_context(|| {
+      50           0 :                     format!("Could not determine whether {rust_toolchain_path:?} exists")
+      51          86 :                 })?
+      52             :             {
+      53          16 :                 return Ok(Some(path.to_path_buf()));
+      54          70 :             }
+      55          70 :             if !workspace
+      56           0 :                 && cargo_toml_path.try_exists().with_context(|| {
+      57           0 :                     format!("Could not determine whether {cargo_toml_path:?} exists")
+      58           0 :                 })?
+      59             :             {
+      60           0 :                 return Ok(Some(path.to_path_buf()));
+      61          70 :             }
+      62          70 :             Ok(None)
+      63         122 :         })
+      64           2 :         .filter_map(Result::transpose))
+      65           2 : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/filename.rs.func-sort-c.html b/coverage/internal/src/filename.rs.func-sort-c.html new file mode 100644 index 000000000..c473e36f0 --- /dev/null +++ b/coverage/internal/src/filename.rs.func-sort-c.html @@ -0,0 +1,88 @@ + + + + + + + LCOV - unnamed - internal/src/filename.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - filename.rs (source / functions)HitTotalCoverage
Test:unnamedLines:2222100.0 %
Date:2024-09-27 12:58:08Functions:44100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint_internal::filename::library_filename25
dylint_internal::filename::parse_target_name127
dylint_internal::filename::parse_filename235
dylint_internal::filename::parse_path_filename235
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/filename.rs.func.html b/coverage/internal/src/filename.rs.func.html new file mode 100644 index 000000000..a54d5e905 --- /dev/null +++ b/coverage/internal/src/filename.rs.func.html @@ -0,0 +1,88 @@ + + + + + + + LCOV - unnamed - internal/src/filename.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - filename.rs (source / functions)HitTotalCoverage
Test:unnamedLines:2222100.0 %
Date:2024-09-27 12:58:08Functions:44100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint_internal::filename::library_filename25
dylint_internal::filename::parse_filename235
dylint_internal::filename::parse_path_filename235
dylint_internal::filename::parse_target_name127
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/filename.rs.gcov.html b/coverage/internal/src/filename.rs.gcov.html new file mode 100644 index 000000000..12678474f --- /dev/null +++ b/coverage/internal/src/filename.rs.gcov.html @@ -0,0 +1,171 @@ + + + + + + + LCOV - unnamed - internal/src/filename.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - filename.rs (source / functions)HitTotalCoverage
Test:unnamedLines:2222100.0 %
Date:2024-09-27 12:58:08Functions:44100.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : use std::{env::consts, path::Path};
+       2             : 
+       3             : /// Returns the filename of a Dylint library.
+       4             : ///
+       5             : /// # Examples
+       6             : ///
+       7             : /// ```
+       8             : /// use dylint_internal::library_filename;
+       9             : ///
+      10             : /// #[cfg(target_os = "linux")]
+      11             : /// assert_eq!(
+      12             : ///     library_filename("foo", "stable-x86_64-unknown-linux-gnu"),
+      13             : ///     "libfoo@stable-x86_64-unknown-linux-gnu.so"
+      14             : /// );
+      15             : ///
+      16             : /// #[cfg(target_os = "macos")]
+      17             : /// assert_eq!(
+      18             : ///     library_filename("foo", "stable-x86_64-apple-darwin"),
+      19             : ///     "libfoo@stable-x86_64-apple-darwin.dylib"
+      20             : /// );
+      21             : ///
+      22             : /// #[cfg(target_os = "windows")]
+      23             : /// assert_eq!(
+      24             : ///     library_filename("foo", "stable-x86_64-pc-windows-msvc"),
+      25             : ///     "foo@stable-x86_64-pc-windows-msvc.dll"
+      26             : /// );
+      27             : /// ```
+      28             : // smoelius: Build a standard rlib, and the filename will use snake case. `library_filename`'s
+      29             : // behavior is consistent with that.
+      30             : #[allow(clippy::module_name_repetitions, clippy::uninlined_format_args)]
+      31             : #[must_use]
+      32          25 : pub fn library_filename(lib_name: &str, toolchain: &str) -> String {
+      33          25 :     format!(
+      34          25 :         "{}{}@{}{}",
+      35          25 :         consts::DLL_PREFIX,
+      36          25 :         lib_name.replace('-', "_"),
+      37          25 :         toolchain,
+      38          25 :         consts::DLL_SUFFIX
+      39          25 :     )
+      40          25 : }
+      41             : 
+      42             : /// Parses the filename of a Dylint library path into a tuple of (name, toolchain).
+      43             : ///
+      44             : /// # Examples
+      45             : ///
+      46             : /// ```
+      47             : /// use dylint_internal::parse_path_filename;
+      48             : /// use std::path::Path;
+      49             : ///
+      50             : /// #[cfg(target_os = "linux")]
+      51             : /// assert_eq!(
+      52             : ///     parse_path_filename(Path::new("libfoo@stable-x86_64-unknown-linux-gnu.so")),
+      53             : ///     Some((
+      54             : ///         String::from("foo"),
+      55             : ///         String::from("stable-x86_64-unknown-linux-gnu")
+      56             : ///     ))
+      57             : /// );
+      58             : ///
+      59             : /// #[cfg(target_os = "macos")]
+      60             : /// assert_eq!(
+      61             : ///     parse_path_filename(Path::new("libfoo@stable-x86_64-apple-darwin.dylib")),
+      62             : ///     Some((
+      63             : ///         String::from("foo"),
+      64             : ///         String::from("stable-x86_64-apple-darwin")
+      65             : ///     ))
+      66             : /// );
+      67             : ///
+      68             : /// #[cfg(target_os = "windows")]
+      69             : /// assert_eq!(
+      70             : ///     parse_path_filename(Path::new("foo@stable-x86_64-pc-windows-msvc.dll")),
+      71             : ///     Some((
+      72             : ///         String::from("foo"),
+      73             : ///         String::from("stable-x86_64-pc-windows-msvc")
+      74             : ///     ))
+      75             : /// );
+      76             : /// ```
+      77             : #[allow(clippy::module_name_repetitions)]
+      78             : #[must_use]
+      79         235 : pub fn parse_path_filename(path: &Path) -> Option<(String, String)> {
+      80         235 :     let filename = path.file_name()?;
+      81         235 :     parse_filename(&filename.to_string_lossy())
+      82         235 : }
+      83             : 
+      84             : #[allow(clippy::module_name_repetitions)]
+      85             : #[must_use]
+      86         235 : pub fn parse_filename(filename: &str) -> Option<(String, String)> {
+      87         235 :     let file_stem = filename.strip_suffix(consts::DLL_SUFFIX)?;
+      88         127 :     let target_name = file_stem.strip_prefix(consts::DLL_PREFIX)?;
+      89         127 :     parse_target_name(target_name)
+      90         235 : }
+      91             : 
+      92         127 : fn parse_target_name(target_name: &str) -> Option<(String, String)> {
+      93         127 :     let (lib_name, toolchain) = target_name.split_once('@')?;
+      94          83 :     Some((lib_name.to_owned(), toolchain.to_owned()))
+      95         127 : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/git.rs.func-sort-c.html b/coverage/internal/src/git.rs.func-sort-c.html new file mode 100644 index 000000000..5a6f9d17b --- /dev/null +++ b/coverage/internal/src/git.rs.func-sort-c.html @@ -0,0 +1,108 @@ + + + + + + + LCOV - unnamed - internal/src/git.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - git.rs (source / functions)HitTotalCoverage
Test:unnamedLines:324866.7 %
Date:2024-09-27 12:58:08Functions:3933.3 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint_internal::git::checkout::{closure#0}0
dylint_internal::git::checkout::{closure#1}0
dylint_internal::git::checkout::{closure#2}0
dylint_internal::git::checkout::{closure#3}0
dylint_internal::git::checkout::{closure#4}0
dylint_internal::git::clone_with_git20
dylint_internal::git::checkout9
dylint_internal::git::clone9
dylint_internal::git::clone_with_cli9
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/git.rs.func.html b/coverage/internal/src/git.rs.func.html new file mode 100644 index 000000000..3241e59cd --- /dev/null +++ b/coverage/internal/src/git.rs.func.html @@ -0,0 +1,108 @@ + + + + + + + LCOV - unnamed - internal/src/git.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - git.rs (source / functions)HitTotalCoverage
Test:unnamedLines:324866.7 %
Date:2024-09-27 12:58:08Functions:3933.3 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint_internal::git::checkout9
dylint_internal::git::checkout::{closure#0}0
dylint_internal::git::checkout::{closure#1}0
dylint_internal::git::checkout::{closure#2}0
dylint_internal::git::checkout::{closure#3}0
dylint_internal::git::checkout::{closure#4}0
dylint_internal::git::clone9
dylint_internal::git::clone_with_cli9
dylint_internal::git::clone_with_git20
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/git.rs.gcov.html b/coverage/internal/src/git.rs.gcov.html new file mode 100644 index 000000000..908b33a5a --- /dev/null +++ b/coverage/internal/src/git.rs.gcov.html @@ -0,0 +1,160 @@ + + + + + + + LCOV - unnamed - internal/src/git.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - git.rs (source / functions)HitTotalCoverage
Test:unnamedLines:324866.7 %
Date:2024-09-27 12:58:08Functions:3933.3 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : use crate::CommandExt;
+       2             : use anyhow::{Context, Result};
+       3             : use git2::Repository;
+       4             : use if_chain::if_chain;
+       5             : use std::{
+       6             :     path::Path,
+       7             :     process::{Command, Stdio},
+       8             : };
+       9             : 
+      10             : // smoelius: I think this imitates Cargo's default behavior:
+      11             : // https://doc.rust-lang.org/cargo/reference/config.html#netretry
+      12             : const N_RETRIES: usize = 2;
+      13             : 
+      14             : // smoelius: I think I may have run into https://github.com/libgit2/libgit2/issues/5294 a few times,
+      15             : // but I don't know of a good general-purpose solution. TODO: Investigate whether/how Cargo's
+      16             : // wrappers handle this.
+      17           9 : pub fn clone(url: &str, refname: &str, path: &Path, quiet: bool) -> Result<Repository> {
+      18           9 :     let repository = if Command::new("git")
+      19           9 :         .args(["--version"])
+      20           9 :         .stdout(Stdio::null())
+      21           9 :         .success()
+      22           9 :         .is_ok()
+      23             :     {
+      24           9 :         clone_with_cli(url, path, quiet)
+      25             :     } else {
+      26           0 :         clone_with_git2(url, path, quiet)
+      27           0 :     }?;
+      28             : 
+      29           9 :     checkout(&repository, refname)?;
+      30             : 
+      31           9 :     Ok(repository)
+      32           9 : }
+      33             : 
+      34           9 : fn clone_with_cli(url: &str, path: &Path, quiet: bool) -> Result<Repository> {
+      35           9 :     let mut command = Command::new("git");
+      36           9 :     command.args(["clone", url, &path.to_string_lossy()]);
+      37           9 :     if quiet {
+      38           0 :         command.args(["--quiet"]);
+      39           9 :     }
+      40           9 :     command.success()?;
+      41             : 
+      42           9 :     Repository::open(path).map_err(Into::into)
+      43           9 : }
+      44             : 
+      45           0 : fn clone_with_git2(url: &str, path: &Path, _quiet: bool) -> Result<Repository> {
+      46           0 :     let mut result = Repository::clone(url, path);
+      47             : 
+      48           0 :     for _ in 0..N_RETRIES {
+      49           0 :         if result.is_err() {
+      50           0 :             result = Repository::clone(url, path);
+      51           0 :         } else {
+      52           0 :             break;
+      53             :         }
+      54             :     }
+      55             : 
+      56           0 :     result.map_err(Into::into)
+      57           0 : }
+      58             : 
+      59             : // smoelius: `checkout` is based on: https://stackoverflow.com/a/67240436
+      60           9 : pub fn checkout(repository: &Repository, refname: &str) -> Result<()> {
+      61           9 :     let (object, reference) = repository
+      62           9 :         .revparse_ext(refname)
+      63           9 :         .with_context(|| format!("`revparse_ext` failed for `{refname}`"))?;
+      64             : 
+      65           9 :     repository
+      66           9 :         .checkout_tree(&object, None)
+      67           9 :         .with_context(|| format!("`checkout_tree` failed for `{object:?}`"))?;
+      68             : 
+      69           0 :     if_chain! {
+      70           9 :         if let Some(reference) = reference;
+      71           9 :         if let Some(refname) = reference.name();
+      72             :         then {
+      73           9 :             repository
+      74           9 :                 .set_head(refname)
+      75           9 :                 .with_context(|| format!("`set_head` failed for `{refname}`"))?;
+      76             :         } else {
+      77           0 :             repository
+      78           0 :                 .set_head_detached(object.id())
+      79           0 :                 .with_context(|| format!("`set_head_detached` failed for `{}`", object.id()))?;
+      80             :         }
+      81             :     }
+      82             : 
+      83           9 :     Ok(())
+      84           9 : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/index-sort-f.html b/coverage/internal/src/index-sort-f.html new file mode 100644 index 000000000..3a896f5bd --- /dev/null +++ b/coverage/internal/src/index-sort-f.html @@ -0,0 +1,203 @@ + + + + + + + LCOV - unnamed - internal/src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/srcHitTotalCoverage
Test:unnamedLines:50359884.1 %
Date:2024-09-27 12:58:08Functions:7913857.2 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
config.rs +
66.0%66.0%
+
66.0 %35 / 5327.3 %3 / 11
sed.rs +
100.0%
+
100.0 %10 / 1033.3 %2 / 6
git.rs +
66.7%66.7%
+
66.7 %32 / 4833.3 %3 / 9
command.rs +
62.3%62.3%
+
62.3 %33 / 5342.9 %3 / 7
env.rs +
50.0%50.0%
+
50.0 %3 / 650.0 %2 / 4
clippy_utils.rs +
74.7%74.7%
+
74.7 %68 / 9156.5 %13 / 23
packaging.rs +
99.0%99.0%
+
99.0 %97 / 9856.7 %17 / 30
examples.rs +
90.7%90.7%
+
90.7 %49 / 5457.1 %4 / 7
rustup.rs +
100.0%
+
100.0 %38 / 3870.0 %7 / 10
cargo.rs +
92.3%92.3%
+
92.3 %108 / 11775.0 %18 / 24
testing.rs +
100.0%
+
100.0 %8 / 8100.0 %3 / 3
filename.rs +
100.0%
+
100.0 %22 / 22100.0 %4 / 4
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/index-sort-l.html b/coverage/internal/src/index-sort-l.html new file mode 100644 index 000000000..f2078c8f8 --- /dev/null +++ b/coverage/internal/src/index-sort-l.html @@ -0,0 +1,203 @@ + + + + + + + LCOV - unnamed - internal/src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/srcHitTotalCoverage
Test:unnamedLines:50359884.1 %
Date:2024-09-27 12:58:08Functions:7913857.2 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
env.rs +
50.0%50.0%
+
50.0 %3 / 650.0 %2 / 4
command.rs +
62.3%62.3%
+
62.3 %33 / 5342.9 %3 / 7
config.rs +
66.0%66.0%
+
66.0 %35 / 5327.3 %3 / 11
git.rs +
66.7%66.7%
+
66.7 %32 / 4833.3 %3 / 9
clippy_utils.rs +
74.7%74.7%
+
74.7 %68 / 9156.5 %13 / 23
examples.rs +
90.7%90.7%
+
90.7 %49 / 5457.1 %4 / 7
cargo.rs +
92.3%92.3%
+
92.3 %108 / 11775.0 %18 / 24
packaging.rs +
99.0%99.0%
+
99.0 %97 / 9856.7 %17 / 30
testing.rs +
100.0%
+
100.0 %8 / 8100.0 %3 / 3
sed.rs +
100.0%
+
100.0 %10 / 1033.3 %2 / 6
filename.rs +
100.0%
+
100.0 %22 / 22100.0 %4 / 4
rustup.rs +
100.0%
+
100.0 %38 / 3870.0 %7 / 10
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/index.html b/coverage/internal/src/index.html new file mode 100644 index 000000000..8d742fe5f --- /dev/null +++ b/coverage/internal/src/index.html @@ -0,0 +1,203 @@ + + + + + + + LCOV - unnamed - internal/src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/srcHitTotalCoverage
Test:unnamedLines:50359884.1 %
Date:2024-09-27 12:58:08Functions:7913857.2 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
cargo.rs +
92.3%92.3%
+
92.3 %108 / 11775.0 %18 / 24
clippy_utils.rs +
74.7%74.7%
+
74.7 %68 / 9156.5 %13 / 23
command.rs +
62.3%62.3%
+
62.3 %33 / 5342.9 %3 / 7
config.rs +
66.0%66.0%
+
66.0 %35 / 5327.3 %3 / 11
env.rs +
50.0%50.0%
+
50.0 %3 / 650.0 %2 / 4
examples.rs +
90.7%90.7%
+
90.7 %49 / 5457.1 %4 / 7
filename.rs +
100.0%
+
100.0 %22 / 22100.0 %4 / 4
git.rs +
66.7%66.7%
+
66.7 %32 / 4833.3 %3 / 9
packaging.rs +
99.0%99.0%
+
99.0 %97 / 9856.7 %17 / 30
rustup.rs +
100.0%
+
100.0 %38 / 3870.0 %7 / 10
sed.rs +
100.0%
+
100.0 %10 / 1033.3 %2 / 6
testing.rs +
100.0%
+
100.0 %8 / 8100.0 %3 / 3
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/packaging.rs.func-sort-c.html b/coverage/internal/src/packaging.rs.func-sort-c.html new file mode 100644 index 000000000..7da2a3a72 --- /dev/null +++ b/coverage/internal/src/packaging.rs.func-sort-c.html @@ -0,0 +1,192 @@ + + + + + + + LCOV - unnamed - internal/src/packaging.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - packaging.rs (source / functions)HitTotalCoverage
Test:unnamedLines:979899.0 %
Date:2024-09-27 12:58:08Functions:173056.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<dylint_internal::packaging::Template as rust_embed::RustEmbed>::get0
<dylint_internal::packaging::Template as rust_embed::RustEmbed>::iter0
dylint_internal::packaging::isolate::{closure#0}0
dylint_internal::packaging::isolate::{closure#2}0
dylint_internal::packaging::new_template::{closure#0}0
dylint_internal::packaging::new_template::{closure#1}0
dylint_internal::packaging::new_template::{closure#2}0
dylint_internal::packaging::new_template::{closure#3}0
dylint_internal::packaging::new_template::{closure#4}0
dylint_internal::packaging::use_local_packages::{closure#0}0
dylint_internal::packaging::use_local_packages::{closure#3}0
dylint_internal::packaging::use_local_packages::{closure#5}0
dylint_internal::packaging::use_local_packages::{closure#6}0
dylint_internal::packaging::test::template_has_initial_version1
dylint_internal::packaging::test::template_has_initial_version::{closure#0}1
dylint_internal::packaging::test::template_includes_only_whitelisted_paths1
<dylint_internal::packaging::Template>::matcher::{closure#0}5
dylint_internal::packaging::test::template_includes_only_whitelisted_paths::{closure#0}8
dylint_internal::packaging::new_template9
dylint_internal::packaging::use_local_packages9
dylint_internal::packaging::use_local_packages::{closure#1}9
dylint_internal::packaging::use_local_packages::{closure#2}9
<dylint_internal::packaging::Template>::iter10
dylint_internal::packaging::isolate13
dylint_internal::packaging::isolate::{closure#1}13
<dylint_internal::packaging::Template>::get72
<dylint_internal::packaging::Template>::iter::{closure#0}80
<dylint_internal::packaging::Template>::matcher82
dylint_internal::packaging::use_local_packages::{closure#4}153
dylint_internal::packaging::use_local_packages::{closure#4}::{closure#0}153
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/packaging.rs.func.html b/coverage/internal/src/packaging.rs.func.html new file mode 100644 index 000000000..7adf36bbf --- /dev/null +++ b/coverage/internal/src/packaging.rs.func.html @@ -0,0 +1,192 @@ + + + + + + + LCOV - unnamed - internal/src/packaging.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - packaging.rs (source / functions)HitTotalCoverage
Test:unnamedLines:979899.0 %
Date:2024-09-27 12:58:08Functions:173056.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<dylint_internal::packaging::Template as rust_embed::RustEmbed>::get0
<dylint_internal::packaging::Template as rust_embed::RustEmbed>::iter0
<dylint_internal::packaging::Template>::get72
<dylint_internal::packaging::Template>::iter10
<dylint_internal::packaging::Template>::iter::{closure#0}80
<dylint_internal::packaging::Template>::matcher82
<dylint_internal::packaging::Template>::matcher::{closure#0}5
dylint_internal::packaging::isolate13
dylint_internal::packaging::isolate::{closure#0}0
dylint_internal::packaging::isolate::{closure#1}13
dylint_internal::packaging::isolate::{closure#2}0
dylint_internal::packaging::new_template9
dylint_internal::packaging::new_template::{closure#0}0
dylint_internal::packaging::new_template::{closure#1}0
dylint_internal::packaging::new_template::{closure#2}0
dylint_internal::packaging::new_template::{closure#3}0
dylint_internal::packaging::new_template::{closure#4}0
dylint_internal::packaging::test::template_has_initial_version1
dylint_internal::packaging::test::template_has_initial_version::{closure#0}1
dylint_internal::packaging::test::template_includes_only_whitelisted_paths1
dylint_internal::packaging::test::template_includes_only_whitelisted_paths::{closure#0}8
dylint_internal::packaging::use_local_packages9
dylint_internal::packaging::use_local_packages::{closure#0}0
dylint_internal::packaging::use_local_packages::{closure#1}9
dylint_internal::packaging::use_local_packages::{closure#2}9
dylint_internal::packaging::use_local_packages::{closure#3}0
dylint_internal::packaging::use_local_packages::{closure#4}153
dylint_internal::packaging::use_local_packages::{closure#4}::{closure#0}153
dylint_internal::packaging::use_local_packages::{closure#5}0
dylint_internal::packaging::use_local_packages::{closure#6}0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/packaging.rs.gcov.html b/coverage/internal/src/packaging.rs.gcov.html new file mode 100644 index 000000000..85d5745e5 --- /dev/null +++ b/coverage/internal/src/packaging.rs.gcov.html @@ -0,0 +1,244 @@ + + + + + + + LCOV - unnamed - internal/src/packaging.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - packaging.rs (source / functions)HitTotalCoverage
Test:unnamedLines:979899.0 %
Date:2024-09-27 12:58:08Functions:173056.7 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : // smoelius: Since the update to `rust_embed` 8.3.0, `unnecessary_conversion_for_trait` started
+       2             : // firing on `struct Template`. Requiring `!expr.span.from_expansion()` in
+       3             : // `unnecessary_conversion_for_trait` causes one of its tests to fail. So allow the lint for now.
+       4             : // smoelius: `abs_home_path` now fires as well.
+       5             : #![cfg_attr(dylint_lib = "general", allow(abs_home_path))]
+       6             : #![cfg_attr(dylint_lib = "overscoped_allow", allow(overscoped_allow))]
+       7             : #![cfg_attr(dylint_lib = "supplementary", allow(unnecessary_conversion_for_trait))]
+       8             : 
+       9             : use crate::cargo::{current_metadata, package};
+      10             : use anyhow::{anyhow, Context, Result};
+      11             : use rust_embed::RustEmbed;
+      12             : use std::{
+      13             :     fs::{create_dir_all, OpenOptions},
+      14             :     io::Write,
+      15             :     path::Path,
+      16             : };
+      17             : 
+      18         164 : #[derive(RustEmbed)]
+      19             : #[folder = "template"]
+      20             : #[exclude = "Cargo.lock"]
+      21             : #[exclude = "target/*"]
+      22             : struct Template;
+      23             : 
+      24           9 : pub fn new_template(to: &Path) -> Result<()> {
+      25          81 :     for path in Template::iter() {
+      26          72 :         let embedded_file = Template::get(&path)
+      27          72 :             .ok_or_else(|| anyhow!("Could not get embedded file `{}`", path))?;
+      28          72 :         let to_path = to.join(path.trim_end_matches('~'));
+      29          72 :         let parent = to_path
+      30          72 :             .parent()
+      31          72 :             .ok_or_else(|| anyhow!("Could not get parent directory"))?;
+      32          72 :         create_dir_all(parent).with_context(|| {
+      33           0 :             format!("`create_dir_all` failed for `{}`", parent.to_string_lossy())
+      34          72 :         })?;
+      35          72 :         let mut file = OpenOptions::new()
+      36          72 :             .create(true)
+      37          72 :             .truncate(true)
+      38          72 :             .write(true)
+      39          72 :             .open(&to_path)
+      40          72 :             .with_context(|| format!("Could not open `{}`", to_path.to_string_lossy()))?;
+      41          72 :         file.write_all(&embedded_file.data)
+      42          72 :             .with_context(|| format!("Could not write to {to_path:?}"))?;
+      43             :     }
+      44             : 
+      45           9 :     Ok(())
+      46           9 : }
+      47             : 
+      48             : // smoelius: If a package is checked out in the current directory, this must be dealt with:
+      49             : // error: current package believes it's in a workspace when it's not
+      50          13 : pub fn isolate(path: &Path) -> Result<()> {
+      51          13 :     let manifest = path.join("Cargo.toml");
+      52          13 :     let mut file = OpenOptions::new()
+      53          13 :         .append(true)
+      54          13 :         .open(&manifest)
+      55          13 :         .with_context(|| format!("Could not open `{}`", manifest.to_string_lossy()))?;
+      56             : 
+      57          13 :     writeln!(file)
+      58          13 :         .and_then(|()| writeln!(file, "[workspace]"))
+      59          13 :         .with_context(|| format!("Could not write to `{}`", manifest.to_string_lossy()))?;
+      60             : 
+      61          13 :     Ok(())
+      62          13 : }
+      63             : 
+      64             : // smoelius: If you clone, say, `dylint-template` and run `cargo test` on it, it will obtain Dylint
+      65             : // packages from `crates.io`. But for the tests in this repository, you often want it to use the
+      66             : // packages in this repository. The function `use_local_packages` patches a workspace's `Cargo.toml`
+      67             : // file to do so.
+      68           9 : pub fn use_local_packages(path: &Path) -> Result<()> {
+      69           9 :     let metadata = current_metadata()?;
+      70             : 
+      71           9 :     let manifest = path.join("Cargo.toml");
+      72             : 
+      73           9 :     let mut file = OpenOptions::new()
+      74           9 :         .append(true)
+      75           9 :         .open(&manifest)
+      76           9 :         .with_context(|| format!("Could not open `{}`", manifest.to_string_lossy()))?;
+      77             : 
+      78             :     // smoelius: `use_local_packages` broke when `dylint_linting` was removed from the workspace.
+      79             :     // For now, add `dylint_linting` manually.
+      80           9 :     writeln!(file)
+      81           9 :         .and_then(|()| writeln!(file, "[patch.crates-io]"))
+      82           9 :         .and_then(|()| {
+      83           9 :             writeln!(
+      84           9 :                 file,
+      85           9 :                 r#"dylint_linting = {{ path = "{}" }}"#,
+      86           9 :                 metadata
+      87           9 :                     .workspace_root
+      88           9 :                     .join("utils/linting")
+      89           9 :                     .to_string()
+      90           9 :                     .replace('\\', "\\\\")
+      91           9 :             )
+      92           9 :         })
+      93           9 :         .with_context(|| format!("Could not write to `{}`", manifest.to_string_lossy()))?;
+      94             : 
+      95          72 :     for package_id in &metadata.workspace_members {
+      96          63 :         let package = package(&metadata, package_id)?;
+      97          63 :         if package.publish == Some(vec![])
+      98          45 :             || package
+      99          45 :                 .targets
+     100          45 :                 .iter()
+     101         153 :                 .all(|target| target.kind.iter().all(|kind| kind != "lib"))
+     102             :         {
+     103          36 :             continue;
+     104          27 :         }
+     105          27 :         let path = package
+     106          27 :             .manifest_path
+     107          27 :             .parent()
+     108          27 :             .ok_or_else(|| anyhow!("Could not get parent directory"))?;
+     109          27 :         writeln!(
+     110          27 :             file,
+     111          27 :             r#"{} = {{ path = "{}" }}"#,
+     112          27 :             package.name,
+     113          27 :             path.to_string().replace('\\', "\\\\")
+     114          27 :         )
+     115          27 :         .with_context(|| format!("Could not write to `{}`", manifest.to_string_lossy()))?;
+     116             :     }
+     117             : 
+     118           9 :     Ok(())
+     119           9 : }
+     120             : 
+     121             : #[cfg(test)]
+     122             : mod test {
+     123             :     use super::*;
+     124             :     use std::fs::read_to_string;
+     125             :     use toml_edit::{DocumentMut, Item};
+     126             : 
+     127             :     #[cfg_attr(
+     128             :         dylint_lib = "assert_eq_arg_misordering",
+     129             :         allow(assert_eq_arg_misordering)
+     130             :     )]
+     131             :     #[test]
+     132           1 :     fn template_includes_only_whitelisted_paths() {
+     133             :         const PATHS: [&str; 8] = [
+     134             :             ".cargo/config.toml",
+     135             :             ".gitignore",
+     136             :             "Cargo.toml~",
+     137             :             "README.md",
+     138             :             "rust-toolchain",
+     139             :             "src/lib.rs",
+     140             :             "ui/main.rs",
+     141             :             "ui/main.stderr",
+     142             :         ];
+     143             : 
+     144           1 :         let mut paths_sorted = PATHS.to_vec();
+     145           1 :         paths_sorted.sort_unstable();
+     146           1 :         assert_eq!(paths_sorted, PATHS);
+     147             : 
+     148           1 :         let paths = Template::iter()
+     149           8 :             .filter(|path| PATHS.binary_search(&&**path).is_err())
+     150           1 :             .collect::<Vec<_>>();
+     151           1 : 
+     152           1 :         assert!(paths.is_empty(), "found {paths:#?}");
+     153           1 :     }
+     154             : 
+     155             :     #[test]
+     156           1 :     fn template_has_initial_version() {
+     157           1 :         let contents = read_to_string("template/Cargo.toml~").unwrap();
+     158           1 :         let document = contents.parse::<DocumentMut>().unwrap();
+     159           1 :         let version = document
+     160           1 :             .as_table()
+     161           1 :             .get("package")
+     162           1 :             .and_then(Item::as_table)
+     163           1 :             .and_then(|table| table.get("version"))
+     164           1 :             .and_then(Item::as_str)
+     165           1 :             .unwrap();
+     166           1 :         assert_eq!("0.1.0", version);
+     167           1 :     }
+     168             : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/rustup.rs.func-sort-c.html b/coverage/internal/src/rustup.rs.func-sort-c.html new file mode 100644 index 000000000..133437311 --- /dev/null +++ b/coverage/internal/src/rustup.rs.func-sort-c.html @@ -0,0 +1,112 @@ + + + + + + + LCOV - unnamed - internal/src/rustup.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - rustup.rs (source / functions)HitTotalCoverage
Test:unnamedLines:3838100.0 %
Date:2024-09-27 12:58:08Functions:71070.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint_internal::rustup::active_toolchain::{closure#1}0
dylint_internal::rustup::is_rustc::<_>0
dylint_internal::rustup::toolchain_path::{closure#0}0
dylint_internal::rustup::is_rustc::<str>1
dylint_internal::rustup::rustc_is_rustc1
dylint_internal::rustup::is_rustc::<&&str>6
dylint_internal::rustup::toolchain_path7
dylint_internal::rustup::active_toolchain30
dylint_internal::rustup::active_toolchain::{closure#0}30
<std::process::Command as dylint_internal::rustup::SanitizeEnvironment>::sanitize_environment116
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/rustup.rs.func.html b/coverage/internal/src/rustup.rs.func.html new file mode 100644 index 000000000..9b199f139 --- /dev/null +++ b/coverage/internal/src/rustup.rs.func.html @@ -0,0 +1,112 @@ + + + + + + + LCOV - unnamed - internal/src/rustup.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - rustup.rs (source / functions)HitTotalCoverage
Test:unnamedLines:3838100.0 %
Date:2024-09-27 12:58:08Functions:71070.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<std::process::Command as dylint_internal::rustup::SanitizeEnvironment>::sanitize_environment116
dylint_internal::rustup::active_toolchain30
dylint_internal::rustup::active_toolchain::{closure#0}30
dylint_internal::rustup::active_toolchain::{closure#1}0
dylint_internal::rustup::is_rustc::<&&str>6
dylint_internal::rustup::is_rustc::<_>0
dylint_internal::rustup::is_rustc::<str>1
dylint_internal::rustup::rustc_is_rustc1
dylint_internal::rustup::toolchain_path7
dylint_internal::rustup::toolchain_path::{closure#0}0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/rustup.rs.gcov.html b/coverage/internal/src/rustup.rs.gcov.html new file mode 100644 index 000000000..79869cd3f --- /dev/null +++ b/coverage/internal/src/rustup.rs.gcov.html @@ -0,0 +1,136 @@ + + + + + + + LCOV - unnamed - internal/src/rustup.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - rustup.rs (source / functions)HitTotalCoverage
Test:unnamedLines:3838100.0 %
Date:2024-09-27 12:58:08Functions:71070.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : use crate::{env, CommandExt};
+       2             : use anyhow::{anyhow, Result};
+       3             : use std::{
+       4             :     ffi::OsStr,
+       5             :     path::{Path, PathBuf},
+       6             :     process::Command,
+       7             : };
+       8             : 
+       9             : // smoelius: Should this be merged into `CommandExt`?
+      10             : pub trait SanitizeEnvironment {
+      11             :     fn sanitize_environment(&mut self) -> &mut Self;
+      12             : }
+      13             : 
+      14             : impl SanitizeEnvironment for Command {
+      15         116 :     fn sanitize_environment(&mut self) -> &mut Self {
+      16         116 :         self.env_remove(env::CARGO);
+      17         116 :         self.env_remove(env::RUSTC);
+      18         116 :         self.env_remove(env::RUSTUP_TOOLCHAIN);
+      19         116 :         self
+      20         116 :     }
+      21             : }
+      22             : 
+      23             : // smoelius: Consider carefully whether you need to call this function! In most cases, the toolchain
+      24             : // you want is not the one returned by rustup.
+      25          30 : pub fn active_toolchain(path: &Path) -> Result<String> {
+      26          30 :     let output = Command::new("rustup")
+      27          30 :         .sanitize_environment()
+      28          30 :         .current_dir(path)
+      29          30 :         .args(["show", "active-toolchain"])
+      30          30 :         .logged_output(true)?;
+      31          30 :     let stdout = std::str::from_utf8(&output.stdout)?;
+      32          30 :     stdout
+      33          30 :         .split_once(' ')
+      34          30 :         .map(|(s, _)| s.to_owned())
+      35          30 :         .ok_or_else(|| anyhow!("Could not determine active toolchain"))
+      36          30 : }
+      37             : 
+      38           7 : pub fn toolchain_path(path: &Path) -> Result<PathBuf> {
+      39           7 :     let output = Command::new("rustup")
+      40           7 :         .sanitize_environment()
+      41           7 :         .current_dir(path)
+      42           7 :         .args(["which", "rustc"])
+      43           7 :         .logged_output(true)?;
+      44           7 :     let stdout = std::str::from_utf8(&output.stdout)?;
+      45           7 :     let path = PathBuf::from(stdout);
+      46           7 :     // smoelius: `path` should end with `/bin/rustc`.
+      47           7 :     path.ancestors()
+      48           7 :         .nth(2)
+      49           7 :         .map(Into::into)
+      50           7 :         .ok_or_else(|| anyhow!("Could not get ancestor"))
+      51           7 : }
+      52             : 
+      53           7 : pub fn is_rustc<T: AsRef<OsStr> + ?Sized>(arg: &T) -> bool {
+      54           7 :     Path::new(arg).file_stem() == Some(OsStr::new("rustc"))
+      55           7 : }
+      56             : 
+      57             : #[test]
+      58           1 : fn rustc_is_rustc() {
+      59           1 :     assert!(is_rustc("rustc"));
+      60           1 : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/sed.rs.func-sort-c.html b/coverage/internal/src/sed.rs.func-sort-c.html new file mode 100644 index 000000000..f660d74dc --- /dev/null +++ b/coverage/internal/src/sed.rs.func-sort-c.html @@ -0,0 +1,96 @@ + + + + + + + LCOV - unnamed - internal/src/sed.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - sed.rs (source / functions)HitTotalCoverage
Test:unnamedLines:1010100.0 %
Date:2024-09-27 12:58:08Functions:2633.3 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint_internal::sed::find_and_replace::<&alloc::string::String>::{closure#0}0
dylint_internal::sed::find_and_replace::<&str>::{closure#0}0
dylint_internal::sed::find_and_replace::<_>0
dylint_internal::sed::find_and_replace::<_>::{closure#0}0
dylint_internal::sed::find_and_replace::<&str>1
dylint_internal::sed::find_and_replace::<&alloc::string::String>32
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/sed.rs.func.html b/coverage/internal/src/sed.rs.func.html new file mode 100644 index 000000000..05ab8cc88 --- /dev/null +++ b/coverage/internal/src/sed.rs.func.html @@ -0,0 +1,96 @@ + + + + + + + LCOV - unnamed - internal/src/sed.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - sed.rs (source / functions)HitTotalCoverage
Test:unnamedLines:1010100.0 %
Date:2024-09-27 12:58:08Functions:2633.3 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint_internal::sed::find_and_replace::<&alloc::string::String>32
dylint_internal::sed::find_and_replace::<&alloc::string::String>::{closure#0}0
dylint_internal::sed::find_and_replace::<&str>1
dylint_internal::sed::find_and_replace::<&str>::{closure#0}0
dylint_internal::sed::find_and_replace::<_>0
dylint_internal::sed::find_and_replace::<_>::{closure#0}0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/sed.rs.gcov.html b/coverage/internal/src/sed.rs.gcov.html new file mode 100644 index 000000000..836efbe89 --- /dev/null +++ b/coverage/internal/src/sed.rs.gcov.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - unnamed - internal/src/sed.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - sed.rs (source / functions)HitTotalCoverage
Test:unnamedLines:1010100.0 %
Date:2024-09-27 12:58:08Functions:2633.3 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : use anyhow::{Context, Result};
+       2             : use regex::Regex;
+       3             : use std::{
+       4             :     fs::{read_to_string, write},
+       5             :     path::Path,
+       6             : };
+       7             : 
+       8          33 : pub fn find_and_replace<R>(path: &Path, re: &str, replacement: R) -> Result<()>
+       9          33 : where
+      10          33 :     R: AsRef<str>,
+      11          33 : {
+      12          33 :     let before = read_to_string(path)
+      13          33 :         .with_context(|| format!("`read_to_string` failed for `{}`", path.to_string_lossy()))?;
+      14          33 :     let re = Regex::new(re)?;
+      15          33 :     let after = re.replace_all(&before, replacement.as_ref());
+      16          33 :     write(path, after.as_bytes()).map_err(Into::into)
+      17          33 : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/testing.rs.func-sort-c.html b/coverage/internal/src/testing.rs.func-sort-c.html new file mode 100644 index 000000000..347671983 --- /dev/null +++ b/coverage/internal/src/testing.rs.func-sort-c.html @@ -0,0 +1,84 @@ + + + + + + + LCOV - unnamed - internal/src/testing.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - testing.rs (source / functions)HitTotalCoverage
Test:unnamedLines:88100.0 %
Date:2024-09-27 12:58:08Functions:33100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint_internal::testing::new_template8
dylint_internal::testing::init55
dylint_internal::testing::init___rust_ctor___ctor::init___rust_ctor___ctor55
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/testing.rs.func.html b/coverage/internal/src/testing.rs.func.html new file mode 100644 index 000000000..e1edae0ea --- /dev/null +++ b/coverage/internal/src/testing.rs.func.html @@ -0,0 +1,84 @@ + + + + + + + LCOV - unnamed - internal/src/testing.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - testing.rs (source / functions)HitTotalCoverage
Test:unnamedLines:88100.0 %
Date:2024-09-27 12:58:08Functions:33100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
dylint_internal::testing::init55
dylint_internal::testing::init___rust_ctor___ctor::init___rust_ctor___ctor55
dylint_internal::testing::new_template8
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/internal/src/testing.rs.gcov.html b/coverage/internal/src/testing.rs.gcov.html new file mode 100644 index 000000000..7009ab27a --- /dev/null +++ b/coverage/internal/src/testing.rs.gcov.html @@ -0,0 +1,89 @@ + + + + + + + LCOV - unnamed - internal/src/testing.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - internal/src - testing.rs (source / functions)HitTotalCoverage
Test:unnamedLines:88100.0 %
Date:2024-09-27 12:58:08Functions:33100.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : use anyhow::Result;
+       2             : use std::path::Path;
+       3             : 
+       4          55 : #[ctor::ctor]
+       5          55 : fn init() {
+       6          55 :     env_logger::init();
+       7             : }
+       8             : 
+       9           8 : pub fn new_template(path: &Path) -> Result<()> {
+      10           8 :     crate::packaging::new_template(path)?;
+      11           8 :     crate::packaging::use_local_packages(path)?;
+      12           8 :     Ok(())
+      13           8 : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/ruby.png b/coverage/ruby.png new file mode 100644 index 0000000000000000000000000000000000000000..991b6d4ec9e78be165e3ef757eed1aada287364d GIT binary patch literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)ga>?NMQuI!iC1^FceV#7`HfI^%F z9+AZi4BSE>%y{W;-5;PJOS+@4BLl<6e(pbstUx|nfKQ0)e^Y%R^MdiLxj>4`)5S5Q b;#P73kj=!v_*DHKNFRfztDnm{r-UW|iOwIS literal 0 HcmV?d00001 diff --git a/coverage/snow.png b/coverage/snow.png new file mode 100644 index 0000000000000000000000000000000000000000..2cdae107fceec6e7f02ac7acb4a34a82a540caa5 GIT binary patch literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)ga>?NMQuI!iC1^MM!lvI6;R0X`wF|Ns97GD8ntt^-nBo-U3d c6}OTTfNUlP#;5A{K>8RwUHx3vIVCg!071?oo&W#< literal 0 HcmV?d00001 diff --git a/coverage/updown.png b/coverage/updown.png new file mode 100644 index 0000000000000000000000000000000000000000..aa56a238b3e6c435265250f9266cd1b8caba0f20 GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^AT}Qd8;}%R+`Ae`*?77*hG?8mPH5^{)z4*}Q$iB}huR`+ literal 0 HcmV?d00001 diff --git a/coverage/utils/linting/src/index-sort-f.html b/coverage/utils/linting/src/index-sort-f.html new file mode 100644 index 000000000..0be2b673f --- /dev/null +++ b/coverage/utils/linting/src/index-sort-f.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - unnamed - utils/linting/src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - utils/linting/srcHitTotalCoverage
Test:unnamedLines:0920.0 %
Date:2024-09-27 12:58:08Functions:0130.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
lib.rs +
0.0%
+
0.0 %0 / 920.0 %0 / 13
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/utils/linting/src/index-sort-l.html b/coverage/utils/linting/src/index-sort-l.html new file mode 100644 index 000000000..a88e33aac --- /dev/null +++ b/coverage/utils/linting/src/index-sort-l.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - unnamed - utils/linting/src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - utils/linting/srcHitTotalCoverage
Test:unnamedLines:0920.0 %
Date:2024-09-27 12:58:08Functions:0130.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
lib.rs +
0.0%
+
0.0 %0 / 920.0 %0 / 13
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/utils/linting/src/index.html b/coverage/utils/linting/src/index.html new file mode 100644 index 000000000..897e44897 --- /dev/null +++ b/coverage/utils/linting/src/index.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - unnamed - utils/linting/src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - utils/linting/srcHitTotalCoverage
Test:unnamedLines:0920.0 %
Date:2024-09-27 12:58:08Functions:0130.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
lib.rs +
0.0%
+
0.0 %0 / 920.0 %0 / 13
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/utils/linting/src/lib.rs.func-sort-c.html b/coverage/utils/linting/src/lib.rs.func-sort-c.html new file mode 100644 index 000000000..1a9310115 --- /dev/null +++ b/coverage/utils/linting/src/lib.rs.func-sort-c.html @@ -0,0 +1,124 @@ + + + + + + + LCOV - unnamed - utils/linting/src/lib.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - utils/linting/src - lib.rs (source / functions)HitTotalCoverage
Test:unnamedLines:0920.0 %
Date:2024-09-27 12:58:08Functions:0130.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<rustc_session::session::Session as dylint_linting::ParseSess>::parse_sess0
dylint_linting::config::<_>0
dylint_linting::config_or_default::<_>0
dylint_linting::config_or_default::<_>::{closure#0}0
dylint_linting::config_toml0
dylint_linting::early_error::<_>0
dylint_linting::init_config0
dylint_linting::init_config::{closure#0}0
dylint_linting::local_crate_source_file0
dylint_linting::try_init_config0
dylint_linting::try_init_config_guarded0
dylint_linting::try_init_config_guarded::{closure#0}0
dylint_linting::try_init_config_guarded::{closure#1}0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/utils/linting/src/lib.rs.func.html b/coverage/utils/linting/src/lib.rs.func.html new file mode 100644 index 000000000..64da69415 --- /dev/null +++ b/coverage/utils/linting/src/lib.rs.func.html @@ -0,0 +1,124 @@ + + + + + + + LCOV - unnamed - utils/linting/src/lib.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - utils/linting/src - lib.rs (source / functions)HitTotalCoverage
Test:unnamedLines:0920.0 %
Date:2024-09-27 12:58:08Functions:0130.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<rustc_session::session::Session as dylint_linting::ParseSess>::parse_sess0
dylint_linting::config::<_>0
dylint_linting::config_or_default::<_>0
dylint_linting::config_or_default::<_>::{closure#0}0
dylint_linting::config_toml0
dylint_linting::early_error::<_>0
dylint_linting::init_config0
dylint_linting::init_config::{closure#0}0
dylint_linting::local_crate_source_file0
dylint_linting::try_init_config0
dylint_linting::try_init_config_guarded0
dylint_linting::try_init_config_guarded::{closure#0}0
dylint_linting::try_init_config_guarded::{closure#1}0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/utils/linting/src/lib.rs.gcov.html b/coverage/utils/linting/src/lib.rs.gcov.html new file mode 100644 index 000000000..0d4d1f95c --- /dev/null +++ b/coverage/utils/linting/src/lib.rs.gcov.html @@ -0,0 +1,742 @@ + + + + + + + LCOV - unnamed - utils/linting/src/lib.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - utils/linting/src - lib.rs (source / functions)HitTotalCoverage
Test:unnamedLines:0920.0 %
Date:2024-09-27 12:58:08Functions:0130.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : //! This crate provides macros for creating [Dylint] libraries, and utilities for creating
+       2             : //! configurable libraries.
+       3             : //!
+       4             : //! **Contents**
+       5             : //!
+       6             : //! - [`dylint_library!`]
+       7             : //! - [`declare_late_lint!`, `declare_early_lint!`, `declare_pre_expansion_lint!`]
+       8             : //! - [`impl_late_lint!`, `impl_early_lint!`, `impl_pre_expansion_lint!`]
+       9             : //! - [`constituent` feature]
+      10             : //! - [Configurable libraries]
+      11             : //!
+      12             : //! # `dylint_library!`
+      13             : //!
+      14             : //! The `dylint_library!` macro expands to the following:
+      15             : //!
+      16             : //! ```rust,ignore
+      17             : //! #[allow(unused_extern_crates)]
+      18             : //! extern crate rustc_driver;
+      19             : //!
+      20             : //! #[no_mangle]
+      21             : //! pub extern "C" fn dylint_version() -> *mut std::os::raw::c_char {
+      22             : //!     std::ffi::CString::new($crate::DYLINT_VERSION)
+      23             : //!         .unwrap()
+      24             : //!         .into_raw()
+      25             : //! }
+      26             : //! ```
+      27             : //!
+      28             : //! If your library uses the `dylint_library!` macro and the [`dylint-link`] tool, then all you
+      29             : //! should have to do is implement the [`register_lints`] function. See the [examples] in this
+      30             : //! repository.
+      31             : //!
+      32             : //! # `declare_late_lint!`, etc.
+      33             : //!
+      34             : //! If your library contains just one lint, using `declare_late_lint!`, etc. can make your code more
+      35             : //! concise. Each of these macros requires the same arguments as [`declare_lint!`], and wraps the
+      36             : //! following:
+      37             : //!
+      38             : //! - a call to `dylint_library!`
+      39             : //! - an implementation of the `register_lints` function
+      40             : //! - a call to `declare_lint!`
+      41             : //! - a call to [`declare_lint_pass!`]
+      42             : //!
+      43             : //! For example, `declare_late_lint!(vis NAME, Level, "description")` expands to the following:
+      44             : //!
+      45             : //! ```rust,ignore
+      46             : //! dylint_linting::dylint_library!();
+      47             : //!
+      48             : //! extern crate rustc_lint;
+      49             : //! extern crate rustc_session;
+      50             : //!
+      51             : //! #[no_mangle]
+      52             : //! pub fn register_lints(sess: &rustc_session::Session, lint_store: &mut rustc_lint::LintStore) {
+      53             : //!     dylint_linting::init_config(sess);
+      54             : //!     lint_store.register_lints(&[NAME]);
+      55             : //!     lint_store.register_late_pass(|_| Box::new(Name));
+      56             : //! }
+      57             : //!
+      58             : //! rustc_session::declare_lint!(vis NAME, Level, "description");
+      59             : //!
+      60             : //! rustc_session::declare_lint_pass!(Name => [NAME]);
+      61             : //! ```
+      62             : //!
+      63             : //! `declare_early_lint!` and `declare_pre_expansion_lint!` are defined similarly.
+      64             : //!
+      65             : //! # `impl_late_lint!`, etc.
+      66             : //!
+      67             : //! `impl_late_lint!`, etc. are like `declare_late_lint!`, etc. except:
+      68             : //!
+      69             : //! - each calls [`impl_lint_pass!`] instead of `declare_lint_pass!`;
+      70             : //! - each requires an additional argument to specify the value of the lint's [`LintPass`]
+      71             : //!   structure.
+      72             : //!
+      73             : //! That is, `impl_late_lint!`'s additional argument is what goes here:
+      74             : //!
+      75             : //! ```rust,ignore
+      76             : //!     lint_store.register_late_pass(|_| Box::new(...));
+      77             : //!                                                ^^^
+      78             : //! ```
+      79             : //!
+      80             : //! # `constituent` feature
+      81             : //!
+      82             : //! Enabling the package-level `constituent` feature changes the way the above macros work.
+      83             : //! Specifically, it causes them to _exclude_:
+      84             : //!
+      85             : //! - the call to `dylint_library!`
+      86             : //! - the use of `#[no_mangle]` just prior to the declaration of `register_lints`
+      87             : //!
+      88             : //! Such changes facilitate inclusion of a lint declared with one of the above macros into a larger
+      89             : //! library. That is:
+      90             : //!
+      91             : //! - With the feature turned off, the lint can be built as a library by itself.
+      92             : //! - With the feature turned on, the lint can be built as part of a larger library, alongside other
+      93             : //!   lints.
+      94             : //!
+      95             : //! The [general-purpose] and [supplementary] lints in this repository employ this technique.
+      96             : //! That is, each general-purpose lint can be built as a library by itself, or as part of the
+      97             : //! [`general` library]. An analogous statement applies to the supplementary lints and the
+      98             : //! [`supplementary` library]. The `constituent` feature is the underlying mechanism that makes this
+      99             : //! work.
+     100             : //!
+     101             : //! # Configurable libraries
+     102             : //!
+     103             : //! Libraries can be configured by including a `dylint.toml` file in the target workspace's root
+     104             : //! directory. This crate provides the following functions for reading and parsing `dylint.toml`
+     105             : //! files:
+     106             : //!
+     107             : //! - [`config_or_default`]
+     108             : //! - [`config`]
+     109             : //! - [`config_toml`]
+     110             : //! - [`init_config`]
+     111             : //! - [`try_init_config`]
+     112             : //!
+     113             : //! A configurable library containing just one lint will typically have a `lib.rs` file of the
+     114             : //! following form:
+     115             : //!
+     116             : //! ```rust,ignore
+     117             : //! dylint_linting::impl_late_lint! {
+     118             : //!     ...,
+     119             : //!     LintName::new()
+     120             : //! }
+     121             : //!
+     122             : //! // Lint configuration
+     123             : //! #[derive(Default, serde::Deserialize)]
+     124             : //! struct Config {
+     125             : //!     boolean: bool,
+     126             : //!     strings: Vec<String>,
+     127             : //! }
+     128             : //!
+     129             : //! // Keep a copy of the configuration in the `LintPass` structure.
+     130             : //! struct LintName {
+     131             : //!     config: Config,
+     132             : //! }
+     133             : //!
+     134             : //! // Read the configuration from the `dylint.toml` file, or use the default configuration if
+     135             : //! // none is present.
+     136             : //! impl LintName {
+     137             : //!     pub fn new() -> Self {
+     138             : //!         Self {
+     139             : //!             config: dylint_linting::config_or_default(env!("CARGO_PKG_NAME")),
+     140             : //!         }
+     141             : //!     }
+     142             : //! }
+     143             : //! ```
+     144             : //!
+     145             : //! For a concrete example of a `lib.rs` file with this form, see the
+     146             : //! [`non_local_effect_before_error_return`] library in this repository.
+     147             : //!
+     148             : //! A library containing more than one lint must implement the `register_lints` function without
+     149             : //! relying on the above macros. If the library is configurable, then its `register_lints` function
+     150             : //! should include a call to `dylint_linting::init_config`, as in the following example:
+     151             : //!
+     152             : //! ```rust,ignore
+     153             : //! #[no_mangle]
+     154             : //! pub fn register_lints(sess: &rustc_session::Session, lint_store: &mut rustc_lint::LintStore) {
+     155             : //!     // `init_config` or `try_init_config` must be called before `config_or_default`, `config`,
+     156             : //!     // or `config_toml` is called.
+     157             : //!     dylint_linting::init_config(sess);
+     158             : //!
+     159             : //!     lint_store.register_lints(&[FIRST_LINT_NAME, SECOND_LINT_NAME]);
+     160             : //!
+     161             : //!     lint_store.register_late_pass(|_| Box::new(LintPassName::new()));
+     162             : //! }
+     163             : //! ```
+     164             : //!
+     165             : //! Additional documentation on `config_or_default`, etc. can be found on [docs.rs].
+     166             : //!
+     167             : //! [Configurable libraries]: #configurable-libraries
+     168             : //! [Dylint]: https://github.com/trailofbits/dylint/tree/master
+     169             : //! [`LintPass`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LintPass.html
+     170             : //! [`config_or_default`]: https://docs.rs/dylint_linting/latest/dylint_linting/fn.config_or_default.html
+     171             : //! [`config_toml`]: https://docs.rs/dylint_linting/latest/dylint_linting/fn.config_toml.html
+     172             : //! [`config`]: https://docs.rs/dylint_linting/latest/dylint_linting/fn.config.html
+     173             : //! [`constituent` feature]: #constituent-feature
+     174             : //! [`declare_late_lint!`, `declare_early_lint!`, `declare_pre_expansion_lint!`]: #declare_late_lint-etc
+     175             : //! [`declare_lint!`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/macro.declare_lint.html
+     176             : //! [`declare_lint_pass!`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/macro.declare_lint_pass.html
+     177             : //! [`dylint-link`]: https://github.com/trailofbits/dylint/tree/master/dylint-link
+     178             : //! [`dylint_library!`]: #dylint_library
+     179             : //! [`general` library]: https://github.com/trailofbits/dylint/tree/master/examples/general/src/lib.rs
+     180             : //! [`impl_late_lint!`, `impl_early_lint!`, `impl_pre_expansion_lint!`]: #impl_late_lint-etc
+     181             : //! [`impl_lint_pass!`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/macro.impl_lint_pass.html
+     182             : //! [`init_config`]: https://docs.rs/dylint_linting/latest/dylint_linting/fn.init_config.html
+     183             : //! [`non_local_effect_before_error_return`]: https://github.com/trailofbits/dylint/tree/master/examples/general/non_local_effect_before_error_return/src/lib.rs
+     184             : //! [`register_lints`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/interface/struct.Config.html#structfield.register_lints
+     185             : //! [`supplementary` library]: https://github.com/trailofbits/dylint/tree/master/examples/supplementary/src/lib.rs
+     186             : //! [`try_init_config`]: https://docs.rs/dylint_linting/latest/dylint_linting/fn.try_init_config.html
+     187             : //! [docs.rs documentation]: https://docs.rs/dylint_linting/latest/dylint_linting/
+     188             : //! [docs.rs]: https://docs.rs/dylint_linting/latest/dylint_linting/
+     189             : //! [examples]: https://github.com/trailofbits/dylint/tree/master/examples
+     190             : //! [general-purpose]: https://github.com/trailofbits/dylint/tree/master/examples/general
+     191             : //! [supplementary]: https://github.com/trailofbits/dylint/tree/master/examples/supplementary
+     192             : 
+     193             : #![feature(rustc_private)]
+     194             : #![warn(unused_extern_crates)]
+     195             : 
+     196             : #[allow(unused_extern_crates)]
+     197             : extern crate rustc_driver;
+     198             : 
+     199             : extern crate rustc_session;
+     200             : extern crate rustc_span;
+     201             : 
+     202             : use dylint_internal::{config, env};
+     203             : use rustc_span::Symbol;
+     204             : use std::{
+     205             :     any::type_name,
+     206             :     path::{Path, PathBuf},
+     207             : };
+     208             : 
+     209             : pub use config::{Error as ConfigError, Result as ConfigResult};
+     210             : 
+     211             : pub const DYLINT_VERSION: &str = "0.1.0";
+     212             : 
+     213             : pub use paste;
+     214             : 
+     215             : // smoelius: Including `extern crate rustc_driver` causes the library to link against
+     216             : // `librustc_driver.so`, which dylint-driver also links against. So, essentially, the library uses
+     217             : // dylint-driver's copy of the Rust compiler crates.
+     218             : #[macro_export]
+     219             : macro_rules! dylint_library {
+     220             :     () => {
+     221             :         #[allow(unused_extern_crates)]
+     222             :         extern crate rustc_driver;
+     223             : 
+     224             :         #[doc(hidden)]
+     225             :         #[no_mangle]
+     226             :         pub extern "C" fn dylint_version() -> *mut std::os::raw::c_char {
+     227             :             std::ffi::CString::new($crate::DYLINT_VERSION)
+     228             :                 .unwrap()
+     229             :                 .into_raw()
+     230             :         }
+     231             :     };
+     232             : }
+     233             : 
+     234             : #[cfg(not(feature = "constituent"))]
+     235             : #[doc(hidden)]
+     236             : #[macro_export]
+     237             : macro_rules! __maybe_exclude {
+     238             :     ($item:item) => {
+     239             :         $item
+     240             :     };
+     241             : }
+     242             : 
+     243             : #[cfg(feature = "constituent")]
+     244             : #[doc(hidden)]
+     245             : #[macro_export]
+     246             : macro_rules! __maybe_exclude {
+     247             :     ($item:item) => {};
+     248             : }
+     249             : 
+     250             : #[cfg(not(feature = "constituent"))]
+     251             : #[doc(hidden)]
+     252             : #[macro_export]
+     253             : macro_rules! __maybe_mangle {
+     254             :     ($item:item) => {
+     255             :         #[no_mangle]
+     256             :         $item
+     257             :     };
+     258             : }
+     259             : 
+     260             : #[cfg(feature = "constituent")]
+     261             : #[doc(hidden)]
+     262             : #[macro_export]
+     263             : macro_rules! __maybe_mangle {
+     264             :     ($item:item) => {
+     265             :         $item
+     266             :     };
+     267             : }
+     268             : 
+     269             : #[doc(hidden)]
+     270             : #[macro_export]
+     271             : macro_rules! __declare_and_register_lint {
+     272             :     ($(#[$attr:meta])* $vis:vis $NAME:ident, $Level:ident, $desc:expr, $register_pass_method:ident, $pass:expr) => {
+     273             :         $crate::__maybe_exclude! {
+     274             :             $crate::dylint_library!();
+     275             :         }
+     276             : 
+     277             :         extern crate rustc_lint;
+     278             :         extern crate rustc_session;
+     279             : 
+     280             :         $crate::__maybe_mangle! {
+     281             :             #[allow(clippy::no_mangle_with_rust_abi)]
+     282             :             pub fn register_lints(sess: &rustc_session::Session, lint_store: &mut rustc_lint::LintStore) {
+     283             :                 $crate::init_config(sess);
+     284             :                 lint_store.register_lints(&[$NAME]);
+     285             :                 lint_store.$register_pass_method($pass);
+     286             :             }
+     287             :         }
+     288             : 
+     289             :         rustc_session::declare_lint!($(#[$attr])* $vis $NAME, $Level, $desc);
+     290             :     };
+     291             : }
+     292             : 
+     293             : #[rustversion::before(2022-09-08)]
+     294             : #[doc(hidden)]
+     295             : #[macro_export]
+     296             : macro_rules! __make_late_closure {
+     297             :     ($pass:expr) => {
+     298             :         || Box::new($pass)
+     299             :     };
+     300             : }
+     301             : 
+     302             : // smoelius: Relevant PR and merge commit:
+     303             : // - https://github.com/rust-lang/rust/pull/101501
+     304             : // - https://github.com/rust-lang/rust/commit/87788097b776f8e3662f76627944230684b671bd
+     305             : #[rustversion::since(2022-09-08)]
+     306             : #[doc(hidden)]
+     307             : #[macro_export]
+     308             : macro_rules! __make_late_closure {
+     309             :     ($pass:expr) => {
+     310             :         |_| Box::new($pass)
+     311             :     };
+     312             : }
+     313             : 
+     314             : #[macro_export]
+     315             : macro_rules! impl_pre_expansion_lint {
+     316             :     ($(#[$attr:meta])* $vis:vis $NAME:ident, $Level:ident, $desc:expr, $pass:expr) => {
+     317             :         $crate::__declare_and_register_lint!(
+     318             :             $(#[$attr])* $vis $NAME,
+     319             :             $Level,
+     320             :             $desc,
+     321             :             register_pre_expansion_pass,
+     322             :             || Box::new($pass)
+     323             :         );
+     324             :         $crate::paste::paste! {
+     325             :             rustc_session::impl_lint_pass!([< $NAME:camel >] => [$NAME]);
+     326             :         }
+     327             :     };
+     328             : }
+     329             : 
+     330             : #[macro_export]
+     331             : macro_rules! impl_early_lint {
+     332             :     ($(#[$attr:meta])* $vis:vis $NAME:ident, $Level:ident, $desc:expr, $pass:expr) => {
+     333             :         $crate::__declare_and_register_lint!(
+     334             :             $(#[$attr])* $vis $NAME,
+     335             :             $Level,
+     336             :             $desc,
+     337             :             register_early_pass,
+     338             :             || Box::new($pass)
+     339             :         );
+     340             :         $crate::paste::paste! {
+     341             :             rustc_session::impl_lint_pass!([< $NAME:camel >] => [$NAME]);
+     342             :         }
+     343             :     };
+     344             : }
+     345             : 
+     346             : #[macro_export]
+     347             : macro_rules! impl_late_lint {
+     348             :     ($(#[$attr:meta])* $vis:vis $NAME:ident, $Level:ident, $desc:expr, $pass:expr) => {
+     349             :         $crate::__declare_and_register_lint!(
+     350             :             $(#[$attr])* $vis $NAME,
+     351             :             $Level,
+     352             :             $desc,
+     353             :             register_late_pass,
+     354             :             $crate::__make_late_closure!($pass)
+     355             :         );
+     356             :         $crate::paste::paste! {
+     357             :             rustc_session::impl_lint_pass!([< $NAME:camel >] => [$NAME]);
+     358             :         }
+     359             :     };
+     360             : }
+     361             : 
+     362             : #[macro_export]
+     363             : macro_rules! declare_pre_expansion_lint {
+     364             :     ($(#[$attr:meta])* $vis:vis $NAME:ident, $Level:ident, $desc:expr) => {
+     365             :         $crate::paste::paste! {
+     366             :             $crate::__declare_and_register_lint!(
+     367             :                 $(#[$attr])* $vis $NAME,
+     368             :                 $Level,
+     369             :                 $desc,
+     370             :                 register_pre_expansion_pass,
+     371             :                 || Box::new([< $NAME:camel >])
+     372             :             );
+     373             :             rustc_session::declare_lint_pass!([< $NAME:camel >] => [$NAME]);
+     374             :         }
+     375             :     };
+     376             : }
+     377             : 
+     378             : #[macro_export]
+     379             : macro_rules! declare_early_lint {
+     380             :     ($(#[$attr:meta])* $vis:vis $NAME:ident, $Level:ident, $desc:expr) => {
+     381             :         $crate::paste::paste! {
+     382             :             $crate::__declare_and_register_lint!(
+     383             :                 $(#[$attr])* $vis $NAME,
+     384             :                 $Level,
+     385             :                 $desc,
+     386             :                 register_early_pass,
+     387             :                 || Box::new([< $NAME:camel >])
+     388             :             );
+     389             :             rustc_session::declare_lint_pass!([< $NAME:camel >] => [$NAME]);
+     390             :         }
+     391             :     };
+     392             : }
+     393             : 
+     394             : #[macro_export]
+     395             : macro_rules! declare_late_lint {
+     396             :     ($(#[$attr:meta])* $vis:vis $NAME:ident, $Level:ident, $desc:expr) => {
+     397             :         $crate::paste::paste! {
+     398             :             $crate::__declare_and_register_lint!(
+     399             :                 $(#[$attr])* $vis $NAME,
+     400             :                 $Level,
+     401             :                 $desc,
+     402             :                 register_late_pass,
+     403             :                 $crate::__make_late_closure!([< $NAME:camel >])
+     404             :             );
+     405             :             rustc_session::declare_lint_pass!([< $NAME:camel >] => [$NAME]);
+     406             :         }
+     407             :     };
+     408             : }
+     409             : 
+     410             : /// Reads and deserializes an entry from the workspace's `dylint.toml` file, and returns the default
+     411             : /// value if the entry is not present.
+     412             : ///
+     413             : /// - If the target workspace's `dylint.toml` file contains key `name` and its value can be
+     414             : ///   deserializes as `T`, `config_or_default` returns the deserialized value.
+     415             : /// - If the target workspace's `dylint.toml` file does not exist or does not contain key `name`,
+     416             : ///   `config_or_default` returns `T::default()`.
+     417             : /// - If an error occurs (e.g., the value cannot be deserialized as `T`), `config_or_default`
+     418             : ///   panics.
+     419             : ///
+     420             : /// Note: `init_config` or `try_init_config` must be called before `config_or_default` is called.
+     421             : /// However, the `register_lints` function generated by `impl_late_lint`, etc. includes a call to
+     422             : /// `init_config`.
+     423           0 : pub fn config_or_default<T: Default + serde::de::DeserializeOwned>(name: &str) -> T {
+     424           0 :     config::<T>(name).map_or_else(
+     425           0 :         |error| {
+     426           0 :             panic!(
+     427           0 :                 "Could not parse config as `{}`: {}",
+     428           0 :                 type_name::<T>(),
+     429           0 :                 error
+     430           0 :             )
+     431           0 :         },
+     432           0 :         Option::unwrap_or_default,
+     433           0 :     )
+     434           0 : }
+     435             : 
+     436             : /// Reads and deserializes an entry from the workspace's `dylint.toml` file.
+     437             : ///
+     438             : /// Returns:
+     439             : /// - `Ok(Some(...))` if the target workspace's `dylint.toml` file contains key `name` and its value
+     440             : ///   can be deserialized as `T`
+     441             : /// - `Ok(None)` if the target workspace's `dylint.toml` file does not exist or does not contain key
+     442             : ///   `name`
+     443             : /// - `Err(...)` if an error occurs (e.g., the value cannot be deserialized as `T`)
+     444             : ///
+     445             : /// Note: `init_config` or `try_init_config` must be called before `config` is called. However, the
+     446             : /// `register_lints` function generated by `impl_late_lint`, etc. includes a call to `init_config`.
+     447           0 : pub fn config<T: serde::de::DeserializeOwned>(name: &str) -> ConfigResult<Option<T>> {
+     448           0 :     let toml = config_toml(name)?;
+     449           0 :     toml.map(toml::Value::try_into::<T>)
+     450           0 :         .transpose()
+     451           0 :         .map_err(Into::into)
+     452           0 : }
+     453             : 
+     454             : /// Reads an entry from the workspace's `dylint.toml` file as a raw `toml::Value`.
+     455             : ///
+     456             : /// Returns:
+     457             : /// - `Ok(Some(...))` if the target workspace's `dylint.toml` file contains key `name`
+     458             : /// - `Ok(None)` if the target workspace's `dylint.toml` file does not exist or does not contain key
+     459             : ///   `name`
+     460             : /// - `Err(...)` if an error occurs (e.g., `init_config` was not called)
+     461             : ///
+     462             : /// Note: `init_config` or `try_init_config` must be called before `config_toml` is called. However,
+     463             : /// the `register_lints` function generated by `impl_late_lint`, etc. includes a call to
+     464             : /// `init_config`.
+     465           0 : pub fn config_toml(name: &str) -> ConfigResult<Option<toml::Value>> {
+     466           0 :     let Some(config_table) = config::get() else {
+     467           0 :         return Err(ConfigError::other(
+     468           0 :             "Config is not initialized; `init_config` should have been called from \
+     469           0 :              `register_lints`"
+     470           0 :                 .into(),
+     471           0 :         ));
+     472             :     };
+     473           0 :     Ok(config_table.get(name).cloned())
+     474           0 : }
+     475             : 
+     476             : /// A wrapper around `try_init_config`. Calls `rustc_session::early_error` if `try_init_config`
+     477             : /// returns an error.
+     478             : ///
+     479             : /// Note: `init_config` or `try_init_config` must be called before `config_or_default`, `config`, or
+     480             : /// `config_toml` is called. However, the `register_lints` function generated by `impl_late_lint`,
+     481             : /// etc. includes a call to `init_config`.
+     482           0 : pub fn init_config(sess: &rustc_session::Session) {
+     483           0 :     try_init_config(sess).unwrap_or_else(|err| {
+     484           0 :         let msg = format!("could not read configuration file: {err}");
+     485           0 :         early_error(msg);
+     486           0 :     });
+     487           0 : }
+     488             : 
+     489             : trait ParseSess {
+     490             :     fn parse_sess(&self) -> &rustc_session::parse::ParseSess;
+     491             : }
+     492             : 
+     493             : impl ParseSess for rustc_session::Session {
+     494             :     #[rustversion::before(2024-03-05)]
+     495             :     fn parse_sess(&self) -> &rustc_session::parse::ParseSess {
+     496             :         &self.parse_sess
+     497             :     }
+     498             : 
+     499             :     #[rustversion::since(2024-03-05)]
+     500           0 :     fn parse_sess(&self) -> &rustc_session::parse::ParseSess {
+     501           0 :         &self.psess
+     502           0 :     }
+     503             : }
+     504             : 
+     505             : /// Reads the target workspace's `dylint.toml` file and parses it as a `toml::value::Table`.
+     506             : ///
+     507             : /// Note: `init_config` or `try_init_config` must be called before `config_or_default`, `config`, or
+     508             : /// `config_toml` is called. However, the `register_lints` function generated by `impl_late_lint`,
+     509             : /// etc. includes a call to `init_config`.
+     510           0 : pub fn try_init_config(sess: &rustc_session::Session) -> ConfigResult<()> {
+     511           0 :     let result = try_init_config_guarded(sess);
+     512           0 : 
+     513           0 :     // smoelius: If we're returning `Ok(())`, ensure that `config::get()` will later return
+     514           0 :     // `Some(..)`.
+     515           0 :     if result.is_ok() && config::get().is_none() {
+     516           0 :         config::init_from_string("").unwrap();
+     517           0 :     }
+     518             : 
+     519           0 :     result
+     520           0 : }
+     521             : 
+     522             : #[allow(clippy::empty_line_after_outer_attr)]
+     523             : #[cfg_attr(dylint_lib = "supplementary", allow(commented_code))]
+     524           0 : fn try_init_config_guarded(sess: &rustc_session::Session) -> ConfigResult<()> {
+     525           0 :     if config::get().is_some() {
+     526           0 :         return Ok(());
+     527           0 :     }
+     528             : 
+     529           0 :     if let Ok(value) = std::env::var(env::DYLINT_TOML) {
+     530           0 :         config::init_from_string(&value)?;
+     531           0 :         sess.parse_sess().env_depinfo.lock().insert((
+     532           0 :             Symbol::intern(env::DYLINT_TOML),
+     533           0 :             Some(Symbol::intern(&value)),
+     534           0 :         ));
+     535           0 :         return Ok(());
+     536           0 :     }
+     537             : 
+     538           0 :     let Some(local_crate_source_file) =
+     539           0 :         local_crate_source_file(sess).filter(|path| *path != PathBuf::new())
+     540             :     else {
+     541           0 :         return Ok(());
+     542             :     };
+     543             : 
+     544             :     #[rustfmt::skip]
+     545             :     // smoelius: Canonicalizing `local_crate_source_file` causes errors like the following on
+     546             :     // Windows:
+     547             :     //
+     548             :     //   error: could not read configuration file: cargo metadata error: `cargo metadata` exited with an error: error: failed to load manifest for dependency `await_holding_span_guard`
+     549             :     //
+     550             :     //          Caused by:
+     551             :     //            failed to parse manifest at `D:\a\dylint\dylint\examples\general\await_holding_span_guard\Cargo.toml`
+     552             :     //
+     553             :     //          Caused by:
+     554             :     //            error inheriting `clippy_utils` from workspace root manifest's `workspace.dependencies.clippy_utils`
+     555             :     //
+     556             :     //          Caused by:
+     557             :     //            `workspace.dependencies` was not defined
+     558             :     //
+     559             :     // The issue is that `canonicalize` prepends `\\?\` to the path, and such "verbatim" paths
+     560             :     // cause problems for Cargo. See the following GitHub issue for more information:
+     561             :     // https://github.com/rust-lang/cargo/issues/9770#issuecomment-993069234
+     562             :     //
+     563             :     // For reasons that I don't understand, fixing this problem in Cargo would be difficult.
+     564             : 
+     565             :     /* let local_crate_source_file = local_crate_source_file.canonicalize().map_err(|error| {
+     566             :         ConfigErrorInner::Io(
+     567             :             format!("Could not canonicalize {local_crate_source_file:?}"),
+     568             :             error,
+     569             :         )
+     570             :     })?; */
+     571             : 
+     572           0 :     let mut parent = local_crate_source_file
+     573           0 :         .parent()
+     574           0 :         .ok_or_else(|| ConfigError::other("Could not get parent directory".into()))?;
+     575             : 
+     576             :     // smoelius: https://users.rust-lang.org/t/pathbuf-equivalent-to-string-is-empty/24823
+     577           0 :     if parent.as_os_str().is_empty() {
+     578           0 :         parent = Path::new(".");
+     579           0 :     };
+     580             : 
+     581           0 :     let result = cargo_metadata::MetadataCommand::new()
+     582           0 :         .current_dir(parent)
+     583           0 :         .no_deps()
+     584           0 :         .exec();
+     585             : 
+     586           0 :     match result {
+     587           0 :         Err(cargo_metadata::Error::CargoMetadata { stderr })
+     588           0 :             if stderr.contains("could not find `Cargo.toml`") => {}
+     589             :         _ => {
+     590           0 :             let metadata = result?;
+     591             : 
+     592           0 :             let value = config::try_init_with_metadata(&metadata)?;
+     593             : 
+     594           0 :             if let Some(s) = &value {
+     595           0 :                 sess.parse_sess()
+     596           0 :                     .file_depinfo
+     597           0 :                     .lock()
+     598           0 :                     .insert(Symbol::intern(s));
+     599           0 :             }
+     600             :         }
+     601             :     }
+     602             : 
+     603           0 :     Ok(())
+     604           0 : }
+     605             : 
+     606             : #[rustversion::before(2023-01-19)]
+     607             : fn local_crate_source_file(sess: &rustc_session::Session) -> Option<PathBuf> {
+     608             :     sess.local_crate_source_file.clone()
+     609             : }
+     610             : 
+     611             : // smoelius: Relevant PR and merge commit:
+     612             : // - https://github.com/rust-lang/rust/pull/106810
+     613             : // - https://github.com/rust-lang/rust/commit/65d2f2a5f9c323c88d1068e8e90d0b47a20d491c
+     614             : #[rustversion::all(since(2023-01-19), before(2024-03-29))]
+     615             : fn local_crate_source_file(sess: &rustc_session::Session) -> Option<PathBuf> {
+     616             :     sess.local_crate_source_file()
+     617             : }
+     618             : 
+     619             : // smoelius: Relevant PR and merge commit:
+     620             : // - https://github.com/rust-lang/rust/pull/122450
+     621             : // - https://github.com/rust-lang/rust/commit/685927aae69657b46323cffbeb0062835bd7fa2b
+     622             : #[rustversion::since(2024-03-29)]
+     623           0 : fn local_crate_source_file(sess: &rustc_session::Session) -> Option<PathBuf> {
+     624             :     use rustc_span::RealFileName;
+     625           0 :     sess.local_crate_source_file()
+     626           0 :         .and_then(RealFileName::into_local_path)
+     627           0 : }
+     628             : 
+     629             : #[rustversion::before(2023-06-28)]
+     630             : fn early_error(msg: String) -> ! {
+     631             :     rustc_session::early_error(
+     632             :         rustc_session::config::ErrorOutputType::default(),
+     633             :         Box::leak(msg.into_boxed_str()) as &str,
+     634             :     )
+     635             : }
+     636             : 
+     637             : #[rustversion::since(2023-06-28)]
+     638             : extern crate rustc_errors;
+     639             : 
+     640             : #[rustversion::all(since(2023-06-28), before(2023-12-18))]
+     641             : fn early_error(msg: impl Into<rustc_errors::DiagnosticMessage>) -> ! {
+     642             :     let handler =
+     643             :         rustc_session::EarlyErrorHandler::new(rustc_session::config::ErrorOutputType::default());
+     644             :     handler.early_error(msg)
+     645             : }
+     646             : 
+     647             : #[rustversion::all(since(2023-12-18), before(2023-12-23))]
+     648             : fn early_error(msg: impl Into<rustc_errors::DiagnosticMessage>) -> ! {
+     649             :     let handler =
+     650             :         rustc_session::EarlyDiagCtxt::new(rustc_session::config::ErrorOutputType::default());
+     651             :     handler.early_error(msg)
+     652             : }
+     653             : 
+     654             : #[rustversion::all(since(2023-12-23), before(2024-03-05))]
+     655             : fn early_error(msg: impl Into<rustc_errors::DiagnosticMessage>) -> ! {
+     656             :     let handler =
+     657             :         rustc_session::EarlyDiagCtxt::new(rustc_session::config::ErrorOutputType::default());
+     658             :     handler.early_fatal(msg)
+     659             : }
+     660             : 
+     661             : #[rustversion::since(2024-03-05)]
+     662           0 : fn early_error(msg: impl Into<rustc_errors::DiagMessage>) -> ! {
+     663           0 :     let handler =
+     664           0 :         rustc_session::EarlyDiagCtxt::new(rustc_session::config::ErrorOutputType::default());
+     665           0 :     handler.early_fatal(msg)
+     666             : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/utils/testing/src/index-sort-f.html b/coverage/utils/testing/src/index-sort-f.html new file mode 100644 index 000000000..49a4d8b2c --- /dev/null +++ b/coverage/utils/testing/src/index-sort-f.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - unnamed - utils/testing/src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - utils/testing/srcHitTotalCoverage
Test:unnamedLines:02970.0 %
Date:2024-09-27 12:58:08Functions:0450.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
ui.rs +
0.0%
+
0.0 %0 / 600.0 %0 / 9
lib.rs +
0.0%
+
0.0 %0 / 2370.0 %0 / 36
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/utils/testing/src/index-sort-l.html b/coverage/utils/testing/src/index-sort-l.html new file mode 100644 index 000000000..a76ff8a05 --- /dev/null +++ b/coverage/utils/testing/src/index-sort-l.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - unnamed - utils/testing/src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - utils/testing/srcHitTotalCoverage
Test:unnamedLines:02970.0 %
Date:2024-09-27 12:58:08Functions:0450.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
ui.rs +
0.0%
+
0.0 %0 / 600.0 %0 / 9
lib.rs +
0.0%
+
0.0 %0 / 2370.0 %0 / 36
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/utils/testing/src/index.html b/coverage/utils/testing/src/index.html new file mode 100644 index 000000000..f82894292 --- /dev/null +++ b/coverage/utils/testing/src/index.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - unnamed - utils/testing/src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - utils/testing/srcHitTotalCoverage
Test:unnamedLines:02970.0 %
Date:2024-09-27 12:58:08Functions:0450.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
lib.rs +
0.0%
+
0.0 %0 / 2370.0 %0 / 36
ui.rs +
0.0%
+
0.0 %0 / 600.0 %0 / 9
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/utils/testing/src/lib.rs.func-sort-c.html b/coverage/utils/testing/src/lib.rs.func-sort-c.html new file mode 100644 index 000000000..7100ee9a3 --- /dev/null +++ b/coverage/utils/testing/src/lib.rs.func-sort-c.html @@ -0,0 +1,216 @@ + + + + + + + LCOV - unnamed - utils/testing/src/lib.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - utils/testing/src - lib.rs (source / functions)HitTotalCoverage
Test:unnamedLines:02370.0 %
Date:2024-09-27 12:58:08Functions:0360.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<dylint_testing::VarGuard as core::ops::drop::Drop>::drop0
<dylint_testing::VarGuard>::set::<_>0
dylint_testing::RE::{closure#0}0
dylint_testing::copy_with_extension::<_0
dylint_testing::dylint_libs0
dylint_testing::example_target0
dylint_testing::example_target::{closure#0}0
dylint_testing::example_target::{closure#1}0
dylint_testing::example_targets0
dylint_testing::example_targets::{closure#0}0
dylint_testing::initialize0
dylint_testing::initialize::{closure#0}0
dylint_testing::linking_flags0
dylint_testing::linking_flags::{closure#0}0
dylint_testing::next::<_0
dylint_testing::remove_example0
dylint_testing::remove_example::{closure#0}0
dylint_testing::remove_example::{closure#1}0
dylint_testing::remove_example::{closure#2}0
dylint_testing::run_example_test0
dylint_testing::run_example_test::{closure#0}0
dylint_testing::run_example_test::{closure#1}0
dylint_testing::run_example_test::{closure#2}0
dylint_testing::run_example_test::{closure#3}0
dylint_testing::run_tests0
dylint_testing::run_tests::{closure#0}0
dylint_testing::rustc_flags0
dylint_testing::rustc_flags::{closure#0}0
dylint_testing::rustc_flags::{closure#0}::{closure#0}0
dylint_testing::rustc_flags::{closure#0}::{closure#1}0
dylint_testing::rustc_flags::{closure#0}::{closure#1}::{closure#0}0
dylint_testing::rustc_flags::{closure#1}0
dylint_testing::snake_case0
dylint_testing::ui_test::<_>0
dylint_testing::ui_test_example0
dylint_testing::ui_test_examples0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/utils/testing/src/lib.rs.func.html b/coverage/utils/testing/src/lib.rs.func.html new file mode 100644 index 000000000..59fd3ad10 --- /dev/null +++ b/coverage/utils/testing/src/lib.rs.func.html @@ -0,0 +1,216 @@ + + + + + + + LCOV - unnamed - utils/testing/src/lib.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - utils/testing/src - lib.rs (source / functions)HitTotalCoverage
Test:unnamedLines:02370.0 %
Date:2024-09-27 12:58:08Functions:0360.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<dylint_testing::VarGuard as core::ops::drop::Drop>::drop0
<dylint_testing::VarGuard>::set::<_>0
dylint_testing::RE::{closure#0}0
dylint_testing::copy_with_extension::<_0
dylint_testing::dylint_libs0
dylint_testing::example_target0
dylint_testing::example_target::{closure#0}0
dylint_testing::example_target::{closure#1}0
dylint_testing::example_targets0
dylint_testing::example_targets::{closure#0}0
dylint_testing::initialize0
dylint_testing::initialize::{closure#0}0
dylint_testing::linking_flags0
dylint_testing::linking_flags::{closure#0}0
dylint_testing::next::<_0
dylint_testing::remove_example0
dylint_testing::remove_example::{closure#0}0
dylint_testing::remove_example::{closure#1}0
dylint_testing::remove_example::{closure#2}0
dylint_testing::run_example_test0
dylint_testing::run_example_test::{closure#0}0
dylint_testing::run_example_test::{closure#1}0
dylint_testing::run_example_test::{closure#2}0
dylint_testing::run_example_test::{closure#3}0
dylint_testing::run_tests0
dylint_testing::run_tests::{closure#0}0
dylint_testing::rustc_flags0
dylint_testing::rustc_flags::{closure#0}0
dylint_testing::rustc_flags::{closure#0}::{closure#0}0
dylint_testing::rustc_flags::{closure#0}::{closure#1}0
dylint_testing::rustc_flags::{closure#0}::{closure#1}::{closure#0}0
dylint_testing::rustc_flags::{closure#1}0
dylint_testing::snake_case0
dylint_testing::ui_test::<_>0
dylint_testing::ui_test_example0
dylint_testing::ui_test_examples0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/utils/testing/src/lib.rs.gcov.html b/coverage/utils/testing/src/lib.rs.gcov.html new file mode 100644 index 000000000..7e39a9567 --- /dev/null +++ b/coverage/utils/testing/src/lib.rs.gcov.html @@ -0,0 +1,550 @@ + + + + + + + LCOV - unnamed - utils/testing/src/lib.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - utils/testing/src - lib.rs (source / functions)HitTotalCoverage
Test:unnamedLines:02370.0 %
Date:2024-09-27 12:58:08Functions:0360.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : //! This crate provides convenient access to the [`compiletest_rs`] package for testing [Dylint]
+       2             : //! libraries.
+       3             : //!
+       4             : //! **Note: If your test has dependencies, you must use `ui_test_example` or `ui_test_examples`.**
+       5             : //! See the [`question_mark_in_expression`] example in this repository.
+       6             : //!
+       7             : //! This crate provides the following three functions:
+       8             : //!
+       9             : //! - [`ui_test`] - test a library on all source files in a directory
+      10             : //! - [`ui_test_example`] - test a library on one example target
+      11             : //! - [`ui_test_examples`] - test a library on all example targets
+      12             : //!
+      13             : //! For most situations, you can add the following to your library's `lib.rs` file:
+      14             : //!
+      15             : //! ```rust,ignore
+      16             : //! #[test]
+      17             : //! fn ui() {
+      18             : //!     dylint_testing::ui_test(env!("CARGO_PKG_NAME"), "ui");
+      19             : //! }
+      20             : //! ```
+      21             : //!
+      22             : //! And include one or more `.rs` and `.stderr` files in a `ui` directory alongside your library's
+      23             : //! `src` directory. See the [examples] in this repository.
+      24             : //!
+      25             : //! # Test builder
+      26             : //!
+      27             : //! In addition to the above three functions, [`ui::Test`] is a test "builder." Currently, the main
+      28             : //! advantage of using `Test` over the above functions is that `Test` allows flags to be passed to
+      29             : //! `rustc`. For an example of its use, see [`non_thread_safe_call_in_test`] in this repository.
+      30             : //!
+      31             : //! `Test` has three constructors, which correspond to the above three functions as follows:
+      32             : //!
+      33             : //! - [`ui::Test::src_base`] <-> [`ui_test`]
+      34             : //! - [`ui::Test::example`] <-> [`ui_test_example`]
+      35             : //! - [`ui::Test::examples`] <-> [`ui_test_examples`]
+      36             : //!
+      37             : //! In each case, the constructor's arguments are exactly those of the corresponding function.
+      38             : //!
+      39             : //! A `Test` instance has the following methods:
+      40             : //!
+      41             : //! - `dylint_toml` - set the `dylint.toml` file's contents (for testing [configurable libraries])
+      42             : //! - `rustc_flags` - pass flags to the compiler when running the test
+      43             : //! - `run` - run the test
+      44             : //!
+      45             : //! # Updating `.stderr` files
+      46             : //!
+      47             : //! If the standard error that results from running your `.rs` file differs from the contents of
+      48             : //! your `.stderr` file, `compiletest_rs` will produce a report like the following:
+      49             : //!
+      50             : //! ```text
+      51             : //! diff of stderr:
+      52             : //!
+      53             : //!  error: calling `std::env::set_var` in a test could affect the outcome of other tests
+      54             : //!    --> $DIR/main.rs:8:5
+      55             : //!     |
+      56             : //!  LL |     std::env::set_var("KEY", "VALUE");
+      57             : //!     |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+      58             : //!     |
+      59             : //!     = note: `-D non-thread-safe-call-in-test` implied by `-D warnings`
+      60             : //!
+      61             : //! -error: aborting due to previous error
+      62             : //! +error: calling `std::env::set_var` in a test could affect the outcome of other tests
+      63             : //! +  --> $DIR/main.rs:23:9
+      64             : //! +   |
+      65             : //! +LL |         std::env::set_var("KEY", "VALUE");
+      66             : //! +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+      67             : //! +
+      68             : //! +error: aborting due to 2 previous errors
+      69             : //!
+      70             : //!
+      71             : //!
+      72             : //! The actual stderr differed from the expected stderr.
+      73             : //! Actual stderr saved to ...
+      74             : //! ```
+      75             : //!
+      76             : //! The meaning of each line is as follows:
+      77             : //!
+      78             : //! - A line beginning with a plus (`+`) is in the actual standard error, but not in your `.stderr`
+      79             : //!   file.
+      80             : //! - A line beginning with a minus (`-`) is in your `.stderr` file, but not in the actual standard
+      81             : //!   error.
+      82             : //! - A line beginning with a space (` `) is in both the actual standard error and your `.stderr`
+      83             : //!   file, and is provided for context.
+      84             : //! - All other lines (e.g., `diff of stderr:`) contain `compiletest_rs` messages.
+      85             : //!
+      86             : //! **Note:** In the actual standard error, a blank line usually follows the `error: aborting due to
+      87             : //! N previous errors` line. So a correct `.stderr` file will typically contain one blank line at
+      88             : //! the end.
+      89             : //!
+      90             : //! In general, it is not too hard to update a `.stderr` file by hand. However, the `compiletest_rs`
+      91             : //! report should contain a line of the form `Actual stderr saved to PATH`. Copying `PATH` to your
+      92             : //! `.stderr` file should update it completely.
+      93             : //!
+      94             : //! Additional documentation on `compiletest_rs` can be found in [its repository].
+      95             : //!
+      96             : //! [Dylint]: https://github.com/trailofbits/dylint/tree/master
+      97             : //! [`compiletest_rs`]: https://github.com/Manishearth/compiletest-rs
+      98             : //! [`non_thread_safe_call_in_test`]: https://github.com/trailofbits/dylint/tree/master/examples/general/non_thread_safe_call_in_test/src/lib.rs
+      99             : //! [`question_mark_in_expression`]: https://github.com/trailofbits/dylint/tree/master/examples/restriction/question_mark_in_expression/Cargo.toml
+     100             : //! [`ui::Test::example`]: https://docs.rs/dylint_testing/latest/dylint_testing/ui/struct.Test.html#method.example
+     101             : //! [`ui::Test::examples`]: https://docs.rs/dylint_testing/latest/dylint_testing/ui/struct.Test.html#method.examples
+     102             : //! [`ui::Test::src_base`]: https://docs.rs/dylint_testing/latest/dylint_testing/ui/struct.Test.html#method.src_base
+     103             : //! [`ui::Test`]: https://docs.rs/dylint_testing/latest/dylint_testing/ui/struct.Test.html
+     104             : //! [`ui_test_example`]: https://docs.rs/dylint_testing/latest/dylint_testing/fn.ui_test_example.html
+     105             : //! [`ui_test_examples`]: https://docs.rs/dylint_testing/latest/dylint_testing/fn.ui_test_examples.html
+     106             : //! [`ui_test`]: https://docs.rs/dylint_testing/latest/dylint_testing/fn.ui_test.html
+     107             : //! [configurable libraries]: https://github.com/trailofbits/dylint/tree/master#configurable-libraries
+     108             : //! [docs.rs documentation]: https://docs.rs/dylint_testing/latest/dylint_testing/
+     109             : //! [examples]: https://github.com/trailofbits/dylint/tree/master/examples
+     110             : //! [its repository]: https://github.com/Manishearth/compiletest-rs
+     111             : 
+     112             : use anyhow::{anyhow, ensure, Context, Result};
+     113             : use cargo_metadata::{Metadata, Package, Target};
+     114             : use compiletest_rs as compiletest;
+     115             : use dylint_internal::{env, library_filename, rustup::is_rustc, CommandExt};
+     116             : use once_cell::sync::{Lazy, OnceCell};
+     117             : use regex::Regex;
+     118             : use std::{
+     119             :     env::{consts, remove_var, set_var, var_os},
+     120             :     ffi::{OsStr, OsString},
+     121             :     fs::{copy, read_dir, remove_file},
+     122             :     io::BufRead,
+     123             :     path::{Path, PathBuf},
+     124             :     sync::Mutex,
+     125             : };
+     126             : 
+     127             : pub mod ui;
+     128             : 
+     129             : static DRIVER: OnceCell<PathBuf> = OnceCell::new();
+     130             : static LINKING_FLAGS: OnceCell<Vec<String>> = OnceCell::new();
+     131             : 
+     132             : /// Test a library on all source files in a directory.
+     133             : ///
+     134             : /// - `name` is the name of a Dylint library to be tested. (Often, this is the same as the package
+     135             : ///   name.)
+     136             : /// - `src_base` is a directory containing:
+     137             : ///   - source files on which to test the library (`.rs` files), and
+     138             : ///   - the output those files should produce (`.stderr` files).
+     139           0 : pub fn ui_test(name: &str, src_base: impl AsRef<Path>) {
+     140           0 :     ui::Test::src_base(name, src_base).run();
+     141           0 : }
+     142             : 
+     143             : /// Test a library on one example target.
+     144             : ///
+     145             : /// - `name` is the name of a Dylint library to be tested.
+     146             : /// - `example` is an example target on which to test the library.
+     147           0 : pub fn ui_test_example(name: &str, example: &str) {
+     148           0 :     ui::Test::example(name, example).run();
+     149           0 : }
+     150             : 
+     151             : /// Test a library on all example targets.
+     152             : ///
+     153             : /// - `name` is the name of a Dylint library to be tested.
+     154           0 : pub fn ui_test_examples(name: &str) {
+     155           0 :     ui::Test::examples(name).run();
+     156           0 : }
+     157             : 
+     158           0 : fn initialize(name: &str) -> Result<&Path> {
+     159           0 :     DRIVER
+     160           0 :         .get_or_try_init(|| {
+     161           0 :             let _ = env_logger::try_init();
+     162           0 : 
+     163           0 :             // smoelius: Try to order failures by how informative they are: failure to build the
+     164           0 :             // library, failure to find the library, failure to build/find the driver.
+     165           0 : 
+     166           0 :             dylint_internal::cargo::build(&format!("library `{name}`"))
+     167           0 :                 .build()
+     168           0 :                 .success()?;
+     169             : 
+     170             :             // smoelius: `DYLINT_LIBRARY_PATH` must be set before `dylint_libs` is called.
+     171             :             // smoelius: This was true when `dylint_libs` called `name_toolchain_map`, but that is
+     172             :             // no longer the case. I am leaving the comment here for now in case removal
+     173             :             // of the `name_toolchain_map` call causes a regression.
+     174           0 :             let metadata = dylint_internal::cargo::current_metadata().unwrap();
+     175           0 :             let dylint_library_path = metadata.target_directory.join("debug");
+     176           0 :             set_var(env::DYLINT_LIBRARY_PATH, dylint_library_path);
+     177             : 
+     178           0 :             let dylint_libs = dylint_libs(name)?;
+     179           0 :             let driver = dylint::driver_builder::get(
+     180           0 :                 &dylint::opts::Dylint::default(),
+     181           0 :                 env!("RUSTUP_TOOLCHAIN"),
+     182           0 :             )?;
+     183             : 
+     184           0 :             set_var(env::CLIPPY_DISABLE_DOCS_LINKS, "true");
+     185           0 :             set_var(env::DYLINT_LIBS, dylint_libs);
+     186           0 : 
+     187           0 :             Ok(driver)
+     188           0 :         })
+     189           0 :         .map(PathBuf::as_path)
+     190           0 : }
+     191             : 
+     192             : #[doc(hidden)]
+     193           0 : pub fn dylint_libs(name: &str) -> Result<String> {
+     194           0 :     let metadata = dylint_internal::cargo::current_metadata().unwrap();
+     195           0 :     let rustup_toolchain = env::var(env::RUSTUP_TOOLCHAIN)?;
+     196           0 :     let filename = library_filename(name, &rustup_toolchain);
+     197           0 :     let path = metadata.target_directory.join("debug").join(filename);
+     198           0 :     let paths = vec![path];
+     199           0 :     serde_json::to_string(&paths).map_err(Into::into)
+     200           0 : }
+     201             : 
+     202           0 : fn example_target(package: &Package, example: &str) -> Result<Target> {
+     203           0 :     package
+     204           0 :         .targets
+     205           0 :         .iter()
+     206           0 :         .find(|target| target.kind == ["example"] && target.name == example)
+     207           0 :         .cloned()
+     208           0 :         .ok_or_else(|| anyhow!("Could not find example `{}`", example))
+     209           0 : }
+     210             : 
+     211             : #[allow(clippy::unnecessary_wraps)]
+     212           0 : fn example_targets(package: &Package) -> Result<Vec<Target>> {
+     213           0 :     Ok(package
+     214           0 :         .targets
+     215           0 :         .iter()
+     216           0 :         .filter(|target| target.kind == ["example"])
+     217           0 :         .cloned()
+     218           0 :         .collect())
+     219           0 : }
+     220             : 
+     221           0 : fn run_example_test(
+     222           0 :     driver: &Path,
+     223           0 :     metadata: &Metadata,
+     224           0 :     package: &Package,
+     225           0 :     target: &Target,
+     226           0 :     config: &ui::Config,
+     227           0 : ) -> Result<()> {
+     228           0 :     let linking_flags = linking_flags(metadata, package, target)?;
+     229           0 :     let file_name = target
+     230           0 :         .src_path
+     231           0 :         .file_name()
+     232           0 :         .ok_or_else(|| anyhow!("Could not get file name"))?;
+     233             : 
+     234           0 :     let tempdir = tempfile::tempdir().with_context(|| "`tempdir` failed")?;
+     235           0 :     let src_base = tempdir.path();
+     236           0 :     let to = src_base.join(file_name);
+     237           0 : 
+     238           0 :     copy(&target.src_path, &to).with_context(|| {
+     239           0 :         format!(
+     240           0 :             "Could not copy `{}` to `{}`",
+     241           0 :             target.src_path,
+     242           0 :             to.to_string_lossy()
+     243           0 :         )
+     244           0 :     })?;
+     245           0 :     ["fixed", "stderr", "stdout"]
+     246           0 :         .map(|extension| copy_with_extension(&target.src_path, &to, extension).unwrap_or_default());
+     247           0 : 
+     248           0 :     let mut config = config.clone();
+     249           0 :     config.rustc_flags.extend(linking_flags.iter().cloned());
+     250           0 : 
+     251           0 :     run_tests(driver, src_base, &config);
+     252           0 : 
+     253           0 :     Ok(())
+     254           0 : }
+     255             : 
+     256           0 : fn linking_flags(
+     257           0 :     metadata: &Metadata,
+     258           0 :     package: &Package,
+     259           0 :     target: &Target,
+     260           0 : ) -> Result<&'static [String]> {
+     261           0 :     LINKING_FLAGS
+     262           0 :         .get_or_try_init(|| {
+     263           0 :             let rustc_flags = rustc_flags(metadata, package, target)?;
+     264             : 
+     265           0 :             let mut linking_flags = Vec::new();
+     266           0 : 
+     267           0 :             let mut iter = rustc_flags.into_iter();
+     268           0 :             while let Some(flag) = iter.next() {
+     269           0 :                 if flag.starts_with("--edition=") {
+     270           0 :                     linking_flags.push(flag);
+     271           0 :                 } else if flag == "--extern" || flag == "-L" {
+     272           0 :                     let arg = next(&flag, &mut iter)?;
+     273           0 :                     linking_flags.extend([flag, arg.trim_matches('\'').to_owned()]);
+     274           0 :                 }
+     275             :             }
+     276             : 
+     277           0 :             Ok(linking_flags)
+     278           0 :         })
+     279           0 :         .map(Vec::as_slice)
+     280           0 : }
+     281             : 
+     282             : // smoelius: We need to recover the `rustc` flags used to build a target. I can see four options:
+     283             : //
+     284             : // * Use `cargo build --build-plan`
+     285             : //   - Pros: Easily parsable JSON output
+     286             : //   - Cons: Unstable and likely to be removed: https://github.com/rust-lang/cargo/issues/7614
+     287             : // * Parse the output of `cargo build --verbose`
+     288             : //   - Pros: ?
+     289             : //   - Cons: Not as easily parsable, requires synchronization (see below)
+     290             : // * Use a custom executor like Siderophile does: https://github.com/trailofbits/siderophile/blob/26c067306f6c2f66d9530dacef6b17dbf59cdf8c/src/trawl_source/mod.rs#L399
+     291             : //   - Pros: Ground truth
+     292             : //   - Cons: Seems a bit of a heavy lift (Note: I think Siderophile's approach was inspired by
+     293             : //     `cargo-geiger`.)
+     294             : // * Set `RUSTC_WORKSPACE_WRAPPER` to something that logs `rustc` invocations
+     295             : //   - Pros: Ground truth
+     296             : //   - Cons: Requires a separate executable/script, portability could be an issue
+     297             : //
+     298             : // I am going with the second option for now, because it seems to be the least of all evils. This
+     299             : // decision may need to be revisited.
+     300             : 
+     301           0 : static RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"^\s*Running\s*`(.*)`$").unwrap());
+     302             : 
+     303           0 : fn rustc_flags(metadata: &Metadata, package: &Package, target: &Target) -> Result<Vec<String>> {
+     304             :     // smoelius: The following comments are old and retained for posterity. The linking flags are
+     305             :     // now initialized using a `OnceCell`, which makes the mutex unnecessary.
+     306             :     //   smoelius: Force rebuilding of the example by removing it. This is kind of messy. The
+     307             :     //   example is a shared resource that may be needed by multiple tests. For now, I lock a mutex
+     308             :     //   while the example is removed and put back.
+     309             :     //   smoelius: Should we use a temporary target directory here?
+     310           0 :     let output = {
+     311           0 :         remove_example(metadata, package, target)?;
+     312             : 
+     313             :         // smoelius: Because of lazy initialization, `cargo build` is run only once. Seeing
+     314             :         // "Building example `target`" for one example but not for others is confusing. So instead
+     315             :         // say "Building `package` examples".
+     316           0 :         dylint_internal::cargo::build(&format!("`{}` examples", package.name))
+     317           0 :             .build()
+     318           0 :             .envs([(env::CARGO_TERM_COLOR, "never")])
+     319           0 :             .args([
+     320           0 :                 "--manifest-path",
+     321           0 :                 package.manifest_path.as_ref(),
+     322           0 :                 "--example",
+     323           0 :                 &target.name,
+     324           0 :                 "--verbose",
+     325           0 :             ])
+     326           0 :             .logged_output(true)?
+     327             :     };
+     328             : 
+     329           0 :     let matches = output
+     330           0 :         .stderr
+     331           0 :         .lines()
+     332           0 :         .map(|line| {
+     333           0 :             let line =
+     334           0 :                 line.with_context(|| format!("Could not read from `{}`", package.manifest_path))?;
+     335           0 :             Ok((*RE).captures(&line).and_then(|captures| {
+     336           0 :                 let args = captures[1]
+     337           0 :                     .split(' ')
+     338           0 :                     .map(ToOwned::to_owned)
+     339           0 :                     .collect::<Vec<_>>();
+     340           0 :                 if args.first().map_or(false, is_rustc)
+     341           0 :                     && args
+     342           0 :                         .as_slice()
+     343           0 :                         .windows(2)
+     344           0 :                         .any(|window| window == ["--crate-name", &snake_case(&target.name)])
+     345             :                 {
+     346           0 :                     Some(args)
+     347             :                 } else {
+     348           0 :                     None
+     349             :                 }
+     350           0 :             }))
+     351           0 :         })
+     352           0 :         .collect::<Result<Vec<Option<Vec<_>>>>>()?;
+     353             : 
+     354           0 :     let mut matches = matches.into_iter().flatten().collect::<Vec<Vec<_>>>();
+     355           0 :     ensure!(
+     356           0 :         matches.len() <= 1,
+     357           0 :         "Found multiple `rustc` invocations for `{}`",
+     358             :         target.name
+     359             :     );
+     360           0 :     matches
+     361           0 :         .pop()
+     362           0 :         .ok_or_else(|| anyhow!("Found no `rustc` invocations for `{}`", target.name))
+     363           0 : }
+     364             : 
+     365           0 : fn remove_example(metadata: &Metadata, _package: &Package, target: &Target) -> Result<()> {
+     366           0 :     let examples = metadata.target_directory.join("debug/examples");
+     367           0 :     for entry in
+     368           0 :         read_dir(&examples).with_context(|| format!("`read_dir` failed for `{examples}`"))?
+     369             :     {
+     370           0 :         let entry = entry.with_context(|| format!("`read_dir` failed for `{examples}`"))?;
+     371           0 :         let path = entry.path();
+     372             : 
+     373           0 :         if let Some(file_name) = path.file_name() {
+     374           0 :             let s = file_name.to_string_lossy();
+     375           0 :             let target_name = snake_case(&target.name);
+     376           0 :             if s == target_name.clone() + consts::EXE_SUFFIX
+     377           0 :                 || s.starts_with(&(target_name.clone() + "-"))
+     378             :             {
+     379           0 :                 remove_file(&path).with_context(|| {
+     380           0 :                     format!("`remove_file` failed for `{}`", path.to_string_lossy())
+     381           0 :                 })?;
+     382           0 :             }
+     383           0 :         }
+     384             :     }
+     385             : 
+     386           0 :     Ok(())
+     387           0 : }
+     388             : 
+     389           0 : fn next<I, T>(flag: &str, iter: &mut I) -> Result<T>
+     390           0 : where
+     391           0 :     I: Iterator<Item = T>,
+     392           0 : {
+     393           0 :     iter.next()
+     394           0 :         .ok_or_else(|| anyhow!("Missing argument for `{}`", flag))
+     395           0 : }
+     396             : 
+     397           0 : fn copy_with_extension<P: AsRef<Path>, Q: AsRef<Path>>(
+     398           0 :     from: P,
+     399           0 :     to: Q,
+     400           0 :     extension: &str,
+     401           0 : ) -> Result<u64> {
+     402           0 :     let from = from.as_ref().with_extension(extension);
+     403           0 :     let to = to.as_ref().with_extension(extension);
+     404           0 :     copy(from, to).map_err(Into::into)
+     405           0 : }
+     406             : 
+     407             : static MUTEX: Mutex<()> = Mutex::new(());
+     408             : 
+     409           0 : fn run_tests(driver: &Path, src_base: &Path, config: &ui::Config) {
+     410           0 :     let _lock = MUTEX.lock().unwrap();
+     411           0 : 
+     412           0 :     // smoelius: There doesn't seem to be a way to set environment variables using `compiletest`'s
+     413           0 :     // [`Config`](https://docs.rs/compiletest_rs/0.7.1/compiletest_rs/common/struct.Config.html)
+     414           0 :     // struct. For comparison, where Clippy uses `compiletest`, it sets environment variables
+     415           0 :     // directly (see: https://github.com/rust-lang/rust-clippy/blob/master/tests/compile-test.rs).
+     416           0 :     //
+     417           0 :     // Of course, even if `compiletest` had such support, it would need to be incorporated into
+     418           0 :     // `dylint_testing`.
+     419           0 : 
+     420           0 :     let _var = config
+     421           0 :         .dylint_toml
+     422           0 :         .as_ref()
+     423           0 :         .map(|value| VarGuard::set(env::DYLINT_TOML, value));
+     424             : 
+     425           0 :     let config = compiletest::Config {
+     426           0 :         mode: compiletest::common::Mode::Ui,
+     427           0 :         rustc_path: driver.to_path_buf(),
+     428           0 :         src_base: src_base.to_path_buf(),
+     429           0 :         target_rustcflags: Some(
+     430           0 :             config.rustc_flags.clone().join(" ")
+     431           0 :                 + " --emit=metadata"
+     432           0 :                 + if cfg!(feature = "deny_warnings") {
+     433           0 :                     " -Dwarnings"
+     434             :                 } else {
+     435           0 :                     ""
+     436             :                 }
+     437           0 :                 + " -Zui-testing",
+     438           0 :         ),
+     439           0 :         ..compiletest::Config::default()
+     440           0 :     };
+     441           0 : 
+     442           0 :     compiletest::run_tests(&config);
+     443           0 : }
+     444             : 
+     445             : // smoelius: `VarGuard` was copied from:
+     446             : // https://github.com/rust-lang/rust-clippy/blob/9cc8da222b3893bc13bc13c8827e93f8ea246854/tests/compile-test.rs
+     447             : 
+     448             : /// Restores an env var on drop
+     449             : #[must_use]
+     450             : struct VarGuard {
+     451             :     key: &'static str,
+     452             :     value: Option<OsString>,
+     453             : }
+     454             : 
+     455             : impl VarGuard {
+     456           0 :     fn set(key: &'static str, val: impl AsRef<OsStr>) -> Self {
+     457           0 :         let value = var_os(key);
+     458           0 :         set_var(key, val);
+     459           0 :         Self { key, value }
+     460           0 :     }
+     461             : }
+     462             : 
+     463             : impl Drop for VarGuard {
+     464           0 :     fn drop(&mut self) {
+     465           0 :         match self.value.as_deref() {
+     466           0 :             None => remove_var(self.key),
+     467           0 :             Some(value) => set_var(self.key, value),
+     468             :         }
+     469           0 :     }
+     470             : }
+     471             : 
+     472           0 : fn snake_case(name: &str) -> String {
+     473           0 :     name.replace('-', "_")
+     474           0 : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/utils/testing/src/ui.rs.func-sort-c.html b/coverage/utils/testing/src/ui.rs.func-sort-c.html new file mode 100644 index 000000000..173245d5e --- /dev/null +++ b/coverage/utils/testing/src/ui.rs.func-sort-c.html @@ -0,0 +1,108 @@ + + + + + + + LCOV - unnamed - utils/testing/src/ui.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - utils/testing/src - ui.rs (source / functions)HitTotalCoverage
Test:unnamedLines:0600.0 %
Date:2024-09-27 12:58:08Functions:090.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<dylint_testing::ui::Test>::dylint_toml::<_>0
<dylint_testing::ui::Test>::example0
<dylint_testing::ui::Test>::examples0
<dylint_testing::ui::Test>::new0
<dylint_testing::ui::Test>::run0
<dylint_testing::ui::Test>::run_immutable0
<dylint_testing::ui::Test>::rustc_flags::<_0
<dylint_testing::ui::Test>::src_base::<_>0
dylint_testing::ui::test::rustc_flags0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/utils/testing/src/ui.rs.func.html b/coverage/utils/testing/src/ui.rs.func.html new file mode 100644 index 000000000..3bb935d12 --- /dev/null +++ b/coverage/utils/testing/src/ui.rs.func.html @@ -0,0 +1,108 @@ + + + + + + + LCOV - unnamed - utils/testing/src/ui.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - utils/testing/src - ui.rs (source / functions)HitTotalCoverage
Test:unnamedLines:0600.0 %
Date:2024-09-27 12:58:08Functions:090.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
<dylint_testing::ui::Test>::dylint_toml::<_>0
<dylint_testing::ui::Test>::example0
<dylint_testing::ui::Test>::examples0
<dylint_testing::ui::Test>::new0
<dylint_testing::ui::Test>::run0
<dylint_testing::ui::Test>::run_immutable0
<dylint_testing::ui::Test>::rustc_flags::<_0
<dylint_testing::ui::Test>::src_base::<_>0
dylint_testing::ui::test::rustc_flags0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/utils/testing/src/ui.rs.gcov.html b/coverage/utils/testing/src/ui.rs.gcov.html new file mode 100644 index 000000000..bbd722999 --- /dev/null +++ b/coverage/utils/testing/src/ui.rs.gcov.html @@ -0,0 +1,198 @@ + + + + + + + LCOV - unnamed - utils/testing/src/ui.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - utils/testing/src - ui.rs (source / functions)HitTotalCoverage
Test:unnamedLines:0600.0 %
Date:2024-09-27 12:58:08Functions:090.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : use crate::{example_target, example_targets, initialize, run_example_test, run_tests};
+       2             : use std::{
+       3             :     env::current_dir,
+       4             :     path::{Path, PathBuf},
+       5             : };
+       6             : 
+       7             : enum Target {
+       8             :     SrcBase(PathBuf),
+       9             :     Example(String),
+      10             :     Examples,
+      11             : }
+      12             : 
+      13             : #[derive(Clone, Default)]
+      14             : pub(super) struct Config {
+      15             :     pub(super) rustc_flags: Vec<String>,
+      16             :     pub(super) dylint_toml: Option<String>,
+      17             : }
+      18             : 
+      19             : /// Test builder
+      20             : pub struct Test {
+      21             :     name: String,
+      22             :     target: Target,
+      23             :     config: Config,
+      24             : }
+      25             : 
+      26             : impl Test {
+      27             :     /// Test a library on all source files in a directory (similar to [`ui_test`]).
+      28             :     ///
+      29             :     /// [`ui_test`]: crate::ui_test
+      30             :     #[must_use]
+      31           0 :     pub fn src_base(name: &str, src_base: impl AsRef<Path>) -> Self {
+      32           0 :         Self::new(name, Target::SrcBase(src_base.as_ref().to_owned()))
+      33           0 :     }
+      34             : 
+      35             :     /// Test a library on one example target (similar to [`ui_test_example`]).
+      36             :     ///
+      37             :     /// [`ui_test_example`]: crate::ui_test_example
+      38             :     #[must_use]
+      39           0 :     pub fn example(name: &str, example: &str) -> Self {
+      40           0 :         Self::new(name, Target::Example(example.to_owned()))
+      41           0 :     }
+      42             : 
+      43             :     /// Test a library on all example targets (similar to [`ui_test_examples`]).
+      44             :     ///
+      45             :     /// [`ui_test_examples`]: crate::ui_test_examples
+      46             :     #[must_use]
+      47           0 :     pub fn examples(name: &str) -> Self {
+      48           0 :         Self::new(name, Target::Examples)
+      49           0 :     }
+      50             : 
+      51             :     /// Pass flags to the compiler when running the test.
+      52           0 :     pub fn rustc_flags(
+      53           0 :         &mut self,
+      54           0 :         rustc_flags: impl IntoIterator<Item = impl AsRef<str>>,
+      55           0 :     ) -> &mut Self {
+      56           0 :         self.config
+      57           0 :             .rustc_flags
+      58           0 :             .extend(rustc_flags.into_iter().map(|s| s.as_ref().to_owned()));
+      59           0 :         self
+      60           0 :     }
+      61             : 
+      62             :     /// Set the `dylint.toml` file's contents (for testing configurable libraries).
+      63           0 :     pub fn dylint_toml(&mut self, dylint_toml: impl AsRef<str>) -> &mut Self {
+      64           0 :         self.config.dylint_toml = Some(dylint_toml.as_ref().to_owned());
+      65           0 :         self
+      66           0 :     }
+      67             : 
+      68             :     /// Run the test.
+      69             :     #[allow(clippy::needless_pass_by_ref_mut)]
+      70           0 :     pub fn run(&mut self) {
+      71           0 :         self.run_immutable();
+      72           0 :     }
+      73             : 
+      74           0 :     fn new(name: &str, target: Target) -> Self {
+      75           0 :         Self {
+      76           0 :             name: name.to_owned(),
+      77           0 :             target,
+      78           0 :             config: Config::default(),
+      79           0 :         }
+      80           0 :     }
+      81             : 
+      82           0 :     fn run_immutable(&self) {
+      83           0 :         let driver = initialize(&self.name).unwrap();
+      84           0 : 
+      85           0 :         match &self.target {
+      86           0 :             Target::SrcBase(src_base) => {
+      87           0 :                 run_tests(driver, src_base, &self.config);
+      88           0 :             }
+      89           0 :             Target::Example(example) => {
+      90           0 :                 let metadata = dylint_internal::cargo::current_metadata().unwrap();
+      91           0 :                 let current_dir = current_dir().unwrap();
+      92           0 :                 let package =
+      93           0 :                     dylint_internal::cargo::package_with_root(&metadata, &current_dir).unwrap();
+      94           0 :                 let target = example_target(&package, example).unwrap();
+      95           0 : 
+      96           0 :                 run_example_test(driver, &metadata, &package, &target, &self.config).unwrap();
+      97           0 :             }
+      98             :             Target::Examples => {
+      99           0 :                 let metadata = dylint_internal::cargo::current_metadata().unwrap();
+     100           0 :                 let current_dir = current_dir().unwrap();
+     101           0 :                 let package =
+     102           0 :                     dylint_internal::cargo::package_with_root(&metadata, &current_dir).unwrap();
+     103           0 :                 let targets = example_targets(&package).unwrap();
+     104             : 
+     105           0 :                 for target in targets {
+     106           0 :                     run_example_test(driver, &metadata, &package, &target, &self.config).unwrap();
+     107           0 :                 }
+     108             :             }
+     109             :         }
+     110           0 :     }
+     111             : }
+     112             : 
+     113             : #[cfg(test)]
+     114             : mod test {
+     115             :     use super::*;
+     116             : 
+     117             :     // smoelius: Verify that `rustc_flags` compiles when used as intended.
+     118             :     #[allow(dead_code)]
+     119           0 :     fn rustc_flags() {
+     120           0 :         let _ = Test::src_base("name", PathBuf::new()).rustc_flags(["--test"]);
+     121           0 :     }
+     122             : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + +