Skip to content

Commit 5e4ed4f

Browse files
committed
Add special handling for proc macros to treat them as the build dependencies they are
1 parent d887374 commit 5e4ed4f

2 files changed

Lines changed: 36 additions & 4 deletions

File tree

cargo-auditable/src/auditable_from_metadata.rs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
//! Converts from `cargo_metadata` crate structs to `auditable-serde` structs,
22
//! which map to our own serialialized representation.
33
4-
use std::{cmp::min, cmp::Ordering::*, collections::HashMap, error::Error, fmt::Display};
4+
use std::{
5+
cmp::{min, Ordering::*},
6+
collections::{HashMap, HashSet},
7+
error::Error,
8+
fmt::Display,
9+
};
510

611
use auditable_serde::{DependencyKind, Package, Source, VersionInfo};
712

@@ -84,6 +89,8 @@ pub fn encode_audit_data(
8489
.repr
8590
.as_str();
8691

92+
let proc_macros = proc_macro_packages(metadata);
93+
8794
// Walk the dependency tree and resolve dependency kinds for each package.
8895
// We need this because there may be several different paths to the same package
8996
// and we need to aggregate dependency types across all of them.
@@ -103,8 +110,14 @@ pub fn encode_audit_data(
103110
let parent_dep_kind = id_to_dep_kind[parent.id.repr.as_str()];
104111
for child in &parent.deps {
105112
let child_id = child.pkg.repr.as_str();
106-
let dep_kind = strongest_dep_kind(child.dep_kinds.as_slice());
107-
let dep_kind = min(dep_kind, parent_dep_kind);
113+
let mut dep_kind = strongest_dep_kind(child.dep_kinds.as_slice());
114+
// If the parent is a build dependency that has a runtime dependency, overall dependency should be 'build'.
115+
// This propagates the dependency kinds that way from parent to child.
116+
dep_kind = min(dep_kind, parent_dep_kind);
117+
// proc macros require special handling since cargo_metadata reports them as normal deps
118+
if proc_macros.contains(child_id) {
119+
dep_kind = min(dep_kind, PrivateDepKind::Build);
120+
}
108121
let dep_kind_on_previous_visit = id_to_dep_kind.get(child_id);
109122
if dep_kind_on_previous_visit.is_none()
110123
|| &dep_kind > dep_kind_on_previous_visit.unwrap()
@@ -215,6 +228,25 @@ fn strongest_dep_kind(deps: &[cargo_metadata::DepKindInfo]) -> PrivateDepKind {
215228
.unwrap_or(PrivateDepKind::Runtime) // for compatibility with Rust earlier than 1.41
216229
}
217230

231+
fn proc_macro_packages(metadata: &cargo_metadata::Metadata) -> HashSet<&str> {
232+
metadata
233+
.packages
234+
.iter()
235+
.filter_map(|pkg| {
236+
// As of Rust 1.88 a single crate cannot be both a proc macro and something else.
237+
// Checking that length is 1 is purely to hedge against support for it being added in the future.
238+
if pkg.targets.len() == 1
239+
&& pkg.targets[0].kind.len() == 1
240+
&& pkg.targets[0].kind[0] == "proc-macro"
241+
{
242+
Some(pkg.id.repr.as_str())
243+
} else {
244+
None
245+
}
246+
})
247+
.collect()
248+
}
249+
218250
#[cfg(test)]
219251
mod tests {
220252
#![allow(unused_imports)] // otherwise conditional compilation emits warnings

cargo-auditable/tests/it.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -555,7 +555,7 @@ fn test_path_not_equal_name_inner(sbom: bool) {
555555

556556
#[test]
557557
fn test_proc_macro() {
558-
//test_proc_macro_inner(false); //TODO
558+
test_proc_macro_inner(false);
559559
test_proc_macro_inner(true);
560560
}
561561
fn test_proc_macro_inner(sbom: bool) {

0 commit comments

Comments
 (0)