wowlab_tidy/languages/toml/rules/cargo/
proc_macro_crate_helper.rs1#[cfg(test)]
2use googletest::prelude::*;
3
4use super::{
5 assignment_line, cargo_document, dependency_tables, is_cargo_manifest, resolved_dependency_name,
6};
7use crate::{Example, TomlCtx, Violation, violation};
8
9const HELPER_CRATE: &str = "proc-macro-crate";
10
11#[rustfmt::skip]
12const EXAMPLES: &[Example] = &[
13 Example { label: "ordinary proc macro deps", code: "[dependencies]\nproc-macro2 = \"1\"\nquote = \"1\"\nsyn = \"2\"\n", pass: true },
14 Example { label: "no dependencies", code: "[package]\nname = \"foo\"\n", pass: true },
15 Example { label: "direct dependency", code: "[dependencies]\nproc-macro-crate = \"3\"\n", pass: false },
16 Example { label: "renamed dependency", code: "[dependencies]\npmc = { package = \"proc-macro-crate\", version = \"3\" }\n", pass: false },
17 Example { label: "dev dependency", code: "[dev-dependencies]\nproc-macro-crate = \"3\"\n", pass: false },
18];
19
20crate::toml_rule!(
21 toml_cargo_proc_macro_crate_helper,
22 "Ban the proc-macro-crate helper dependency in Cargo manifests.",
23 "Macros should assume they are used through their main crate and emit main-crate paths; supporting renamed or indirect imports is not worth the complexity (M-MACRO-MAIN-CRATE).",
24 Low,
25);
26
27fn check_toml_cargo_proc_macro_crate_helper(ctx: &TomlCtx<'_>) -> Vec<Violation> {
28 if !is_cargo_manifest(ctx.file.rel) {
29 return Vec::new();
30 }
31
32 let Some(document) = cargo_document(ctx) else {
33 return Vec::new();
34 };
35
36 let dependencies = dependency_tables(&document)
37 .into_iter()
38 .flat_map(|table| table.iter())
39 .filter(|(key, value)| resolved_dependency_name(key, value) == HELPER_CRATE);
40
41 dependencies
42 .map(|(key, _)| {
43 violation(
44 ctx.file.rel,
45 assignment_line(ctx.file.lines, key),
46 "depends on proc-macro-crate; macros must emit main-crate paths instead of supporting renamed imports",
47 )
48 })
49 .collect()
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55
56 fn run(source: &str) -> Vec<Violation> {
57 crate::test_support::check_source_toml_at(
58 "crates/foo/Cargo.toml",
59 source,
60 check_toml_cargo_proc_macro_crate_helper,
61 )
62 }
63
64 crate::example_tests!(EXAMPLES, check_toml_cargo_proc_macro_crate_helper);
65
66 #[gtest]
67 fn flags_target_specific_dependency() -> Result<()> {
68 let violations = run("[target.'cfg(windows)'.dependencies]\nproc-macro-crate = \"3\"\n");
69
70 verify_eq!(violations.len(), 1)?;
71
72 Ok(())
73 }
74}