diff --git a/.gitignore b/.gitignore index cd5597e6..456bf1eb 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ .vscode/ .idea/ cobertura.xml +cargo-geiger/tests/snapshots/*.new diff --git a/Cargo.lock b/Cargo.lock index 52d5c964..926ced8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -292,7 +292,7 @@ dependencies = [ "serde_json", "sha1", "shell-escape", - "syn 2.0.40", + "syn 2.0.60", "tar", "tempfile", "time", @@ -365,7 +365,7 @@ dependencies = [ "cargo-geiger-serde", "cargo-platform", "cargo-util", - "cargo_metadata 0.18.1", + "cargo_metadata", "colored", "console", "fs_extra", @@ -442,20 +442,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "cargo_metadata" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", - "thiserror", -] - [[package]] name = "cc" version = "1.0.83" @@ -1017,7 +1003,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.60", ] [[package]] @@ -1063,7 +1049,7 @@ dependencies = [ "cargo-geiger-serde", "proc-macro2", "rstest", - "syn 1.0.109", + "syn 2.0.60", "tempfile", ] @@ -1475,7 +1461,7 @@ checksum = "02a5bcaf6704d9354a3071cede7e77d366a5980c7352e102e2c2f9b645b1d3ae" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.60", ] [[package]] @@ -2043,7 +2029,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a857d4b6450fbc2b85c03684b2beae51916a5a90e2fb5f9c2b8acc920ad29e49" dependencies = [ - "cargo_metadata 0.15.4", + "cargo_metadata", "cfg-expr", "petgraph", "semver", @@ -2319,7 +2305,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.60", ] [[package]] @@ -2559,9 +2545,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" dependencies = [ "unicode-ident", ] @@ -2588,9 +2574,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -2748,7 +2734,7 @@ dependencies = [ "regex", "relative-path", "rustc_version", - "syn 2.0.40", + "syn 2.0.60", "unicode-ident", ] @@ -2911,7 +2897,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.60", ] [[package]] @@ -3091,9 +3077,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.40" +version = "2.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13fa70a4ee923979ffb522cacce59d34421ebdea5625e1073c4326ef9d2dd42e" +checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" dependencies = [ "proc-macro2", "quote", @@ -3156,7 +3142,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.60", ] [[package]] @@ -3268,7 +3254,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.60", ] [[package]] @@ -3446,7 +3432,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.60", "wasm-bindgen-shared", ] @@ -3468,7 +3454,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.60", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/cargo-geiger/Cargo.toml b/cargo-geiger/Cargo.toml index 7c3b11fc..2311e098 100644 --- a/cargo-geiger/Cargo.toml +++ b/cargo-geiger/Cargo.toml @@ -17,7 +17,7 @@ maintenance = { status = "experimental" } anyhow = "1.0.70" cargo = "0.75.1" cargo-geiger-serde = { path = "../cargo-geiger-serde", version = "0.2.3" } -cargo_metadata = "0.18.1" +cargo_metadata = "0.15.4" cargo-platform = "0.1.2" colored = "2.0.0" console = "0.15.5" diff --git a/cargo-geiger/src/mapping/geiger.rs b/cargo-geiger/src/mapping/geiger.rs index 2f40ce0f..978ede71 100644 --- a/cargo-geiger/src/mapping/geiger.rs +++ b/cargo-geiger/src/mapping/geiger.rs @@ -114,10 +114,10 @@ mod geiger_tests { } ), case( - "git+https://github.com/rust-itertools/itertools.git?rev=8761fbefb3b209", + "git+https://github.com/rust-itertools/itertools.git?rev=98d3978", CargoGeigerSerdeSource::Git { url: Url::parse("https://github.com/rust-itertools/itertools.git").unwrap(), - rev: String::from("8761fbefb3b209") + rev: String::from("98d3978") } ), case( diff --git a/cargo-geiger/src/scan/rs_file/custom_executor.rs b/cargo-geiger/src/scan/rs_file/custom_executor.rs index f8402894..bffbb657 100644 --- a/cargo-geiger/src/scan/rs_file/custom_executor.rs +++ b/cargo-geiger/src/scan/rs_file/custom_executor.rs @@ -27,9 +27,13 @@ pub struct CustomExecutor { #[derive(Debug)] enum CustomExecutorError { + #[allow(dead_code)] InnerContextMutex(String), + #[allow(dead_code)] Io(io::Error, PathBuf), + #[allow(dead_code)] OutDirKeyMissing(String), + #[allow(dead_code)] OutDirValueMissing(String), } diff --git a/cargo-geiger/tests/external_package_reports/mod.rs b/cargo-geiger/tests/external_package_reports/mod.rs index 006aa7a7..1acfc25d 100644 --- a/cargo-geiger/tests/external_package_reports/mod.rs +++ b/cargo-geiger/tests/external_package_reports/mod.rs @@ -114,11 +114,11 @@ pub fn doc_comment_safety_report() -> SafetyReport { pub fn itertools_package_id() -> PackageId { PackageId { name: "itertools".into(), - version: Version::new(0, 8, 0), + version: Version::new(0, 12, 1), source: Source::Git { url: Url::parse("https://github.com/rust-itertools/itertools.git") .unwrap(), - rev: "8761fbefb3b209".into(), + rev: "98d3978".into(), }, } } diff --git a/cargo-geiger/tests/integration_tests.rs b/cargo-geiger/tests/integration_tests.rs index 1b8e9e62..265f9d04 100644 --- a/cargo-geiger/tests/integration_tests.rs +++ b/cargo-geiger/tests/integration_tests.rs @@ -35,7 +35,7 @@ fn test_package(name: &str) { if !stderr.is_empty() { let manifest_path_regex = regex::Regex::new(r"`([^`]+).toml`").unwrap(); let artifact_json_blob_regex = - regex::Regex::new(r#"\{"artifact":.*"emit":.*\}"#).unwrap(); + regex::Regex::new(r#"\{"\$message_type":"artifact","artifact":.*"emit":.*\}"#).unwrap(); let stderr = manifest_path_regex.replace(&stderr, "`{MANIFEST_PATH}`"); let stderr = artifact_json_blob_regex diff --git a/cargo-geiger/tests/snapshots/integration_tests__test3_package_with_nested_deps.stdout.snap b/cargo-geiger/tests/snapshots/integration_tests__test3_package_with_nested_deps.stdout.snap index 96751aa1..31be33fc 100644 --- a/cargo-geiger/tests/snapshots/integration_tests__test3_package_with_nested_deps.stdout.snap +++ b/cargo-geiger/tests/snapshots/integration_tests__test3_package_with_nested_deps.stdout.snap @@ -16,12 +16,12 @@ Functions Expressions Impls Traits Methods Dependency 0/0 1/1 0/0 0/0 0/0 ! test3_package_with_nested_deps 0.1.0 0/0 0/0 0/0 0/0 0/0 ? ├── doc-comment 0.3.1 -0/0 0/72 0/3 0/1 0/3 ? ├── itertools 0.8.0 +0/0 13/83 0/3 0/1 0/3 ! ├── itertools 0.12.1 0/0 0/0 0/0 0/0 0/0 ? │ └── either 1.5.2 1/1 4/4 0/0 0/0 0/0 ! └── test2_package_with_shallow_deps 0.1.0 0/0 2/2 0/0 0/0 0/0 ! ├── ref_slice 1.1.1 1/1 2/2 0/0 0/0 0/0 ! └── test1_package_with_no_deps 0.1.0 -2/2 9/81 0/3 0/1 0/3 +2/2 22/92 0/3 0/1 0/3 diff --git a/cargo-geiger/tests/snapshots/integration_tests__test6_cargo_lock_out_of_date.stdout.snap b/cargo-geiger/tests/snapshots/integration_tests__test6_cargo_lock_out_of_date.stdout.snap index 2ad3825a..8b6bd0a4 100644 --- a/cargo-geiger/tests/snapshots/integration_tests__test6_cargo_lock_out_of_date.stdout.snap +++ b/cargo-geiger/tests/snapshots/integration_tests__test6_cargo_lock_out_of_date.stdout.snap @@ -22,8 +22,8 @@ Functions Expressions Impls Traits Methods Dependency 0/0 0/0 0/0 0/0 0/0 :) ├── unicode-bidi 0.3.4 0/0 0/0 0/0 0/0 0/0 ? │ └── matches 0.1.8 0/0 20/20 0/0 0/0 0/0 ! └── unicode-normalization 0.1.8 -2/2 354/354 4/4 1/1 13/13 ! └── smallvec 0.6.9 +2/2 349/349 4/4 1/1 13/13 ! └── smallvec 0.6.9 -2/2 375/375 4/4 1/1 13/13 +2/2 370/370 4/4 1/1 13/13 diff --git a/cargo-geiger/tests/snapshots/integration_tests__test9_package_with_git_deps.stdout.snap b/cargo-geiger/tests/snapshots/integration_tests__test9_package_with_git_deps.stdout.snap index acc8f890..a6c99d2f 100644 --- a/cargo-geiger/tests/snapshots/integration_tests__test9_package_with_git_deps.stdout.snap +++ b/cargo-geiger/tests/snapshots/integration_tests__test9_package_with_git_deps.stdout.snap @@ -15,10 +15,10 @@ Symbols: Functions Expressions Impls Traits Methods Dependency 0/0 0/0 0/0 0/0 0/0 ? test9_package_with_git_deps 0.1.0 -0/0 0/72 0/3 0/1 0/3 ? ├── itertools 0.8.0 -0/0 14/14 0/0 0/0 0/0 ! │ └── either 1.9.0 +0/0 13/83 0/3 0/1 0/3 ! ├── itertools 0.12.1 +0/0 14/14 0/0 0/0 0/0 ! │ └── either 1.11.0 0/0 2/2 0/0 0/0 0/0 ! └── ref_slice 1.2.1 -0/0 16/88 0/3 0/1 0/3 +0/0 29/99 0/3 0/1 0/3 diff --git a/cargo-geiger/tests/snapshots/readme_integration_tests__test3_package_with_nested_deps.readme.snap b/cargo-geiger/tests/snapshots/readme_integration_tests__test3_package_with_nested_deps.readme.snap index 0b319960..9b96ba6b 100644 --- a/cargo-geiger/tests/snapshots/readme_integration_tests__test3_package_with_nested_deps.readme.snap +++ b/cargo-geiger/tests/snapshots/readme_integration_tests__test3_package_with_nested_deps.readme.snap @@ -24,13 +24,13 @@ Functions Expressions Impls Traits Methods Dependency 0/0 1/1 0/0 0/0 0/0 ☢️ test3_package_with_nested_deps 0.1.0 0/0 0/0 0/0 0/0 0/0 ❓ ├── doc-comment 0.3.1 -0/0 0/72 0/3 0/1 0/3 ❓ ├── itertools 0.8.0 +0/0 13/83 0/3 0/1 0/3 ☢️ ├── itertools 0.12.1 0/0 0/0 0/0 0/0 0/0 ❓ │ └── either 1.5.2 1/1 4/4 0/0 0/0 0/0 ☢️ └── test2_package_with_shallow_deps 0.1.0 0/0 2/2 0/0 0/0 0/0 ☢️ ├── ref_slice 1.1.1 1/1 2/2 0/0 0/0 0/0 ☢️ └── test1_package_with_no_deps 0.1.0 -2/2 9/81 0/3 0/1 0/3 +2/2 22/92 0/3 0/1 0/3 ``` ## Second Section Header diff --git a/cargo-geiger/tests/snapshots/readme_integration_tests__test6_cargo_lock_out_of_date.readme.snap b/cargo-geiger/tests/snapshots/readme_integration_tests__test6_cargo_lock_out_of_date.readme.snap index 2d249579..36a76336 100644 --- a/cargo-geiger/tests/snapshots/readme_integration_tests__test6_cargo_lock_out_of_date.readme.snap +++ b/cargo-geiger/tests/snapshots/readme_integration_tests__test6_cargo_lock_out_of_date.readme.snap @@ -24,9 +24,9 @@ Functions Expressions Impls Traits Methods Dependency 0/0 0/0 0/0 0/0 0/0 🔒 ├── unicode-bidi 0.3.4 0/0 0/0 0/0 0/0 0/0 ❓ │ └── matches 0.1.8 0/0 20/20 0/0 0/0 0/0 ☢️ └── unicode-normalization 0.1.8 -2/2 354/354 4/4 1/1 13/13 ☢️ └── smallvec 0.6.9 +2/2 349/349 4/4 1/1 13/13 ☢️ └── smallvec 0.6.9 -2/2 375/375 4/4 1/1 13/13 +2/2 370/370 4/4 1/1 13/13 ``` diff --git a/geiger/Cargo.toml b/geiger/Cargo.toml index cec60c0b..73d99803 100644 --- a/geiger/Cargo.toml +++ b/geiger/Cargo.toml @@ -15,7 +15,7 @@ maintenance = { status = "experimental" } [dependencies] cargo-geiger-serde = { path = "../cargo-geiger-serde", version = "0.2.3" } -syn = { version = "1.0.109", features = ["parsing", "printing", "clone-impls", "full", "extra-traits", "visit"] } +syn = { version = "^2.0.60", features = ["parsing", "printing", "clone-impls", "full", "extra-traits", "visit"] } proc-macro2 = "1.0.78" [dev-dependencies] diff --git a/geiger/src/find.rs b/geiger/src/find.rs index f5981e5e..c5b5fd7c 100644 --- a/geiger/src/find.rs +++ b/geiger/src/find.rs @@ -38,14 +38,24 @@ mod find_tests { use super::*; use cargo_geiger_serde::{Count, CounterBlock}; - use rstest::*; - use std::io::Write; use tempfile::tempdir; + const DEFAULT_COUNTERS: CounterBlock = CounterBlock { + functions: Count { safe: 0, unsafe_: 0 }, + exprs: Count { safe: 0, unsafe_: 0 }, + item_impls: Count { safe: 0, unsafe_: 0 }, + item_traits: Count { safe: 0, unsafe_: 0 }, + methods: Count { safe: 0, unsafe_: 0 }, + }; + const DEFAULT_METRICS: RsFileMetrics = RsFileMetrics { + counters: DEFAULT_COUNTERS, + forbids_unsafe: false, + }; + const FILE_CONTENT_STRING: &str = "use std::io::Write; pub unsafe fn f() { - unimplemented!() + f(); } pub fn g() { @@ -56,12 +66,12 @@ pub fn g() { #[no_mangle] pub fn h() { - unimplemented!() + f(); } #[export_name = \"exported_g\"] pub fn g() { - unimplemented!() + f(); } #[cfg(test)] @@ -71,162 +81,138 @@ mod tests { #[test] fn test_1() { unsafe { - println!(\"Inside unsafe\"); + f(); } } } "; - #[rstest( - input_include_tests, - expected_rs_file_metrics, - case( - IncludeTests::Yes, - RsFileMetrics { + #[test] + fn find_unsafe() { + let temp_dir = tempdir().unwrap(); + let file_path = temp_dir.path().join("lib.rs"); + std::fs::write(&file_path, FILE_CONTENT_STRING).unwrap(); + + let from_file = + find_unsafe_in_file(&file_path, IncludeTests::No).unwrap(); + let from_string = + find_unsafe_in_string(FILE_CONTENT_STRING, IncludeTests::No).unwrap(); + let expected = RsFileMetrics { counters: CounterBlock { - functions: Count { - safe: 2, - unsafe_: 3 - }, - exprs: Count { - safe: 4, - unsafe_: 5 - }, - item_impls: Count { - safe: 0, - unsafe_: 0 - }, - item_traits: Count { - safe: 0, - unsafe_: 0 - }, - methods: Count { - safe: 0, - unsafe_: 0 - } + functions: Count { safe: 1, unsafe_: 3 }, + exprs: Count { safe: 4, unsafe_: 4 }, + ..DEFAULT_COUNTERS }, - forbids_unsafe: false - } - ), - case( - IncludeTests::No, - RsFileMetrics { - counters: CounterBlock { - functions: Count { - safe: 1, - unsafe_: 3 - }, - exprs: Count { - safe: 4, - unsafe_: 4 - }, - item_impls: Count { - safe: 0, - unsafe_: 0 - }, - item_traits: Count { - safe: 0, - unsafe_: 0 - }, - methods: Count { - safe: 0, - unsafe_: 0 - } - }, - forbids_unsafe: false - } - ) - )] - fn find_unsafe_in_file_test_no_errors( - input_include_tests: IncludeTests, - expected_rs_file_metrics: RsFileMetrics, - ) { - let temp_dir = tempdir().unwrap(); - let lib_file_path = temp_dir.path().join("lib.rs"); - let mut file = File::create(lib_file_path.clone()).unwrap(); - - writeln!(file, "{}", FILE_CONTENT_STRING).unwrap(); - - let unsafe_in_file_result = - find_unsafe_in_file(&lib_file_path, input_include_tests); + ..DEFAULT_METRICS + }; + assert_eq!(from_file, expected); + assert_eq!(from_string, expected); + + let from_file = + find_unsafe_in_file(&file_path, IncludeTests::Yes).unwrap(); + let from_string = + find_unsafe_in_string(FILE_CONTENT_STRING, IncludeTests::Yes).unwrap(); + let expected = RsFileMetrics { + counters: CounterBlock { + functions: Count { safe: 2, unsafe_: 3 }, + exprs: Count { safe: 4, unsafe_: 5 }, + ..DEFAULT_COUNTERS + }, + ..DEFAULT_METRICS + }; + assert_eq!(from_file, expected); + assert_eq!(from_string, expected); + } - assert!(unsafe_in_file_result.is_ok()); + #[test] + fn forbids_unsafe() { + let expected = RsFileMetrics { forbids_unsafe: true, ..DEFAULT_METRICS }; + let actual = find_unsafe_in_string("#![forbid(unsafe_code)]", IncludeTests::No).unwrap(); + assert_eq!(actual, expected); + } - let unsafe_in_file = unsafe_in_file_result.unwrap(); + #[test] + fn counters_functions() { + let expected = RsFileMetrics { + counters: CounterBlock { + functions: Count { safe: 2, unsafe_: 3 }, + exprs: Count { safe: 2, unsafe_: 3 }, + ..DEFAULT_COUNTERS + }, + ..DEFAULT_METRICS + }; + let file = " + pub fn f() { f(); } + pub fn f() { f(); } + pub unsafe fn f() { f(); } + #[no_mangle] + pub fn f() { f(); } + #[export_name = \"exported_e\"] + pub unsafe fn f() { f(); } + "; + let actual = find_unsafe_in_string(file, IncludeTests::No).unwrap(); + assert_eq!(actual, expected); + } - assert_eq!(unsafe_in_file, expected_rs_file_metrics); + #[test] + fn counters_exprs() { + let file = " + pub fn f() { + f(); + x.f(); + let x = *y; + println!(\"abc\"); // The `syn` crate v2.0.60 doesn't visit macros. + let x = 1; // Literal expressions are not counted. + } + pub fn f() { unsafe { let x = f(); } } + pub unsafe fn f() { let x = f(); } + #[cfg(test)] + mod tests { + pub fn f() { f(); } + } + #[test] + pub fn f() { f(); } + "; + let expected = RsFileMetrics { + counters: CounterBlock { + functions: Count { safe: 2, unsafe_: 1 }, + exprs: Count { safe: 3, unsafe_: 2 }, + ..DEFAULT_COUNTERS + }, + ..DEFAULT_METRICS + }; + let actual = find_unsafe_in_string(file, IncludeTests::No).unwrap(); + assert_eq!(actual, expected); } - #[rstest( - input_include_tests, - expected_rs_file_metrics, - case( - IncludeTests::Yes, - RsFileMetrics { - counters: CounterBlock { - functions: Count { - safe: 2, - unsafe_: 3 - }, - exprs: Count { - safe: 4, - unsafe_: 5 - }, - item_impls: Count { - safe: 0, - unsafe_: 0 - }, - item_traits: Count { - safe: 0, - unsafe_: 0 - }, - methods: Count { - safe: 0, - unsafe_: 0 - } - }, - forbids_unsafe: false + #[test] + fn counters_exprs_include_tests() { + let file = " + pub fn f() { f(); } + pub unsafe fn f() { f(); } + #[cfg(test)] + mod tests { + pub unsafe fn f() { f(); } + pub fn f() { + f(); + unsafe { f(); } + } } - ), - case( - IncludeTests::No, - RsFileMetrics { - counters: CounterBlock { - functions: Count { - safe: 1, - unsafe_: 3 - }, - exprs: Count { - safe: 4, - unsafe_: 4 - }, - item_impls: Count { - safe: 0, - unsafe_: 0 - }, - item_traits: Count { - safe: 0, - unsafe_: 0 - }, - methods: Count { - safe: 0, - unsafe_: 0 - } - }, - forbids_unsafe: false + #[test] + pub fn f() { + f(); + unsafe { f(); } } - ) - )] - fn find_unsafe_in_string_test( - input_include_tests: IncludeTests, - expected_rs_file_metrics: RsFileMetrics, - ) { - let unsafe_in_string_result = - find_unsafe_in_string(FILE_CONTENT_STRING, input_include_tests); - - assert!(unsafe_in_string_result.is_ok()); - let unsafe_in_string = unsafe_in_string_result.unwrap(); - - assert_eq!(unsafe_in_string, expected_rs_file_metrics); + "; + let expected = RsFileMetrics { + counters: CounterBlock { + functions: Count { safe: 3, unsafe_: 2 }, + exprs: Count { safe: 3, unsafe_: 4 }, + ..DEFAULT_COUNTERS + }, + ..DEFAULT_METRICS + }; + let actual = find_unsafe_in_string(file, IncludeTests::Yes).unwrap(); + assert_eq!(actual, expected); } } diff --git a/geiger/src/geiger_syn_visitor.rs b/geiger/src/geiger_syn_visitor.rs index a9dea845..de83e655 100644 --- a/geiger/src/geiger_syn_visitor.rs +++ b/geiger/src/geiger_syn_visitor.rs @@ -3,7 +3,7 @@ use super::{ IncludeTests, RsFileMetrics, }; -use syn::{visit, Expr, ImplItemMethod, ItemFn, ItemImpl, ItemMod, ItemTrait}; +use syn::{visit, Expr, ItemFn, ItemImpl, ItemMod, ItemTrait, ImplItemFn, ExprUnsafe}; pub struct GeigerSynVisitor { /// Count unsafe usage inside tests @@ -43,7 +43,7 @@ impl GeigerSynVisitor { impl<'ast> visit::Visit<'ast> for GeigerSynVisitor { fn visit_file(&mut self, i: &'ast syn::File) { self.metrics.forbids_unsafe = file_forbids_unsafe(i); - syn::visit::visit_file(self, i); + visit::visit_file(self, i); } /// Free-standing functions @@ -66,25 +66,20 @@ impl<'ast> visit::Visit<'ast> for GeigerSynVisitor { fn visit_expr(&mut self, i: &Expr) { // Total number of expressions of any type match i { - Expr::Unsafe(i) => { - self.enter_unsafe_scope(); - visit::visit_expr_unsafe(self, i); - self.exit_unsafe_scope(); + Expr::Lit(..) | Expr::Path(..) | Expr::Unsafe(..) => { + // Do not count. } - Expr::Path(_) | Expr::Lit(_) => { - // Do not count. The expression `f(x)` should count as one - // expression, not three. - } - other => { - // TODO: Print something pretty here or gather the data for later - // printing. - // if self.verbosity == Verbosity::Verbose && self.unsafe_scopes > 0 { - // println!("{:#?}", other); - // } + _ => { self.metrics.counters.exprs.count(self.unsafe_scopes > 0); - visit::visit_expr(self, other); } } + visit::visit_expr(self, i); + } + + fn visit_expr_unsafe(&mut self, i: &ExprUnsafe) { + self.enter_unsafe_scope(); + visit::visit_expr_unsafe(self, i); + self.exit_unsafe_scope(); } fn visit_item_mod(&mut self, i: &ItemMod) { @@ -109,7 +104,7 @@ impl<'ast> visit::Visit<'ast> for GeigerSynVisitor { visit::visit_item_trait(self, i); } - fn visit_impl_item_method(&mut self, i: &ImplItemMethod) { + fn visit_impl_item_fn(&mut self, i: &ImplItemFn) { if i.sig.unsafety.is_some() { self.enter_unsafe_scope() } @@ -117,7 +112,7 @@ impl<'ast> visit::Visit<'ast> for GeigerSynVisitor { .counters .methods .count(i.sig.unsafety.is_some()); - visit::visit_impl_item_method(self, i); + visit::visit_impl_item_fn(self, i); if i.sig.unsafety.is_some() { self.exit_unsafe_scope() } diff --git a/geiger/src/lib.rs b/geiger/src/lib.rs index 98492bac..f166792c 100644 --- a/geiger/src/lib.rs +++ b/geiger/src/lib.rs @@ -18,7 +18,7 @@ use std::fmt; use std::io; use std::path::PathBuf; use std::string::FromUtf8Error; -use syn::{ItemFn, ItemMod}; +use syn::{AttrStyle, ItemFn, ItemMod}; #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum IncludeTests { @@ -54,54 +54,44 @@ impl fmt::Display for ScanFileError { } fn file_forbids_unsafe(f: &syn::File) -> bool { - use syn::AttrStyle; - use syn::Meta; - use syn::MetaList; - use syn::NestedMeta; - f.attrs - .iter() - .filter(|a| matches!(a.style, AttrStyle::Inner(_))) - .filter_map(|a| a.parse_meta().ok()) - .filter(|meta| match meta { - Meta::List(MetaList { - path, - paren_token: _paren, - nested, - }) => { - if !path.is_ident("forbid") { - return false; - } - nested.iter().any(|n| match n { - NestedMeta::Meta(Meta::Path(p)) => { - p.is_ident("unsafe_code") + f.attrs.iter().any(|attr|{ + // https://docs.rs/syn/latest/syn/meta/struct.ParseNestedMeta.html#example + let mut is_forbid_unsafe_code = false; + if matches!(attr.style, AttrStyle::Inner(_)) { // Parses `#!`. + if attr.path().is_ident("forbid") { // Parses `forbid`. + let _ = attr.parse_nested_meta(|meta| { // Parses `(`. + if meta.path.is_ident("unsafe_code") { + if meta.value().is_err() { + is_forbid_unsafe_code = true; + } } - _ => false, - }) + Ok(()) + }); } - _ => false, - }) - .count() - > 0 + } + is_forbid_unsafe_code + }) } fn is_test_fn(item_fn: &ItemFn) -> bool { - use syn::Attribute; item_fn .attrs .iter() - .flat_map(Attribute::parse_meta) - .any(|m| meta_contains_ident(&m, "test")) + .any(|attr| attr.path().is_ident("test")) } fn has_unsafe_attributes(item_fn: &ItemFn) -> bool { - use syn::Attribute; item_fn .attrs .iter() - .flat_map(Attribute::parse_meta) - .any(|m| { - meta_contains_ident(&m, "no_mangle") - || meta_contains_attribute(&m, "export_name") + .any(|attr| { + if attr.path().is_ident("no_mangle") { + return true; + } + if attr.path().is_ident("export_name") { + return true; + } + false }) } @@ -112,56 +102,20 @@ fn has_unsafe_attributes(item_fn: &ItemFn) -> bool { /// every single source file path and span within each source file and use that /// as a general filter for included code. /// TODO: Investigate if the needed information can be emitted by rustc today. -fn is_test_mod(i: &ItemMod) -> bool { - use syn::Attribute; - use syn::Meta; - i.attrs +fn is_test_mod(item: &ItemMod) -> bool { + item + .attrs .iter() - .flat_map(Attribute::parse_meta) - .any(|m| match m { - Meta::List(ml) => meta_list_is_cfg_test(&ml), - _ => false, + .any(|attr| { + let mut found_cfg_test = false; + if attr.path().is_ident("cfg") { + let _ = attr.parse_nested_meta(|meta| { // Parse `(`. + if meta.path.is_ident("test") { + found_cfg_test = true; + } + Ok(()) + }); + } + found_cfg_test }) } - -fn meta_contains_ident(m: &syn::Meta, ident: &str) -> bool { - use syn::Meta; - match m { - Meta::Path(p) => p.is_ident(ident), - _ => false, - } -} - -fn meta_contains_attribute(m: &syn::Meta, ident: &str) -> bool { - use syn::Meta; - match m { - Meta::NameValue(nv) => nv.path.is_ident(ident), - _ => false, - } -} - -// MetaList { -// ident: Ident( -// cfg -// ), -// paren_token: Paren, -// nested: [ -// Meta( -// Word( -// Ident( -// test -// ) -// ) -// ) -// ] -// } -fn meta_list_is_cfg_test(meta_list: &syn::MetaList) -> bool { - use syn::NestedMeta; - if !meta_list.path.is_ident("cfg") { - return false; - } - meta_list.nested.iter().any(|n| match n { - NestedMeta::Meta(meta) => meta_contains_ident(meta, "test"), - _ => false, - }) -} diff --git a/rust-toolchain b/rust-toolchain new file mode 100644 index 00000000..38ab2bd6 --- /dev/null +++ b/rust-toolchain @@ -0,0 +1 @@ +1.76 \ No newline at end of file diff --git a/test_crates/test3_package_with_nested_deps/Cargo.toml b/test_crates/test3_package_with_nested_deps/Cargo.toml index 67872541..fc0b910d 100644 --- a/test_crates/test3_package_with_nested_deps/Cargo.toml +++ b/test_crates/test3_package_with_nested_deps/Cargo.toml @@ -5,5 +5,5 @@ edition = "2018" [dependencies] doc-comment = "0.3.1" -itertools = { git = "https://github.com/rust-itertools/itertools.git", rev = "8761fbefb3b209" } +itertools = { git = "https://github.com/rust-itertools/itertools.git", rev = "98d3978" } test2_package_with_shallow_deps = { path = "../test2_package_with_shallow_deps" } diff --git a/test_crates/test9_package_with_git_deps/Cargo.toml b/test_crates/test9_package_with_git_deps/Cargo.toml index 9ae6cea6..d880a0c3 100644 --- a/test_crates/test9_package_with_git_deps/Cargo.toml +++ b/test_crates/test9_package_with_git_deps/Cargo.toml @@ -5,5 +5,5 @@ edition = "2018" [dependencies] ref_slice = { git = "https://github.com/steveklabnik/ref_slice.git" } -itertools = { git = "https://github.com/rust-itertools/itertools.git", rev = "8761fbefb3b209" } +itertools = { git = "https://github.com/rust-itertools/itertools.git", rev = "98d3978" } [workspace] \ No newline at end of file