Skip to content

Commit

Permalink
Add optional warnings for windows-bindgen to improve diagnostics (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
kennykerr authored Feb 20, 2025
1 parent e3a11cd commit ed36c28
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 15 deletions.
9 changes: 7 additions & 2 deletions crates/libs/bindgen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ mod type_name;
mod type_tree;
mod types;
mod value;
mod warnings;
mod winmd;
mod writer;

Expand All @@ -44,6 +45,7 @@ use type_name::*;
use type_tree::*;
use types::*;
use value::*;
pub use warnings::*;
use winmd::*;
use writer::*;
mod method_names;
Expand All @@ -64,11 +66,12 @@ struct Config {
pub implement: bool,
pub derive: Derive,
pub link: String,
pub warnings: WarningBuilder,
}

/// The Windows code generator.
#[track_caller]
pub fn bindgen<I, S>(args: I)
pub fn bindgen<I, S>(args: I) -> Warnings
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
Expand Down Expand Up @@ -201,6 +204,7 @@ where
sys,
implement,
link,
warnings: WarningBuilder::default(),
};

let tree = TypeTree::new(&config.types);
Expand All @@ -210,7 +214,8 @@ where
namespace: "",
};

writer.write(tree)
writer.write(tree);
config.warnings.build()
}

enum ArgKind {
Expand Down
5 changes: 5 additions & 0 deletions crates/libs/bindgen/src/types/cpp_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ impl CppInterface {
if method.dependencies.included(writer.config) {
CppMethodOrName::Method(method)
} else {
writer.config.warnings.skip_method(
method.def,
&method.dependencies,
writer.config,
);
CppMethodOrName::Name(method.def)
}
})
Expand Down
5 changes: 5 additions & 0 deletions crates/libs/bindgen/src/types/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ impl Interface {
if method.dependencies.included(writer.config) {
MethodOrName::Method(method)
} else {
writer.config.warnings.skip_method(
method.def,
&method.dependencies,
writer.config,
);
MethodOrName::Name(method.def)
}
})
Expand Down
65 changes: 65 additions & 0 deletions crates/libs/bindgen/src/warnings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
use super::*;
use std::sync::RwLock;

#[derive(Default)]
pub(crate) struct WarningBuilder(RwLock<Vec<String>>);

impl WarningBuilder {
pub fn build(self) -> Warnings {
Warnings(self.0.write().unwrap().split_off(0))
}

pub fn add(&self, message: String) {
self.0.write().unwrap().push(message);
}

pub fn skip_method(&self, method: MethodDef, dependencies: &TypeMap, config: &Config) {
let mut message = String::new();
writeln!(
&mut message,
"skipping `{}.{}` due to missing dependencies:",
method.parent().type_name(),
method.name()
)
.unwrap();

for tn in dependencies.keys() {
if !config.types.contains_key(tn) && config.references.contains(*tn).is_none() {
writeln!(&mut message, " {tn}").unwrap();
}
}

self.add(message);
}
}

/// Contains warnings collected during code generation.
#[derive(Debug)]
pub struct Warnings(Vec<String>);

impl Warnings {
/// Panics if any warnings are present.
#[track_caller]
pub fn unwrap(&self) {
if !self.is_empty() {
panic!("{self}");
}
}
}

impl std::fmt::Display for Warnings {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for message in &self.0 {
write!(f, "{message}")?;
}
Ok(())
}
}

impl std::ops::Deref for Warnings {
type Target = Vec<String>;

fn deref(&self) -> &Self::Target {
&self.0
}
}
7 changes: 7 additions & 0 deletions crates/libs/bindgen/src/winmd/codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@ code! { MemberRefParent(3)
}

impl MemberRefParent {
pub fn type_name(&self) -> TypeName {
match self {
Self::TypeDef(row) => row.type_name(),
Self::TypeRef(row) => row.type_name(),
}
}

pub fn name(&self) -> &'static str {
match self {
Self::TypeDef(row) => row.name(),
Expand Down
33 changes: 31 additions & 2 deletions crates/tests/bindgen/tests/panic.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#[track_caller]
fn bindgen(args: &str) {
windows_bindgen::bindgen(args.split_whitespace());
fn bindgen(args: &str) -> windows_bindgen::Warnings {
windows_bindgen::bindgen(args.split_whitespace())
}

#[test]
Expand Down Expand Up @@ -151,3 +151,32 @@ fn failed_to_write_file() {

bindgen(&format!("--out {test_path} --in default --filter POINT",));
}

#[test]
#[should_panic(
expected = "skipping `Windows.Win32.System.Com.IPersistFile.Load` due to missing dependencies:\n Windows.Win32.System.Com.STGM"
)]
fn skip_cpp_method() {
let mut path = std::env::temp_dir();
path.push("skip_cpp_method");

windows_bindgen::bindgen(["--out", &path.to_string_lossy(), "--filter", "IPersistFile"])
.unwrap();
}

#[test]
#[should_panic(
expected = "skipping `Windows.Foundation.IMemoryBuffer.CreateReference` due to missing dependencies:\n Windows.Foundation.IMemoryBufferReference"
)]
fn skip_method() {
let mut path = std::env::temp_dir();
path.push("skip_method");

windows_bindgen::bindgen([
"--out",
&path.to_string_lossy(),
"--filter",
"IMemoryBuffer",
])
.unwrap();
}
23 changes: 12 additions & 11 deletions crates/tools/bindings/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@ use windows_bindgen::*;
fn main() {
let time = std::time::Instant::now();

bindgen(["--etc", "crates/tools/bindings/src/async.txt"]);
bindgen(["--etc", "crates/tools/bindings/src/async_impl.txt"]);
bindgen(["--etc", "crates/tools/bindings/src/collections.txt"]);
bindgen(["--etc", "crates/tools/bindings/src/core_com.txt"]);
bindgen(["--etc", "crates/tools/bindings/src/core.txt"]);
bindgen(["--etc", "crates/tools/bindings/src/metadata.txt"]);
bindgen(["--etc", "crates/tools/bindings/src/numerics.txt"]);
bindgen(["--etc", "crates/tools/bindings/src/registry.txt"]);
bindgen(["--etc", "crates/tools/bindings/src/result.txt"]);
bindgen(["--etc", "crates/tools/bindings/src/strings.txt"]);
bindgen(["--etc", "crates/tools/bindings/src/async.txt"]).unwrap();
bindgen(["--etc", "crates/tools/bindings/src/async_impl.txt"]).unwrap();
bindgen(["--etc", "crates/tools/bindings/src/collections.txt"]).unwrap();
bindgen(["--etc", "crates/tools/bindings/src/core_com.txt"]).unwrap();
bindgen(["--etc", "crates/tools/bindings/src/core.txt"]).unwrap();
bindgen(["--etc", "crates/tools/bindings/src/metadata.txt"]).unwrap();
bindgen(["--etc", "crates/tools/bindings/src/numerics.txt"]).unwrap();
bindgen(["--etc", "crates/tools/bindings/src/registry.txt"]).unwrap();
bindgen(["--etc", "crates/tools/bindings/src/result.txt"]).unwrap();
bindgen(["--etc", "crates/tools/bindings/src/strings.txt"]).unwrap();
bindgen(["--etc", "crates/tools/bindings/src/version.txt"]).unwrap();

bindgen(["--etc", "crates/tools/bindings/src/sys.txt"]);
bindgen(["--etc", "crates/tools/bindings/src/version.txt"]);
bindgen(["--etc", "crates/tools/bindings/src/windows.txt"]);

println!("Finished in {:.2}s", time.elapsed().as_secs_f32());
Expand Down

0 comments on commit ed36c28

Please sign in to comment.