1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
use super::super::FfiBackend;
use super::common::*;
use crate::core::backend::Backend;
use crate::core::ir::*;
/// The emitted `lib.rs`'s crate-level `#![allow(...)]` list was audited against a real
/// `cargo clippy --all-targets -- -D warnings` run over an emitted tree (see
/// `tests/generated_output_downstream_gate.rs`), removing entries that never fired. This
/// pins the ones removed so they cannot silently return -- if one of them becomes
/// load-bearing again, the fix belongs at the emitter or per-item allow, not here. ~keep
#[test]
fn crate_level_allow_list_does_not_carry_dead_entries() {
let api = ApiSurface {
crate_name: "sample_lib".to_string(),
version: "0.1.0".to_string(),
functions: vec![FunctionDef {
name: "run".to_string(),
rust_path: "sample_lib::run".to_string(),
return_type: TypeRef::Unit,
..FunctionDef::default()
}],
..ApiSurface::default()
};
let config = resolved_one(
r#"
[workspace]
languages = ["ffi"]
[[crates]]
name = "sample-lib"
sources = ["src/lib.rs"]
[crates.ffi]
prefix = "sample"
"#,
);
let files = FfiBackend.generate_bindings(&api, &config).unwrap();
let lib = files.iter().find(|file| file.path.ends_with("lib.rs")).unwrap();
let header_end = lib.content.find("use std::ffi").unwrap_or(lib.content.len());
let header = &lib.content[..header_end];
assert!(
!header.contains("missing_docs"),
"missing_docs is allow-by-default under rustc and is never escalated by -D warnings \
alone, so the crate-level allow was a no-op:\n{header}"
);
assert!(
!header.contains("clippy::too_many_arguments"),
"too_many_arguments already gets a per-item #[allow] at every site that can exceed \
the threshold (free functions, len companions, method wrappers, constructors, field \
accessors), so the crate-level copy was redundant:\n{header}"
);
assert!(
!header.contains("clippy::useless_conversion"),
"useless_conversion's only source is the Vec<u8>::from(..) polymorphic bytes \
conversion in bytes_result_match.jinja, which now carries its own narrow \
#[allow(clippy::useless_conversion)] at each of its four sites:\n{header}"
);
// `unnecessary_cast` fires only when a cast's source expression already has the exact
// destination type. Every `as i32`/`as u32`/`as usize` this backend emits casts a `bool`
// or a genuine `Named` enum field (see `ffi_visitor_context_enum_init.jinja`, reached only
// when `context_c_type` (`gen_visitor/context.rs`) resolves the field to a real IR enum --
// never when the field is already `TypeRef::Primitive(I32)`, which routes through the
// cast-free passthrough template instead) or an integer of a different width
// (`handle_registry.rs.jinja`'s `u64 -> usize`/`u64 -> u32`). None of those is ever the
// same type as the cast target, so clippy can never see this as redundant. Verified against
// a real `cargo clippy --all-targets -- -D warnings` run over the non-visitor emitted tree
// (`tests/generated_output_downstream_gate.rs`'s fixture) and, for the enum-context site
// specifically, over a real `alef generate` run with a configured trait bridge --
// `gen_bindings::tests::visitor::test_visitor_callbacks_emit_enum_node_type_as_i32` pins
// that this backend still reaches and emits that exact cast. ~keep
assert!(
!header.contains("clippy::unnecessary_cast"),
"every cast this backend emits converts a bool or a Named enum to a different \
primitive type, which clippy's same-type check can never flag as redundant:\n{header}"
);
// `dropping_references` fires only when `drop(...)`'s argument is itself a reference
// (`&T`/`&mut T`); dropping a reference is a no-op the lint exists to catch. Every explicit
// `drop(...)` this backend emits drops an owned value instead: `free_bytes.jinja`'s
// `Box::<[u8]>::from_raw(..)`, `free_string.jinja`'s `CString::from_raw(..)`,
// `handle_registry.rs.jinja`'s `self.take::<T>(handle)?` and `guard` (an owned
// `MutexGuard`, not a borrow of one), and `orchestration.rs`'s `std::mem::drop(obj)` for a
// method literally named `drop`, where `obj` comes from `null_check_self_owned.jinja`'s
// `take_handle::<T>(this)` -- an owned `T`, never a reference binding. No template or
// generator path in this backend ever passes a reference to `drop(...)`, so the entry never
// had anything to allow. Confirmed with a real `cargo clippy --all-targets -- -D warnings`
// run over the gate fixture (`tests/generated_output_downstream_gate.rs`) with the entry
// removed: no new warning appeared. Removed and pinned here per this test's own contract. ~keep
assert!(
!header.contains("dropping_references"),
"every drop(...) this backend emits drops an owned value, never a reference, so the \
crate-level allow was a no-op:\n{header}"
);
}
/// The paired positive: the narrow per-item allow this audit added actually reaches the
/// generated bytes-conversion call site.
#[test]
fn bytes_result_conversion_carries_its_own_narrow_useless_conversion_allow() {
let api = ApiSurface {
crate_name: "sample_lib".to_string(),
version: "0.1.0".to_string(),
functions: vec![FunctionDef {
name: "render".to_string(),
rust_path: "sample_lib::render".to_string(),
return_type: TypeRef::Bytes,
error_type: Some("String".to_string()),
..FunctionDef::default()
}],
..ApiSurface::default()
};
let config = resolved_one(
r#"
[workspace]
languages = ["ffi"]
[[crates]]
name = "sample-lib"
sources = ["src/lib.rs"]
[crates.ffi]
prefix = "sample"
"#,
);
let files = FfiBackend.generate_bindings(&api, &config).unwrap();
let lib = files.iter().find(|file| file.path.ends_with("lib.rs")).unwrap();
assert!(
lib.content
.contains("#[allow(clippy::useless_conversion)]\n let buffer = Vec::<u8>::from(val)"),
"the bytes-conversion call site must keep its own narrow allow now that the \
crate-level one is gone:\n{}",
lib.content
);
}