diff --git a/.github/workflows/local-development-makefile.yaml b/.github/workflows/local-development-makefile.yaml new file mode 100644 index 00000000..354209c3 --- /dev/null +++ b/.github/workflows/local-development-makefile.yaml @@ -0,0 +1,65 @@ +on: + push: + pull_request: + merge_group: + schedule: # Trigger a job on default branch at 4AM PST everyday + - cron: "0 11 * * *" + +name: Local Development Makefile + +env: + RUSTFLAGS: -D warnings + +jobs: + build: + name: Test WDR's local cargo-make Makefile + runs-on: windows-latest + strategy: + matrix: + wdk: + - Microsoft.WindowsWDK.10.0.22621 # NI WDK + + target_triple: + - x86_64-pc-windows-msvc + # - aarch64-pc-windows-msvc FIXME: find a way to validate the local makefile on aarch64 + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Install Winget + uses: ./.github/actions/winget-install + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Install WDK (${{ matrix.wdk }}) + run: | + if (!(winget list --exact --source winget --id ${{ matrix.wdk }})[-1].contains("${{ matrix.wdk }}")) { + winget install --disable-interactivity --source winget --exact --id ${{ matrix.wdk }} + } + + - name: Install Nightly Rust Toolchain (${{ matrix.target_triple }}) + uses: dtolnay/rust-toolchain@nightly + with: + components: clippy, rustfmt + targets: ${{ matrix.target_triple }} + + - name: Install Beta Rust Toolchain (${{ matrix.target_triple }}) + uses: dtolnay/rust-toolchain@beta + with: + components: clippy + targets: ${{ matrix.target_triple }} + + - name: Install Stable Rust Toolchain (${{ matrix.target_triple }}) + uses: dtolnay/rust-toolchain@stable + with: + components: clippy + targets: ${{ matrix.target_triple }} + + - name: Install Cargo Make + uses: taiki-e/install-action@v2 + with: + tool: cargo-make + + - name: Test wdk-pre-commit-flow cargo-make task + run: cargo make wdk-pre-commit-flow diff --git a/Cargo.lock b/Cargo.lock index 7a07919f..64012c53 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -239,6 +239,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "fs4" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21dabded2e32cd57ded879041205c60a4a4c4bab47bd0fd2fa8b01f30849f02b" +dependencies = [ + "rustix", + "windows-sys 0.52.0", +] + [[package]] name = "glob" version = "0.3.1" @@ -320,14 +330,16 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "macrotest" -version = "1.0.9" -source = "git+https://github.com/eupn/macrotest?rev=c4151a5#c4151a5f9f545942f4971980b5d264ebcd0b1d11" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "119d028d9d69a00b737d6af1081a690cee15df8ef75b3f71c86bcc48b301528e" dependencies = [ "basic-toml", "diff", "glob", "prettyplease", "serde", + "serde_derive", "serde_json", "syn", ] @@ -397,12 +409,28 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + [[package]] name = "pin-project-lite" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +[[package]] +name = "pretty_assertions" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +dependencies = [ + "diff", + "yansi", +] + [[package]] name = "prettyplease" version = "0.2.16" @@ -520,6 +548,12 @@ dependencies = [ "wdk-sys", ] +[[package]] +name = "scratch" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" + [[package]] name = "semver" version = "1.0.21" @@ -765,13 +799,19 @@ dependencies = [ name = "wdk-macros" version = "0.2.0" dependencies = [ - "cfg-if", + "cargo_metadata", + "fs4", + "itertools", "lazy_static", "macrotest", "owo-colors", "paste", + "pathdiff", + "pretty_assertions", "proc-macro2", "quote", + "rustversion", + "scratch", "syn", "trybuild", "wdk-sys", @@ -988,3 +1028,9 @@ name = "windows_x86_64_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" diff --git a/Makefile.toml b/Makefile.toml index 7fcae1b2..2481dfd7 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -1,12 +1,14 @@ extend = "./crates/wdk-build/rust-driver-makefile.toml" [config] +min_version = "0.37.11" additional_profiles = ["all-default-tasks"] [env] CARGO_MAKE_SKIP_SLOW_SECONDARY_FLOWS = false CARGO_MAKE_CLIPPY_ARGS = "--all-targets -- -D warnings" RUSTFLAGS = "-D warnings" +CARGO_MAKE_RUST_DEFAULT_TOOLCHAIN = "stable" [tasks.wdk-pre-commit-flow] description = "Run pre-commit tasks and checks" @@ -25,6 +27,9 @@ dependencies = [ "nightly-test-flow", "nightly-clippy-flow", "nightly-docs", + "beta-test-flow", + "beta-clippy-flow", + "beta-docs", ] [tasks.format] @@ -43,7 +48,10 @@ assert ${success} "Failed to delete tests directory" ''' [tasks.test] -install_crate = { crate_name = "cargo-expand", version = "1.0.80" } +install_crate = { crate_name = "cargo-expand", binary = "cargo", test_arg = [ + "expand", + "--version", +], version = "1.0.80" } [tasks.audit] args = ["audit", "--deny", "warnings"] @@ -70,7 +78,6 @@ env = { CARGO_MAKE_CARGO_BUILD_TEST_FLAGS = { unset = true } } [tasks.nightly-clippy-flow] extend = "clippy-flow" -toolchain = "nightly" dependencies = [ "pre-nightly-clippy", "nightly-clippy-router", @@ -88,9 +95,44 @@ env = { CARGO_MAKE_CLIPPY_ARGS = "--features nightly ${CARGO_MAKE_CLIPPY_ARGS}", [tasks.post-nightly-clippy] extend = "post-clippy" -env = { CARGO_MAKE_RUST_DEFAULT_TOOLCHAIN = { unset = true } } +env = { CARGO_MAKE_RUST_DEFAULT_TOOLCHAIN = "${CARGO_MAKE_RUST_DEFAULT_TOOLCHAIN}" } [tasks.nightly-docs] extend = "docs" toolchain = "nightly" args = ["doc", "--no-deps", "--features", "nightly"] + +[tasks.beta-test-flow] +extend = "test-flow" +dependencies = ["pre-beta-test", "beta-test", "post-beta-test"] + +[tasks.pre-beta-test] +alias = "pre-test" + +[tasks.beta-test] +extend = "test" +toolchain = "beta" + +[tasks.post-beta-test] +alias = "post-test" + +[tasks.beta-clippy-flow] +extend = "clippy-flow" +dependencies = ["pre-beta-clippy", "beta-clippy-router", "post-beta-clippy"] + +[tasks.pre-beta-clippy] +extend = "pre-clippy" +# Proc-macro crates fail to trigger recompilation when switching toolchains due to bug in rustc resulting in "found invalid metadata files for crate" errors. +run_task = "clean" + +[tasks.beta-clippy-router] +extend = "clippy-router" +env = { CARGO_MAKE_RUST_DEFAULT_TOOLCHAIN = "beta" } + +[tasks.post-beta-clippy] +extend = "post-clippy" +env = { CARGO_MAKE_RUST_DEFAULT_TOOLCHAIN = "${CARGO_MAKE_RUST_DEFAULT_TOOLCHAIN}" } + +[tasks.beta-docs] +extend = "docs" +toolchain = "beta" diff --git a/crates/sample-kmdf-driver/Cargo.toml b/crates/sample-kmdf-driver/Cargo.toml index 7eacf48e..ddb17a6e 100644 --- a/crates/sample-kmdf-driver/Cargo.toml +++ b/crates/sample-kmdf-driver/Cargo.toml @@ -31,4 +31,4 @@ wdk-build.workspace = true [features] default = [] -nightly = ["wdk-macros/nightly"] +nightly = ["wdk-macros/nightly", "wdk/nightly", "wdk-sys/nightly"] diff --git a/crates/sample-kmdf-driver/build.rs b/crates/sample-kmdf-driver/build.rs index 9ddff738..413ff081 100644 --- a/crates/sample-kmdf-driver/build.rs +++ b/crates/sample-kmdf-driver/build.rs @@ -2,6 +2,5 @@ // License: MIT OR Apache-2.0 fn main() -> Result<(), wdk_build::ConfigError> { - wdk_build::Config::from_env_auto()?.configure_binary_build()?; - Ok(()) + wdk_build::Config::from_env_auto()?.configure_binary_build() } diff --git a/crates/sample-kmdf-driver/src/lib.rs b/crates/sample-kmdf-driver/src/lib.rs index 05b5a68c..f420de0d 100644 --- a/crates/sample-kmdf-driver/src/lib.rs +++ b/crates/sample-kmdf-driver/src/lib.rs @@ -2,7 +2,6 @@ // License: MIT OR Apache-2.0 #![no_std] -#![cfg_attr(feature = "nightly", feature(hint_must_use))] #![deny(unsafe_op_in_unsafe_fn)] #![deny(clippy::all)] #![deny(clippy::pedantic)] @@ -96,7 +95,6 @@ pub unsafe extern "system" fn driver_entry( // 4. `driver_config` is a valid pointer to a valid `WDF_DRIVER_CONFIG` // 5. `driver_handle_output` is expected to be null unsafe { - #![allow(clippy::multiple_unsafe_ops_per_block)] wdf_driver_create_ntstatus = call_unsafe_wdf_function_binding!( WdfDriverCreate, driver as wdk_sys::PDRIVER_OBJECT, @@ -167,7 +165,6 @@ extern "C" fn evt_driver_device_add( // null // 3. `device_handle_output` is expected to be null unsafe { - #![allow(clippy::multiple_unsafe_ops_per_block)] ntstatus = wdk_macros::call_unsafe_wdf_function_binding!( WdfDeviceCreate, &mut device_init, diff --git a/crates/wdk-macros/Cargo.toml b/crates/wdk-macros/Cargo.toml index 33c7a6a4..6f3242cc 100644 --- a/crates/wdk-macros/Cargo.toml +++ b/crates/wdk-macros/Cargo.toml @@ -4,9 +4,9 @@ edition = "2021" name = "wdk-macros" version = "0.2.0" description = "A collection of macros that help make it easier to interact with wdk-sys's direct bindings" -repository = "https://github.com/microsoft/windows-drivers-rs" -readme = "README.md" -license = "MIT OR Apache-2.0" +repository.workspace = true +readme.workspace = true +license.workspace = true keywords = ["wdk", "windows", "wdf", "wdm", "ffi"] categories = [ "external-ffi-bindings", @@ -19,21 +19,25 @@ categories = [ proc-macro = true [dependencies] -cfg-if = "1.0.0" +cargo_metadata = "0.18.1" +itertools = "0.12.1" proc-macro2 = "1.0.78" quote = "1.0.35" +scratch = "1.0" syn = { version = "2.0.48", features = ["full"] } [dev-dependencies] -# use path dependency instead of workspace due to: https://github.com/eupn/macrotest/issues/95 -wdk-sys.path = "../wdk-sys" +wdk-sys.workspace = true +fs4 = { version = "0.8.2", features = ["sync"] } +pathdiff = "0.2.0" lazy_static = "1.4.0" -# Pin to github version due to: https://github.com/eupn/macrotest/issues/94 -macrotest = { git = "https://github.com/eupn/macrotest", rev = "c4151a5" } +macrotest = "1.0.11" +owo-colors = "4.0.0" paste = "1.0.14" +pretty_assertions = "1.4.0" +rustversion = "1.0.14" syn = { version = "2.0.48", features = ["extra-traits"] } trybuild = "1.0.89" -owo-colors = "4.0.0" [package.metadata.cargo-udeps.ignore] development = [ diff --git a/crates/wdk-macros/src/lib.rs b/crates/wdk-macros/src/lib.rs index 2bae0e5f..36a826fc 100644 --- a/crates/wdk-macros/src/lib.rs +++ b/crates/wdk-macros/src/lib.rs @@ -3,7 +3,6 @@ //! A collection of macros that help make it easier to interact with //! [`wdk-sys`]'s direct bindings to the Windows Driver Kit (WDK). -#![cfg_attr(feature = "nightly", feature(hint_must_use))] #![deny(missing_docs)] #![deny(unsafe_op_in_unsafe_fn)] #![deny(clippy::all)] @@ -23,17 +22,46 @@ #![deny(rustdoc::unescaped_backticks)] #![deny(rustdoc::redundant_explicit_links)] -use cfg_if::cfg_if; +use std::{ + io::{BufReader, Read}, + path::PathBuf, + process::{Command, Stdio}, +}; + +use cargo_metadata::{Message, MetadataCommand, PackageId}; +use itertools::Itertools; use proc_macro::TokenStream; -use proc_macro2::TokenStream as TokenStream2; +use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::{format_ident, quote}; use syn::{ parse::{Parse, ParseStream}, parse2, + parse_file, + parse_quote, + punctuated::Punctuated, + AngleBracketedGenericArguments, + Attribute, + BareFnArg, Error, Expr, + ExprCall, + File, + GenericArgument, Ident, + Item, + ItemType, + Path, + PathArguments, + PathSegment, + Result, + ReturnType, + Signature, + Stmt, Token, + Type, + TypeBareFn, + TypePath, + TypePtr, }; /// A procedural macro that allows WDF functions to be called by name. @@ -50,7 +78,6 @@ use syn::{ /// # Examples /// /// ```rust, no_run -/// #![cfg_attr(feature = "nightly", feature(hint_must_use))] /// use wdk_sys::*; /// /// #[export_name = "DriverEntry"] @@ -82,62 +109,177 @@ pub fn call_unsafe_wdf_function_binding(input_tokens: TokenStream) -> TokenStrea call_unsafe_wdf_function_binding_impl(TokenStream2::from(input_tokens)).into() } -struct CallUnsafeWDFFunctionInput { - pointer_type: Ident, - table_index: Ident, - arguments: syn::punctuated::Punctuated, +/// A trait to provide additional functionality to the `String` type +trait StringExt { + /// Convert a string to `snake_case` + fn to_snake_case(&self) -> String; +} + +/// Struct storing the input tokens directly parsed from calls to +/// `call_unsafe_wdf_function_binding` macro +#[derive(Debug, PartialEq)] +struct Inputs { + /// The name of the WDF function to call. This matches the name of the + /// function in C/C++. + wdf_function_identifier: Ident, + /// The arguments to pass to the WDF function. These should match the + /// function signature of the WDF function. + wdf_function_arguments: Punctuated, +} + +/// Struct storing all the AST fragments derived from `Inputs`. This represents +/// all the derived ASTs depend on `Inputs` that ultimately get used in the +/// final generated code that. +#[derive(Debug, PartialEq)] +struct DerivedASTFragments { + function_pointer_type: Ident, + function_table_index: Ident, + parameters: Punctuated, + parameter_identifiers: Punctuated, + return_type: ReturnType, + arguments: Punctuated, + inline_wdf_fn_name: Ident, +} + +/// Struct storing the AST fragments that form distinct sections of the final +/// generated code. These sections are derived from `DerivedASTFragments`. +struct IntermediateOutputASTFragments { + must_use_attribute: Option, + inline_wdf_fn_signature: Signature, + inline_wdf_fn_body_statments: Vec, + inline_wdf_fn_invocation: ExprCall, +} + +impl StringExt for String { + fn to_snake_case(&self) -> String { + // There will be, at max, 2 characters unhandled by the 3-char windows. It is + // only less than 2 when the string has length less than 2 + const MAX_PADDING_NEEDED: usize = 2; + + let mut snake_case_string = Self::with_capacity(self.len()); + + for (current_char, next_char, next_next_char) in self + .chars() + .map(Some) + .chain([None; MAX_PADDING_NEEDED]) + .tuple_windows() + .filter_map(|(c1, c2, c3)| Some((c1?, c2, c3))) + { + // Handle camelCase or PascalCase word boundary (e.g. lC in camelCase) + if current_char.is_lowercase() && next_char.is_some_and(|c| c.is_ascii_uppercase()) { + snake_case_string.push(current_char); + snake_case_string.push('_'); + } + // Handle UPPERCASE acronym word boundary (e.g. ISt in ASCIIString) + else if current_char.is_uppercase() + && next_char.is_some_and(|c| c.is_ascii_uppercase()) + && next_next_char.is_some_and(|c| c.is_ascii_lowercase()) + { + snake_case_string.push(current_char.to_ascii_lowercase()); + snake_case_string.push('_'); + } else { + snake_case_string.push(current_char.to_ascii_lowercase()); + } + } + + snake_case_string + } } -impl Parse for CallUnsafeWDFFunctionInput { - fn parse(input: ParseStream) -> Result { - let c_function_name: String = input.parse::()?.to_string(); +impl Parse for Inputs { + fn parse(input: ParseStream) -> Result { + let c_wdf_function_identifier = input.parse::()?; + + // Support WDF apis with no arguments + if input.is_empty() { + return Ok(Self { + wdf_function_identifier: c_wdf_function_identifier, + wdf_function_arguments: Punctuated::new(), + }); + } + input.parse::()?; - let arguments = input.parse_terminated(Expr::parse, Token![,])?; + let wdf_function_arguments = input.parse_terminated(Expr::parse, Token![,])?; Ok(Self { - pointer_type: format_ident!( - "PFN_{uppercase_c_function_name}", - uppercase_c_function_name = c_function_name.to_uppercase() - ), - table_index: format_ident!("{c_function_name}TableIndex"), - arguments, + wdf_function_identifier: c_wdf_function_identifier, + wdf_function_arguments, }) } } -fn call_unsafe_wdf_function_binding_impl(input_tokens: TokenStream2) -> TokenStream2 { - let CallUnsafeWDFFunctionInput { - pointer_type, - table_index, - arguments, - } = match parse2::(input_tokens) { - Ok(syntax_tree) => syntax_tree, - Err(err) => return err.to_compile_error(), - }; +impl Inputs { + fn generate_derived_ast_fragments(self) -> Result { + let function_pointer_type = format_ident!( + "PFN_{uppercase_c_function_name}", + uppercase_c_function_name = self.wdf_function_identifier.to_string().to_uppercase(), + span = self.wdf_function_identifier.span() + ); + let function_table_index = format_ident!( + "{wdf_function_identifier}TableIndex", + wdf_function_identifier = self.wdf_function_identifier, + span = self.wdf_function_identifier.span() + ); + let (parameters, return_type) = + generate_parameters_and_return_type(&function_pointer_type)?; + let parameter_identifiers = parameters + .iter() + .cloned() + .map(|bare_fn_arg| { + if let Some((identifier, _)) = bare_fn_arg.name { + return Ok(identifier); + } + Err(Error::new( + function_pointer_type.span(), + format!("Expected fn parameter to have a name: {bare_fn_arg:#?}"), + )) + }) + .collect::>()?; + let inline_wdf_fn_name = format_ident!( + "{c_function_name_snake_case}_impl", + c_function_name_snake_case = self.wdf_function_identifier.to_string().to_snake_case() + ); - // let inner_attribute_macros = proc_macro2::TokenStream::from_str( - // "#![allow(unused_unsafe)]\n\ - // #![allow(clippy::multiple_unsafe_ops_per_block)]", - // ).expect("inner_attribute_macros must be convertible to a valid - // TokenStream"); + Ok(DerivedASTFragments { + function_pointer_type, + function_table_index, + parameters, + parameter_identifiers, + return_type, + arguments: self.wdf_function_arguments, + inline_wdf_fn_name, + }) + } +} - let wdf_function_call_tokens = quote! { - { - // Force the macro to require an unsafe block - unsafe fn force_unsafe(){} - force_unsafe(); +impl DerivedASTFragments { + fn generate_intermediate_output_ast_fragments(self) -> IntermediateOutputASTFragments { + let Self { + function_pointer_type, + function_table_index, + parameters, + parameter_identifiers, + return_type, + arguments, + inline_wdf_fn_name, + } = self; + + let must_use_attribute = generate_must_use_attribute(&return_type); + let inline_wdf_fn_signature = parse_quote! { + unsafe fn #inline_wdf_fn_name(#parameters) #return_type + }; + + let inline_wdf_fn_body_statments = parse_quote! { // Get handle to WDF function from the function table - let wdf_function: wdk_sys::#pointer_type = Some( + let wdf_function: wdk_sys::#function_pointer_type = Some( // SAFETY: This `transmute` from a no-argument function pointer to a function pointer with the correct // arguments for the WDF function is safe befause WDF maintains the strict mapping between the // function table index and the correct function pointer type. - #[allow(unused_unsafe)] - #[allow(clippy::multiple_unsafe_ops_per_block)] unsafe { core::mem::transmute( // FIXME: investigate why _WDFFUNCENUM does not have a generated type alias without the underscore prefix - wdk_sys::WDF_FUNCTION_TABLE[wdk_sys::_WDFFUNCENUM::#table_index as usize], + wdk_sys::WDF_FUNCTION_TABLE[wdk_sys::_WDFFUNCENUM::#function_table_index as usize], ) } ); @@ -149,232 +291,1199 @@ fn call_unsafe_wdf_function_binding_impl(input_tokens: TokenStream2) -> TokenStr // `wdk_sys::WDF_FUNCTION_TABLE` indexed by `table_index` and guarded by the type-safety of // `pointer_type`. The passed arguments are also guaranteed to be of a compatible type due to // `pointer_type`. - #[allow(unused_unsafe)] - #[allow(clippy::multiple_unsafe_ops_per_block)] unsafe { (wdf_function)( wdk_sys::WdfDriverGlobals, - #arguments + #parameter_identifiers ) } } else { unreachable!("Option should never be None"); } + }; + + let inline_wdf_fn_invocation = parse_quote! { + #inline_wdf_fn_name(#arguments) + }; + + IntermediateOutputASTFragments { + must_use_attribute, + inline_wdf_fn_signature, + inline_wdf_fn_body_statments, + inline_wdf_fn_invocation, + } + } +} + +impl IntermediateOutputASTFragments { + fn assemble_final_output(self) -> TokenStream2 { + let Self { + must_use_attribute, + inline_wdf_fn_signature, + inline_wdf_fn_body_statments, + inline_wdf_fn_invocation, + } = self; + + let conditional_must_use_attribute = + must_use_attribute.map_or_else(TokenStream2::new, quote::ToTokens::into_token_stream); + + quote! { + { + #conditional_must_use_attribute + #[inline(always)] + #inline_wdf_fn_signature { + #(#inline_wdf_fn_body_statments)* + } + + #inline_wdf_fn_invocation + } } + } +} + +fn call_unsafe_wdf_function_binding_impl(input_tokens: TokenStream2) -> TokenStream2 { + let inputs = match parse2::(input_tokens) { + Ok(syntax_tree) => syntax_tree, + Err(err) => return err.to_compile_error(), }; - cfg_if! { - if #[cfg(feature = "nightly")] { - // FIXME: parse return type of function pointer and only emit - // core::hint::must_use if the return type is not () - quote! { - core::hint::must_use(#wdf_function_call_tokens) + let derived_ast_fragments = match inputs.generate_derived_ast_fragments() { + Ok(derived_ast_fragments) => derived_ast_fragments, + Err(err) => return err.to_compile_error(), + }; + + derived_ast_fragments + .generate_intermediate_output_ast_fragments() + .assemble_final_output() +} + +/// Generate the function parameters and return type corresponding to the +/// function signature of the `function_pointer_type` type alias in the AST for +/// types.rs +/// +/// # Examples +/// +/// Passing the `PFN_WDFDRIVERCREATE` [`Ident`] as `function_pointer_type` would +/// return a [`Punctuated`] representation of +/// +/// ```rust, compile_fail +/// DriverObject: wdk_sys::PDRIVER_OBJECT, +/// RegistryPath: wdk_sys::PCUNICODE_STRING, +/// DriverAttributes: wdk_sys::WDF_OBJECT_ATTRIBUTES, +/// DriverConfig: wdk_sys::PWDF_DRIVER_CONFIG, +/// Driver: *mut wdk_sys::WDFDRIVER +/// ``` +/// +/// and return type as the [`ReturnType`] representation of `wdk_sys::NTSTATUS` +fn generate_parameters_and_return_type( + function_pointer_type: &Ident, +) -> Result<(Punctuated, ReturnType)> { + let types_rs_ast = get_type_rs_ast()?; + let type_alias_definition = find_type_alias_definition(&types_rs_ast, function_pointer_type)?; + let fn_pointer_definition = + extract_fn_pointer_definition(type_alias_definition, function_pointer_type.span())?; + parse_fn_pointer_definition(fn_pointer_definition, function_pointer_type.span()) +} + +/// Finds the `types.rs` file generated by `wdk-sys` and parses it into an AST +fn get_type_rs_ast() -> Result { + let types_rs_path = find_wdk_sys_out_dir()?.join("types.rs"); + let types_rs_contents = match std::fs::read_to_string(&types_rs_path) { + Ok(contents) => contents, + Err(err) => { + return Err(Error::new( + Span::call_site(), + format!( + "Failed to read wdk-sys types.rs at {}: {}", + types_rs_path.display(), + err + ), + )); + } + }; + + match parse_file(&types_rs_contents) { + Ok(wdk_sys_types_rs_abstract_syntax_tree) => Ok(wdk_sys_types_rs_abstract_syntax_tree), + Err(err) => Err(Error::new( + Span::call_site(), + format!( + "Failed to parse wdk-sys types.rs into AST at {}: {}", + types_rs_path.display(), + err + ), + )), + } +} + +/// Find the `OUT_DIR` of wdk-sys crate by running `cargo check` with +/// `--message-format=json` and parsing its output using [`cargo_metadata`] +fn find_wdk_sys_out_dir() -> Result { + let scratch_path = scratch::path(env!("CARGO_PKG_NAME")); + let mut cargo_check_process_handle = match Command::new("cargo") + .args([ + "check", + "--message-format=json", + "--package", + "wdk-sys", + // must have a seperate target directory to prevent deadlock from cargo holding a + // file lock on build output directory since this proc_macro causes + // cargo build to invoke cargo check + "--target-dir", + scratch_path + .as_os_str() + .to_str() + .expect("scratch::path should be valid UTF-8"), + ]) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + { + Ok(process) => process, + Err(err) => { + return Err(Error::new( + Span::call_site(), + format!("Failed to start cargo check process successfully: {err}"), + )); + } + }; + + let wdk_sys_pkg_id = find_wdk_sys_pkg_id()?; + let wdk_sys_out_dir = cargo_metadata::Message::parse_stream(BufReader::new( + cargo_check_process_handle + .stdout + .take() + .expect("cargo check process should have valid stdout handle"), + )) + .filter_map(|message| { + if let Ok(Message::BuildScriptExecuted(build_script_message)) = message { + if build_script_message.package_id == wdk_sys_pkg_id { + return Some(build_script_message.out_dir); } - } else { - quote! { - #wdf_function_call_tokens + } + None + }) + .collect::>(); + let wdk_sys_out_dir = match wdk_sys_out_dir.len() { + 1 => &wdk_sys_out_dir[0], + _ => { + return Err(Error::new( + Span::call_site(), + format!( + "Expected exactly one instance of wdk-sys in dependency graph when running \ + `cargo check`, found {}", + wdk_sys_out_dir.len() + ), + )); + } + }; + match cargo_check_process_handle.wait() { + Ok(exit_status) => { + if !exit_status.success() { + let mut stderr_output = String::new(); + BufReader::new( + cargo_check_process_handle + .stderr + .take() + .expect("cargo check process should have valid stderr handle"), + ) + .read_to_string(&mut stderr_output) + .expect("cargo check process' stderr should be valid UTF-8"); + return Err(Error::new( + Span::call_site(), + format!( + "cargo check failed to execute to get OUT_DIR for wdk-sys: \ + \n{stderr_output}" + ), + )); } } + Err(err) => { + return Err(Error::new( + Span::call_site(), + format!("cargo check process handle should sucessfully be waited on: {err}"), + )); + } } + + Ok(wdk_sys_out_dir.to_owned().into()) } -#[cfg(test)] -mod tests { - use std::path::{Path, PathBuf}; - - use cfg_if::cfg_if; - use lazy_static::lazy_static; - - lazy_static! { - static ref TESTS_FOLDER_PATH: PathBuf = - [env!("CARGO_MANIFEST_DIR"), "tests"].iter().collect(); - static ref NIGHTLY_FOLDER_PATH: PathBuf = TESTS_FOLDER_PATH.join("nightly"); - static ref NON_NIGHTLY_FOLDER_PATH: PathBuf = TESTS_FOLDER_PATH.join("non-nightly"); - static ref NIGHTLY_FEATURE_MACROTEST_FOLDER_PATH: PathBuf = - NIGHTLY_FOLDER_PATH.join("macrotest"); - static ref NO_NIGHTLY_FEATURE_MACROTEST_FOLDER_PATH: PathBuf = - NON_NIGHTLY_FOLDER_PATH.join("macrotest"); - static ref TRYBUILD_FOLDER_PATH: PathBuf = { - cfg_if! { - if #[cfg(feature = "nightly")] { - NIGHTLY_FOLDER_PATH.join("trybuild") - } else { - NON_NIGHTLY_FOLDER_PATH.join("trybuild") +/// find wdk-sys `package_id`. WDR places a limitation that only one instance of +/// wdk-sys is allowed in the dependency graph +fn find_wdk_sys_pkg_id() -> Result { + let cargo_metadata_packages_list = match MetadataCommand::new().exec() { + Ok(metadata) => metadata.packages, + Err(err) => { + return Err(Error::new( + Span::call_site(), + format!("cargo metadata failed to run successfully: {err}"), + )); + } + }; + let wdk_sys_package_matches = cargo_metadata_packages_list + .iter() + .filter(|package| package.name == "wdk-sys") + .collect::>(); + + if wdk_sys_package_matches.len() != 1 { + return Err(Error::new( + Span::call_site(), + format!( + "Expected exactly one instance of wdk-sys in dependency graph when running `cargo \ + metadata`, found {}", + wdk_sys_package_matches.len() + ), + )); + } + Ok(wdk_sys_package_matches[0].id.clone()) +} + +/// Find type alias declaration and definition that matches the Ident of +/// `function_pointer_type` in `syn::File` AST +/// +/// # Examples +/// +/// Passing the `PFN_WDFDRIVERCREATE` [`Ident`] as `function_pointer_type` would +/// return a [`ItemType`] representation of: +/// +/// ```rust, compile_fail +/// pub type PFN_WDFDRIVERCREATE = ::core::option::Option< +/// unsafe extern "C" fn( +/// DriverGlobals: PWDF_DRIVER_GLOBALS, +/// DriverObject: PDRIVER_OBJECT, +/// RegistryPath: PCUNICODE_STRING, +/// DriverAttributes: PWDF_OBJECT_ATTRIBUTES, +/// DriverConfig: PWDF_DRIVER_CONFIG, +/// Driver: *mut WDFDRIVER, +/// ) -> NTSTATUS, +/// >; +/// ``` +fn find_type_alias_definition<'a>( + file_ast: &'a File, + function_pointer_type: &Ident, +) -> Result<&'a ItemType> { + file_ast + .items + .iter() + .find_map(|item| { + if let Item::Type(type_alias) = item { + if type_alias.ident == *function_pointer_type { + return Some(type_alias); } } - }; + None + }) + .ok_or_else(|| { + Error::new( + function_pointer_type.span(), + format!("Failed to find type alias definition for {function_pointer_type}"), + ) + }) +} + +/// Extract the [`TypePath`] representing the function pointer definition from +/// the [`ItemType`] +/// +/// # Examples +/// +/// The [`ItemType`] representation of +/// +/// ```rust, compile_fail +/// pub type PFN_WDFDRIVERCREATE = ::core::option::Option< +/// unsafe extern "C" fn( +/// DriverGlobals: PWDF_DRIVER_GLOBALS, +/// DriverObject: PDRIVER_OBJECT, +/// RegistryPath: PCUNICODE_STRING, +/// DriverAttributes: PWDF_OBJECT_ATTRIBUTES, +/// DriverConfig: PWDF_DRIVER_CONFIG, +/// Driver: *mut WDFDRIVER, +/// ) -> NTSTATUS, +/// >; +/// ``` +/// +/// would return the [`TypePath`] representation of +/// +/// ```rust, compile_fail +/// ::core::option::Option< +/// unsafe extern "C" fn( +/// DriverGlobals: PWDF_DRIVER_GLOBALS, +/// DriverObject: PDRIVER_OBJECT, +/// RegistryPath: PCUNICODE_STRING, +/// DriverAttributes: PWDF_OBJECT_ATTRIBUTES, +/// DriverConfig: PWDF_DRIVER_CONFIG, +/// Driver: *mut WDFDRIVER, +/// ) -> NTSTATUS, +/// > +/// ``` +fn extract_fn_pointer_definition(type_alias: &ItemType, error_span: Span) -> Result<&TypePath> { + if let Type::Path(fn_pointer) = type_alias.ty.as_ref() { + Ok(fn_pointer) + } else { + Err(Error::new( + error_span, + format!("Expected Type::Path when parsing ItemType.ty:\n{type_alias:#?}"), + )) } +} - mod macro_expansion_and_compilation { - use std::{io::Write, stringify}; +/// Parse the parameter list (both names and types) and the return type from the +/// [`TypePath`] representing the function pointer definition +/// +/// # Examples +/// +/// The [`TypePath`] representation of +/// +/// ```rust, compile_fail +/// ::core::option::Option< +/// unsafe extern "C" fn( +/// DriverGlobals: PWDF_DRIVER_GLOBALS, +/// DriverObject: PDRIVER_OBJECT, +/// RegistryPath: PCUNICODE_STRING, +/// DriverAttributes: PWDF_OBJECT_ATTRIBUTES, +/// DriverConfig: PWDF_DRIVER_CONFIG, +/// Driver: *mut WDFDRIVER, +/// ) -> NTSTATUS, +/// > +/// ``` +/// +/// would return the parsed parameter list as the [`Punctuated`] representation +/// of +/// +/// ```rust, compile_fail +/// DriverObject: wdk_sys::PDRIVER_OBJECT, +/// RegistryPath: wdk_sys::PCUNICODE_STRING, +/// DriverAttributes: wdk_sys::WDF_OBJECT_ATTRIBUTES, +/// DriverConfig: wdk_sys::PWDF_DRIVER_CONFIG, +/// Driver: *mut wdk_sys::WDFDRIVER +/// ``` +/// +/// and return type as the [`ReturnType`] representation of `wdk_sys::NTSTATUS` +fn parse_fn_pointer_definition( + fn_pointer_typepath: &TypePath, + error_span: Span, +) -> Result<(Punctuated, ReturnType)> { + let bare_fn_type = extract_bare_fn_type(fn_pointer_typepath, error_span)?; + let fn_parameters = compute_fn_parameters(bare_fn_type, error_span)?; + let return_type = compute_return_type(bare_fn_type, error_span)?; - use owo_colors::OwoColorize; - use paste::paste; + Ok((fn_parameters, return_type)) +} - use super::*; +/// Extract the [`TypeBareFn`] (i.e. function definition) from the [`TypePath`] +/// (i.e. the function pointer option) representing the function +/// +/// # Examples +/// +/// The [`TypePath`] representation of +/// +/// ```rust, compile_fail +/// ::core::option::Option< +/// unsafe extern "C" fn( +/// DriverGlobals: PWDF_DRIVER_GLOBALS, +/// DriverObject: PDRIVER_OBJECT, +/// RegistryPath: PCUNICODE_STRING, +/// DriverAttributes: PWDF_OBJECT_ATTRIBUTES, +/// DriverConfig: PWDF_DRIVER_CONFIG, +/// Driver: *mut WDFDRIVER, +/// ) -> NTSTATUS, +/// > +/// ``` +/// +/// would return the [`TypeBareFn`] representation of +/// +/// ```rust, compile_fail +/// unsafe extern "C" fn( +/// DriverGlobals: PWDF_DRIVER_GLOBALS, +/// DriverObject: PDRIVER_OBJECT, +/// RegistryPath: PCUNICODE_STRING, +/// DriverAttributes: PWDF_OBJECT_ATTRIBUTES, +/// DriverConfig: PWDF_DRIVER_CONFIG, +/// Driver: *mut WDFDRIVER, +/// ) -> NTSTATUS, +/// ``` +fn extract_bare_fn_type(fn_pointer_typepath: &TypePath, error_span: Span) -> Result<&TypeBareFn> { + let option_path_segment: &PathSegment = + fn_pointer_typepath.path.segments.last().ok_or_else(|| { + Error::new( + error_span, + format!("Expected at least one PathSegment in TypePath:\n{fn_pointer_typepath:#?}"), + ) + })?; + if option_path_segment.ident != "Option" { + return Err(Error::new( + error_span, + format!("Expected Option as last PathSegment in TypePath:\n{fn_pointer_typepath:#?}"), + )); + } + let PathArguments::AngleBracketed(AngleBracketedGenericArguments { + args: ref option_angle_bracketed_args, + .. + }) = option_path_segment.arguments + else { + return Err(Error::new( + error_span, + format!( + "Expected AngleBracketed PathArguments in Option \ + PathSegment:\n{option_path_segment:#?}" + ), + )); + }; + let bracketed_argument = option_angle_bracketed_args.first().ok_or_else(|| { + Error::new( + error_span, + format!( + "Expected exactly one GenericArgument in AngleBracketedGenericArguments:\n{:#?}", + option_path_segment.arguments + ), + ) + })?; + let GenericArgument::Type(Type::BareFn(bare_fn_type)) = bracketed_argument else { + return Err(Error::new( + error_span, + format!("Expected TypeBareFn in GenericArgument:\n{bracketed_argument:#?}"), + )); + }; + Ok(bare_fn_type) +} + +/// Compute the function parameters based on the function definition. Prepends +/// `wdk_sys::` to the parameter types +/// +/// # Examples +/// +/// The [`TypeBareFn`] representation of +/// +/// ```rust, compile_fail +/// unsafe extern "C" fn( +/// DriverGlobals: PWDF_DRIVER_GLOBALS, +/// DriverObject: PDRIVER_OBJECT, +/// RegistryPath: PCUNICODE_STRING, +/// DriverAttributes: PWDF_OBJECT_ATTRIBUTES, +/// DriverConfig: PWDF_DRIVER_CONFIG, +/// Driver: *mut WDFDRIVER, +/// ) -> NTSTATUS, +/// ``` +/// +/// would return the [`Punctuated`] representation of +/// ```rust, compile_fail +/// DriverObject: wdk_sys::PDRIVER_OBJECT, +/// RegistryPath: wdk_sys::PCUNICODE_STRING, +/// DriverAttributes: wdk_sys::WDF_OBJECT_ATTRIBUTES, +/// DriverConfig: wdk_sys::PWDF_DRIVER_CONFIG, +/// Driver: *mut wdk_sys::WDFDRIVER +/// ``` +fn compute_fn_parameters( + bare_fn_type: &syn::TypeBareFn, + error_span: Span, +) -> Result> { + let Some(BareFnArg { + ty: + Type::Path(TypePath { + path: + Path { + segments: first_parameter_type_path, + .. + }, + .. + }), + .. + }) = bare_fn_type.inputs.first() + else { + return Err(Error::new( + error_span, + format!( + "Expected at least one input parameter of type Path in \ + BareFnType:\n{bare_fn_type:#?}" + ), + )); + }; + let Some(last_path_segment) = first_parameter_type_path.last() else { + return Err(Error::new( + error_span, + format!("Expected at least one PathSegment in TypePath:\n{bare_fn_type:#?}"), + )); + }; + if last_path_segment.ident != "PWDF_DRIVER_GLOBALS" { + return Err(Error::new( + error_span, + format!( + "Expected PWDF_DRIVER_GLOBALS as last PathSegment in TypePath of first BareFnArg \ + input:\n{bare_fn_type:#?}" + ), + )); + } - /// Given a filename `f` which contains code utilizing macros in - /// `wdk-macros`, generates a pair of tests to verify that code in `f` - /// expands as expected, and compiles successfully. The test output will - /// show `_expansion` as the names of the expansion tests and - /// `_compilation` as the name of the compilation test. `f` must - /// reside in the `tests/macrotest` folder, and may be a path to - /// a file relative to the `tests/macrotest` folder. - /// - /// Note: Due to limitations in `trybuild`, a successful compilation - /// test will include output that looks similar to the following: - /// ``` - /// test \\?\D:\git-repos\windows-drivers-rs\crates\wdk-macros\tests\macrotest\wdf_driver_create.rs ... error - /// Expected test case to fail to compile, but it succeeded. - /// ``` - /// This is because `trybuild` will run `cargo check` when calling - /// `TestCases::compile_fail`, but will run `cargo build` if calling - /// `TestCases::pass`. `cargo build` will fail at link stage due to - /// `trybuild` not allowing configuration to compile as a`cdylib`. To - /// work around this, `compile_fail` is used, and we mark the test as - /// expecting to panic with a specific message using the `should_panic` - /// attribute macro. - macro_rules! generate_macro_expansion_and_compilation_tests { - ($($filename:ident),+) => { - paste! { - - // This module's tests are deliberately not feature-gated by #[cfg(feature = "nightly")] since macrotest can control whether to expand with the nightly feature or not - mod expansion_tests { - use super::*; - - $( - #[test] - fn [<$filename _expansion>]() -> std::io::Result<()> { - macrotest::expand(&NO_NIGHTLY_FEATURE_MACROTEST_FOLDER_PATH.join(format!("{}.rs", stringify!($filename))).canonicalize()?); - Ok(()) - } - )? - - mod nightly_feature { - use super::*; - - $( - #[test] - fn [<$filename _expansion>]() -> std::io::Result<()> { - macrotest::expand_args( - &NIGHTLY_FEATURE_MACROTEST_FOLDER_PATH.join(format!("{}.rs", stringify!($filename))).canonicalize()?, &["--features", "nightly"]); - Ok(()) - } - )? - } + // discard the PWDF_DRIVER_GLOBALS parameter and prepend wdk_sys to the rest of + // the parameters + let parameters = bare_fn_type + .inputs + .iter() + .skip(1) + .cloned() + .map(|mut bare_fn_arg| { + let parameter_type_path_segments: &mut Punctuated = + match &mut bare_fn_arg.ty { + Type::Path(TypePath { + path: + Path { + ref mut segments, .. + }, + .. + }) => segments, + + Type::Ptr(TypePtr { elem: ty, .. }) => { + let Type::Path(TypePath { + path: + Path { + ref mut segments, .. + }, + .. + }) = **ty + else { + return Err(Error::new( + error_span, + format!( + "Failed to parse PathSegments out of TypePtr function \ + parameter:\n{bare_fn_arg:#?}" + ), + )); + }; + segments } - mod compilation_tests { - use super::*; - - pub trait TestCasesExt { - fn pass_cargo_check + std::panic::UnwindSafe>(path: P); - } - - impl TestCasesExt for trybuild::TestCases { - fn pass_cargo_check + std::panic::UnwindSafe>(path: P) { - // "compile_fail" tests that pass cargo check result in this panic message - const SUCCESSFUL_CARGO_CHECK_STRING: &str = "1 of 1 tests failed"; - - let path = path.as_ref(); - - let failed_cargo_check = !std::panic::catch_unwind(|| { - // A new TestCases is required because it relies on running the tests upon drop - trybuild::TestCases::new().compile_fail(path); - }) - .is_err_and(|cause| { - if let Some(str) = cause.downcast_ref::<&str>() { - *str == SUCCESSFUL_CARGO_CHECK_STRING - } else if let Some(string) = cause.downcast_ref::() { - string == SUCCESSFUL_CARGO_CHECK_STRING - } else { - // Unexpected panic trait object type - false - } - }); - - if failed_cargo_check { - let failed_cargo_check_msg = format!( - "{}{}", - path.to_string_lossy().bold().red(), - " failed Cargo Check!".bold().red() - ); - - // Use writeln! to print even without passing --nocapture to the test harness - writeln!(&mut std::io::stderr(), "{failed_cargo_check_msg}").unwrap(); - - panic!("{failed_cargo_check_msg}"); - } else { - // Use writeln! to print even without passing --nocapture to the test harness - writeln!( - &mut std::io::stderr(), - "{}{}{}{}{}", - "Please ignore the above \"Expected test case to fail to compile, but it \ - succeeded.\" message (and its accompanying \"1 of 1 tests failed\" panic \ - message when run with --nocapture).\n" - .italic() - .yellow(), - "test ".bold(), - path.to_string_lossy().bold(), - " ... ".bold(), - "PASSED".bold().green() - ).unwrap(); - } - } - } - - $( - #[cfg(not(feature = "nightly"))] - #[test] - fn [<$filename _compilation>]() { - trybuild::TestCases::pass_cargo_check( - &NO_NIGHTLY_FEATURE_MACROTEST_FOLDER_PATH - .join(format!("{}.rs", stringify!($filename))) - .canonicalize() - .expect(concat!(stringify!($filename), " should exist")), - ); - } - )? - - #[cfg(feature = "nightly")] - mod nightly_feature { - use super::*; - - $( - #[test] - fn [<$filename _compilation>]() { - trybuild::TestCases::pass_cargo_check( - &NIGHTLY_FEATURE_MACROTEST_FOLDER_PATH - .join(format!("{}.rs", stringify!($filename))) - .canonicalize() - .expect(concat!(stringify!($filename), " should exist")), - ); - } - )? - } + _ => { + return Err(Error::new( + error_span, + format!( + "Unexpected Type encountered when parsing function \ + parameter:\n{bare_fn_arg:#?}", + ), + )); } + }; + + parameter_type_path_segments + .insert(0, syn::PathSegment::from(format_ident!("wdk_sys"))); + Ok(bare_fn_arg) + }) + .collect::>()?; + + Ok(parameters) +} + +/// Compute the return type based on the function defintion. Prepends the return +/// type with `wdk_sys::` +/// +/// # Examples +/// +/// The [`TypeBareFn`] representation of +/// +/// ```rust, compile_fail +/// unsafe extern "C" fn( +/// DriverGlobals: PWDF_DRIVER_GLOBALS, +/// DriverObject: PDRIVER_OBJECT, +/// RegistryPath: PCUNICODE_STRING, +/// DriverAttributes: PWDF_OBJECT_ATTRIBUTES, +/// DriverConfig: PWDF_DRIVER_CONFIG, +/// Driver: *mut WDFDRIVER, +/// ) -> NTSTATUS, +/// ``` +/// +/// would return the [`ReturnType`] representation of `wdk_sys::NTSTATUS` +fn compute_return_type(bare_fn_type: &syn::TypeBareFn, error_span: Span) -> Result { + let return_type = match &bare_fn_type.output { + ReturnType::Default => ReturnType::Default, + ReturnType::Type(right_arrow_token, ty) => ReturnType::Type( + *right_arrow_token, + Box::new(Type::Path(TypePath { + qself: None, + path: Path { + leading_colon: None, + segments: { + // prepend wdk_sys to existing TypePath + let Type::Path(TypePath { + path: Path { ref segments, .. }, + .. + }) = **ty + else { + return Err(Error::new( + error_span, + format!("Failed to parse ReturnType TypePath:\n{ty:#?}"), + )); + }; + let mut segments = segments.clone(); + segments.insert( + 0, + PathSegment { + ident: format_ident!("wdk_sys"), + arguments: PathArguments::None, + }, + ); + segments + }, + }, + })), + ), + }; + Ok(return_type) +} + +/// Generate the `#[must_use]` attribute if the return type is not `()` +fn generate_must_use_attribute(return_type: &ReturnType) -> Option { + if matches!(return_type, ReturnType::Type(..)) { + Some(parse_quote! { #[must_use] }) + } else { + None + } +} + +#[cfg(test)] +mod tests { + use pretty_assertions::assert_eq as pretty_assert_eq; + use quote::ToTokens; + + use super::*; + + mod to_snake_case { + use super::*; + + #[test] + fn camel_case() { + let input = "camelCaseString".to_string(); + let expected = "camel_case_string"; + + pretty_assert_eq!(input.to_snake_case(), expected); + } + + #[test] + fn short_camel_case() { + let input = "aB".to_string(); + let expected = "a_b"; + + pretty_assert_eq!(input.to_snake_case(), expected); + } + + #[test] + fn pascal_case() { + let input = "PascalCaseString".to_string(); + let expected = "pascal_case_string"; + + pretty_assert_eq!(input.to_snake_case(), expected); + } + + #[test] + fn pascal_case_with_leading_acronym() { + let input = "ASCIIEncodedString".to_string(); + let expected = "ascii_encoded_string"; + + pretty_assert_eq!(input.to_snake_case(), expected); + } + + #[test] + fn pascal_case_with_trailing_acronym() { + let input = "IsASCII".to_string(); + let expected = "is_ascii"; + + pretty_assert_eq!(input.to_snake_case(), expected); + } + + #[test] + fn screaming_snake_case() { + let input = "PFN_WDF_DRIVER_DEVICE_ADD".to_string(); + let expected = "pfn_wdf_driver_device_add"; + + pretty_assert_eq!(input.to_snake_case(), expected); + } + + #[test] + fn screaming_snake_case_with_leading_acronym() { + let input = "ASCII_STRING".to_string(); + let expected = "ascii_string"; + + pretty_assert_eq!(input.to_snake_case(), expected); + } + + #[test] + fn screaming_snake_case_with_leading_underscore() { + let input = "_WDF_DRIVER_INIT_FLAGS".to_string(); + let expected = "_wdf_driver_init_flags"; + + pretty_assert_eq!(input.to_snake_case(), expected); + } + + #[test] + fn snake_case() { + let input = "snake_case_string".to_string(); + let expected = "snake_case_string"; + + pretty_assert_eq!(input.to_snake_case(), expected); + } + + #[test] + fn snake_case_with_leading_underscore() { + let input = "_snake_case_with_leading_underscore".to_string(); + let expected = "_snake_case_with_leading_underscore"; + + pretty_assert_eq!(input.to_snake_case(), expected); + } + } + + mod inputs { + use super::*; + + mod parse { + use super::*; + + #[test] + fn valid_input() { + let input_tokens = quote! { WdfDriverCreate, driver, registry_path, WDF_NO_OBJECT_ATTRIBUTES, &mut driver_config, driver_handle_output }; + let expected = Inputs { + wdf_function_identifier: format_ident!("WdfDriverCreate"), + wdf_function_arguments: parse_quote! { + driver, + registry_path, + WDF_NO_OBJECT_ATTRIBUTES, + &mut driver_config, + driver_handle_output + }, + }; + + pretty_assert_eq!(parse2::(input_tokens).unwrap(), expected); + } + + #[test] + fn valid_input_with_trailing_comma() { + let input_tokens = quote! { WdfDriverCreate, driver, registry_path, WDF_NO_OBJECT_ATTRIBUTES, &mut driver_config, driver_handle_output, }; + let expected = Inputs { + wdf_function_identifier: format_ident!("WdfDriverCreate"), + wdf_function_arguments: parse_quote! { + driver, + registry_path, + WDF_NO_OBJECT_ATTRIBUTES, + &mut driver_config, + driver_handle_output, + }, + }; + + pretty_assert_eq!(parse2::(input_tokens).unwrap(), expected); + } + + #[test] + fn wdf_function_with_no_arguments() { + let input_tokens = quote! { WdfVerifierDbgBreakPoint }; + let expected = Inputs { + wdf_function_identifier: format_ident!("WdfVerifierDbgBreakPoint"), + wdf_function_arguments: Punctuated::new(), + }; + + pretty_assert_eq!(parse2::(input_tokens).unwrap(), expected); + } + + #[test] + fn wdf_function_with_no_arguments_and_trailing_comma() { + let input_tokens = quote! { WdfVerifierDbgBreakPoint, }; + let expected = Inputs { + wdf_function_identifier: format_ident!("WdfVerifierDbgBreakPoint"), + wdf_function_arguments: Punctuated::new(), + }; + + pretty_assert_eq!(parse2::(input_tokens).unwrap(), expected); + } + + #[test] + fn invalid_ident() { + let input_tokens = quote! { 123InvalidIdent, driver, registry_path, WDF_NO_OBJECT_ATTRIBUTES, &mut driver_config, driver_handle_output, }; + let expected = Error::new(Span::call_site(), "expected identifier"); + + pretty_assert_eq!( + parse2::(input_tokens).unwrap_err().to_string(), + expected.to_string() + ); + } + } + + mod generate_derived_ast_fragments { + use super::*; + + #[test] + fn valid_input() { + let inputs = Inputs { + wdf_function_identifier: format_ident!("WdfDriverCreate"), + wdf_function_arguments: parse_quote! { + driver, + registry_path, + WDF_NO_OBJECT_ATTRIBUTES, + &mut driver_config, + driver_handle_output, + }, + }; + let expected = DerivedASTFragments { + function_pointer_type: format_ident!("PFN_WDFDRIVERCREATE"), + function_table_index: format_ident!("WdfDriverCreateTableIndex"), + parameters: parse_quote! { + DriverObject: wdk_sys::PDRIVER_OBJECT, + RegistryPath: wdk_sys::PCUNICODE_STRING, + DriverAttributes: wdk_sys::PWDF_OBJECT_ATTRIBUTES, + DriverConfig: wdk_sys::PWDF_DRIVER_CONFIG, + Driver: *mut wdk_sys::WDFDRIVER + }, + parameter_identifiers: parse_quote! { + DriverObject, + RegistryPath, + DriverAttributes, + DriverConfig, + Driver + }, + return_type: parse_quote! { -> wdk_sys::NTSTATUS }, + arguments: parse_quote! { + driver, + registry_path, + WDF_NO_OBJECT_ATTRIBUTES, + &mut driver_config, + driver_handle_output, + }, + inline_wdf_fn_name: format_ident!("wdf_driver_create_impl"), + }; + + pretty_assert_eq!(inputs.generate_derived_ast_fragments().unwrap(), expected); + } + + #[test] + fn valid_input_with_no_arguments() { + let inputs = Inputs { + wdf_function_identifier: format_ident!("WdfVerifierDbgBreakPoint"), + wdf_function_arguments: Punctuated::new(), + }; + let expected = DerivedASTFragments { + function_pointer_type: format_ident!("PFN_WDFVERIFIERDBGBREAKPOINT"), + function_table_index: format_ident!("WdfVerifierDbgBreakPointTableIndex"), + parameters: Punctuated::new(), + parameter_identifiers: Punctuated::new(), + return_type: ReturnType::Default, + arguments: Punctuated::new(), + inline_wdf_fn_name: format_ident!("wdf_verifier_dbg_break_point_impl"), + }; + + pretty_assert_eq!(inputs.generate_derived_ast_fragments().unwrap(), expected); + } + } + } + + mod generate_parameters_and_return_type { + use super::*; + + #[test] + fn valid_input() { + let function_pointer_type = format_ident!("PFN_WDFIOQUEUEPURGESYNCHRONOUSLY"); + let expected = ( + parse_quote! { + Queue: wdk_sys::WDFQUEUE + }, + ReturnType::Default, + ); + + pretty_assert_eq!( + generate_parameters_and_return_type(&function_pointer_type).unwrap(), + expected + ); + } + } + + mod find_type_alias_definition { + use super::*; + + #[test] + fn valid_input() { + // This is just a snippet of a generated types.rs file + let types_rs_ast = parse_quote! { + pub type WDF_DRIVER_GLOBALS = _WDF_DRIVER_GLOBALS; + pub type PWDF_DRIVER_GLOBALS = *mut _WDF_DRIVER_GLOBALS; + pub mod _WDFFUNCENUM { + pub type Type = ::core::ffi::c_int; + pub const WdfChildListCreateTableIndex: Type = 0; + pub const WdfChildListGetDeviceTableIndex: Type = 1; + pub const WdfChildListRetrievePdoTableIndex: Type = 2; + pub const WdfChildListRetrieveAddressDescriptionTableIndex: Type = 3; + pub const WdfChildListBeginScanTableIndex: Type = 4; + pub const WdfChildListEndScanTableIndex: Type = 5; + pub const WdfChildListBeginIterationTableIndex: Type = 6; + pub const WdfChildListRetrieveNextDeviceTableIndex: Type = 7; + pub const WdfChildListEndIterationTableIndex: Type = 8; + pub const WdfChildListAddOrUpdateChildDescriptionAsPresentTableIndex: Type = 9; + pub const WdfChildListUpdateChildDescriptionAsMissingTableIndex: Type = 10; + pub const WdfChildListUpdateAllChildDescriptionsAsPresentTableIndex: Type = 11; + pub const WdfChildListRequestChildEjectTableIndex: Type = 12; } + pub type PFN_WDFGETTRIAGEINFO = ::core::option::Option< + unsafe extern "C" fn(DriverGlobals: PWDF_DRIVER_GLOBALS) -> PVOID, + >; + }; + let function_pointer_type = format_ident!("PFN_WDFGETTRIAGEINFO"); + let expected = parse_quote! { + pub type PFN_WDFGETTRIAGEINFO = ::core::option::Option< + unsafe extern "C" fn(DriverGlobals: PWDF_DRIVER_GLOBALS) -> PVOID, + >; }; + + pretty_assert_eq!( + find_type_alias_definition(&types_rs_ast, &function_pointer_type).unwrap(), + &expected + ); } + } - generate_macro_expansion_and_compilation_tests!( - wdf_driver_create, - wdf_device_create, - wdf_device_create_device_interface - ); + mod extract_fn_pointer_definition { + use super::*; + + #[test] + fn valid_input() { + let fn_type_alias = parse_quote! { + pub type PFN_WDFDRIVERCREATE = ::core::option::Option< + unsafe extern "C" fn( + DriverGlobals: PWDF_DRIVER_GLOBALS, + DriverObject: PDRIVER_OBJECT, + RegistryPath: PCUNICODE_STRING, + DriverAttributes: PWDF_OBJECT_ATTRIBUTES, + DriverConfig: PWDF_DRIVER_CONFIG, + Driver: *mut WDFDRIVER, + ) -> NTSTATUS + >; + }; + let expected = parse_quote! { + ::core::option::Option< + unsafe extern "C" fn( + DriverGlobals: PWDF_DRIVER_GLOBALS, + DriverObject: PDRIVER_OBJECT, + RegistryPath: PCUNICODE_STRING, + DriverAttributes: PWDF_OBJECT_ATTRIBUTES, + DriverConfig: PWDF_DRIVER_CONFIG, + Driver: *mut WDFDRIVER, + ) -> NTSTATUS + > + }; + + pretty_assert_eq!( + extract_fn_pointer_definition(&fn_type_alias, Span::call_site()).unwrap(), + &expected + ); + } + + #[test] + fn valid_input_with_no_arguments() { + let fn_type_alias = parse_quote! { + pub type PFN_WDFVERIFIERDBGBREAKPOINT = ::core::option::Option; + }; + let expected = parse_quote! { + ::core::option::Option + }; + + pretty_assert_eq!( + extract_fn_pointer_definition(&fn_type_alias, Span::call_site()).unwrap(), + &expected + ); + } } - mod macro_usage_errors { + mod parse_fn_pointer_definition { use super::*; - /// This test leverages `trybuild` to ensure that developer misuse of - /// the macro cause compilation failures, with an appropriate message #[test] - fn trybuild() { - trybuild::TestCases::new().compile_fail( - // canonicalization of this path causes a bug in `glob`: https://github.com/rust-lang/glob/issues/132 - TRYBUILD_FOLDER_PATH // .canonicalize()? - .join("*.rs"), + fn valid_input() { + // WdfDriverCreate has the following generated signature: + let fn_pointer_typepath = parse_quote! { + ::core::option::Option NTSTATUS> + }; + let expected = ( + parse_quote! { + DriverObject: wdk_sys::PDRIVER_OBJECT, + RegistryPath: wdk_sys::PCUNICODE_STRING, + DriverAttributes: wdk_sys::PWDF_OBJECT_ATTRIBUTES, + DriverConfig: wdk_sys::PWDF_DRIVER_CONFIG, + Driver: *mut wdk_sys::WDFDRIVER + }, + ReturnType::Type( + Token![->](Span::call_site()), + Box::new(Type::Path(parse_quote! { wdk_sys::NTSTATUS })), + ), + ); + + pretty_assert_eq!( + parse_fn_pointer_definition(&fn_pointer_typepath, Span::call_site()).unwrap(), + expected + ); + } + + #[test] + fn valid_input_with_no_arguments() { + // WdfVerifierDbgBreakPoint has the following generated signature: + let fn_pointer_typepath = parse_quote! { + ::core::option::Option + }; + let expected = (Punctuated::new(), ReturnType::Default); + + pretty_assert_eq!( + parse_fn_pointer_definition(&fn_pointer_typepath, Span::call_site()).unwrap(), + expected + ); + } + } + + mod extract_bare_fn_type { + use super::*; + + #[test] + fn valid_input() { + // WdfDriverCreate has the following generated signature: + let fn_pointer_typepath = parse_quote! { + ::core::option::Option< + unsafe extern "C" fn( + DriverGlobals: PWDF_DRIVER_GLOBALS, + DriverObject: PDRIVER_OBJECT, + RegistryPath: PCUNICODE_STRING, + DriverAttributes: PWDF_OBJECT_ATTRIBUTES, + DriverConfig: PWDF_DRIVER_CONFIG, + Driver: *mut WDFDRIVER, + ) -> NTSTATUS, + > + }; + let expected: TypeBareFn = parse_quote! { + unsafe extern "C" fn( + DriverGlobals: PWDF_DRIVER_GLOBALS, + DriverObject: PDRIVER_OBJECT, + RegistryPath: PCUNICODE_STRING, + DriverAttributes: PWDF_OBJECT_ATTRIBUTES, + DriverConfig: PWDF_DRIVER_CONFIG, + Driver: *mut WDFDRIVER, + ) -> NTSTATUS + }; + + pretty_assert_eq!( + extract_bare_fn_type(&fn_pointer_typepath, Span::call_site()).unwrap(), + &expected + ); + } + } + + mod compute_fn_parameters { + use super::*; + + #[test] + fn valid_input() { + // WdfDriverCreate has the following generated signature: + let bare_fn_type = parse_quote! { + unsafe extern "C" fn( + DriverGlobals: PWDF_DRIVER_GLOBALS, + DriverObject: PDRIVER_OBJECT, + RegistryPath: PCUNICODE_STRING, + DriverAttributes: PWDF_OBJECT_ATTRIBUTES, + DriverConfig: PWDF_DRIVER_CONFIG, + Driver: *mut WDFDRIVER, + ) -> NTSTATUS + }; + let expected = parse_quote! { + DriverObject: wdk_sys::PDRIVER_OBJECT, + RegistryPath: wdk_sys::PCUNICODE_STRING, + DriverAttributes: wdk_sys::PWDF_OBJECT_ATTRIBUTES, + DriverConfig: wdk_sys::PWDF_DRIVER_CONFIG, + Driver: *mut wdk_sys::WDFDRIVER + }; + + pretty_assert_eq!( + compute_fn_parameters(&bare_fn_type, Span::call_site()).unwrap(), + expected + ); + } + + #[test] + fn valid_input_with_no_arguments() { + // WdfVerifierDbgBreakPoint has the following generated signature: + let bare_fn_type = parse_quote! { + unsafe extern "C" fn(DriverGlobals: PWDF_DRIVER_GLOBALS) + }; + let expected = Punctuated::new(); + + pretty_assert_eq!( + compute_fn_parameters(&bare_fn_type, Span::call_site()).unwrap(), + expected + ); + } + } + + mod compute_return_type { + use super::*; + + #[test] + fn ntstatus() { + // WdfDriverCreate has the following generated signature: + let bare_fn_type = parse_quote! { + unsafe extern "C" fn( + DriverGlobals: PWDF_DRIVER_GLOBALS, + DriverObject: PDRIVER_OBJECT, + RegistryPath: PCUNICODE_STRING, + DriverAttributes: PWDF_OBJECT_ATTRIBUTES, + DriverConfig: PWDF_DRIVER_CONFIG, + Driver: *mut WDFDRIVER, + ) -> NTSTATUS + }; + let expected = ReturnType::Type( + Token![->](Span::call_site()), + Box::new(Type::Path(parse_quote! { wdk_sys::NTSTATUS })), + ); + + pretty_assert_eq!( + compute_return_type(&bare_fn_type, Span::call_site()).unwrap(), + expected + ); + } + + #[test] + fn unit() { + // WdfSpinLockAcquire has the following generated signature: + let bare_fn_type = parse_quote! { + unsafe extern "C" fn( + DriverGlobals: PWDF_DRIVER_GLOBALS, + SpinLock: WDFSPINLOCK + ) + }; + let expected = ReturnType::Default; + + pretty_assert_eq!( + compute_return_type(&bare_fn_type, Span::call_site()).unwrap(), + expected + ); + } + } + + mod generate_must_use_attribute { + use super::*; + + #[test] + fn unit_return_type() { + let return_type = ReturnType::Default; + let generated_must_use_attribute_tokens = generate_must_use_attribute(&return_type); + + pretty_assert_eq!(generated_must_use_attribute_tokens, None); + } + + #[test] + fn ntstatus_return_type() { + let return_type: ReturnType = parse_quote! { -> NTSTATUS }; + let expected_tokens = quote! { #[must_use] }; + let generated_must_use_attribute_tokens = generate_must_use_attribute(&return_type); + + pretty_assert_eq!( + generated_must_use_attribute_tokens + .unwrap() + .into_token_stream() + .to_string(), + expected_tokens.to_string(), ); } } diff --git a/crates/wdk-macros/tests/non-nightly/macrotest/wdf_device_create.rs b/crates/wdk-macros/tests/inputs/macrotest/wdf_device_create.rs similarity index 96% rename from crates/wdk-macros/tests/non-nightly/macrotest/wdf_device_create.rs rename to crates/wdk-macros/tests/inputs/macrotest/wdf_device_create.rs index d8d5ea0e..a112d726 100644 --- a/crates/wdk-macros/tests/non-nightly/macrotest/wdf_device_create.rs +++ b/crates/wdk-macros/tests/inputs/macrotest/wdf_device_create.rs @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation // License: MIT OR Apache-2.0 - #![no_main] +#![deny(warnings)] + use wdk_sys::*; extern "C" fn evt_driver_device_add( diff --git a/crates/wdk-macros/tests/non-nightly/macrotest/wdf_device_create_device_interface.rs b/crates/wdk-macros/tests/inputs/macrotest/wdf_device_create_device_interface.rs similarity index 97% rename from crates/wdk-macros/tests/non-nightly/macrotest/wdf_device_create_device_interface.rs rename to crates/wdk-macros/tests/inputs/macrotest/wdf_device_create_device_interface.rs index 067fd489..a87ed303 100644 --- a/crates/wdk-macros/tests/non-nightly/macrotest/wdf_device_create_device_interface.rs +++ b/crates/wdk-macros/tests/inputs/macrotest/wdf_device_create_device_interface.rs @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation // License: MIT OR Apache-2.0 - #![no_main] +#![deny(warnings)] + use wdk_sys::*; // {86E0D1E0-8089-11D0-9CE4-08003E301F73} diff --git a/crates/wdk-macros/tests/non-nightly/macrotest/wdf_driver_create.rs b/crates/wdk-macros/tests/inputs/macrotest/wdf_driver_create.rs similarity index 97% rename from crates/wdk-macros/tests/non-nightly/macrotest/wdf_driver_create.rs rename to crates/wdk-macros/tests/inputs/macrotest/wdf_driver_create.rs index 7b02c014..5ad59f6e 100644 --- a/crates/wdk-macros/tests/non-nightly/macrotest/wdf_driver_create.rs +++ b/crates/wdk-macros/tests/inputs/macrotest/wdf_driver_create.rs @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation // License: MIT OR Apache-2.0 - #![no_main] +#![deny(warnings)] + use wdk_sys::*; #[export_name = "DriverEntry"]// WDF expects a symbol with the name DriverEntry diff --git a/crates/wdk-macros/tests/inputs/macrotest/wdf_spin_lock_acquire.rs b/crates/wdk-macros/tests/inputs/macrotest/wdf_spin_lock_acquire.rs new file mode 100644 index 00000000..3d6ba611 --- /dev/null +++ b/crates/wdk-macros/tests/inputs/macrotest/wdf_spin_lock_acquire.rs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation +// License: MIT OR Apache-2.0 +#![no_main] +#![deny(warnings)] + +use wdk_sys::*; + +fn acquire_lock(wdf_spin_lock: WDFSPINLOCK) { + // This demonstrates that the macro won't trigger a must_use warning on WDF APIs that don't return a value + unsafe { + macros::call_unsafe_wdf_function_binding!(WdfSpinLockAcquire, wdf_spin_lock); + } +} diff --git a/crates/wdk-macros/tests/inputs/macrotest/wdf_verifier_dbg_break_point.rs b/crates/wdk-macros/tests/inputs/macrotest/wdf_verifier_dbg_break_point.rs new file mode 100644 index 00000000..fbf7b580 --- /dev/null +++ b/crates/wdk-macros/tests/inputs/macrotest/wdf_verifier_dbg_break_point.rs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation +// License: MIT OR Apache-2.0 +#![no_main] +#![deny(warnings)] + +#[allow(unused_imports)] // used by code generated by call_unsafe_wdf_function_binding +use wdk_sys::*; + +fn foo() { + unsafe { wdk_macros::call_unsafe_wdf_function_binding!(WdfVerifierDbgBreakPoint) } +} diff --git a/crates/wdk-macros/tests/non-nightly/trybuild/wdf_api_that_does_not_exist.rs b/crates/wdk-macros/tests/inputs/trybuild/wdf_api_that_does_not_exist.rs similarity index 84% rename from crates/wdk-macros/tests/non-nightly/trybuild/wdf_api_that_does_not_exist.rs rename to crates/wdk-macros/tests/inputs/trybuild/wdf_api_that_does_not_exist.rs index 22263449..67940609 100644 --- a/crates/wdk-macros/tests/non-nightly/trybuild/wdf_api_that_does_not_exist.rs +++ b/crates/wdk-macros/tests/inputs/trybuild/wdf_api_that_does_not_exist.rs @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation // License: MIT OR Apache-2.0 - #![no_main] +#![deny(warnings)] + use wdk_sys::*; #[export_name = "DriverEntry"]// WDF expects a symbol with the name DriverEntry @@ -9,6 +10,7 @@ pub extern "system" fn driver_entry( driver: &mut DRIVER_OBJECT, registry_path: PCUNICODE_STRING, ) -> NTSTATUS { + // WdfApiThatDoesNotExist is a WDF API that does not exist! unsafe { wdk_macros::call_unsafe_wdf_function_binding!( WdfApiThatDoesNotExist, diff --git a/crates/wdk-macros/tests/nightly/macrotest/wdf_device_create.rs b/crates/wdk-macros/tests/inputs/trybuild/wdf_device_create_unused_return_type.rs similarity index 83% rename from crates/wdk-macros/tests/nightly/macrotest/wdf_device_create.rs rename to crates/wdk-macros/tests/inputs/trybuild/wdf_device_create_unused_return_type.rs index 3fb13643..b5d3ab08 100644 --- a/crates/wdk-macros/tests/nightly/macrotest/wdf_device_create.rs +++ b/crates/wdk-macros/tests/inputs/trybuild/wdf_device_create_unused_return_type.rs @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation // License: MIT OR Apache-2.0 - #![no_main] -#![feature(hint_must_use)] +#![deny(warnings)] + use wdk_sys::*; extern "C" fn evt_driver_device_add( @@ -11,6 +11,7 @@ extern "C" fn evt_driver_device_add( ) -> NTSTATUS { let mut device_handle_output: WDFDEVICE = WDF_NO_HANDLE.cast(); + // The NTSTATUS return value of WdfDeviceCreate is unused! unsafe { wdk_macros::call_unsafe_wdf_function_binding!( WdfDeviceCreate, @@ -18,5 +19,7 @@ extern "C" fn evt_driver_device_add( WDF_NO_OBJECT_ATTRIBUTES, &mut device_handle_output, ) - } + }; + + 0 } diff --git a/crates/wdk-macros/tests/non-nightly/trybuild/wdf_driver_create_missing_arg.rs b/crates/wdk-macros/tests/inputs/trybuild/wdf_driver_create_missing_arg.rs similarity index 97% rename from crates/wdk-macros/tests/non-nightly/trybuild/wdf_driver_create_missing_arg.rs rename to crates/wdk-macros/tests/inputs/trybuild/wdf_driver_create_missing_arg.rs index d22e6bce..05b0dd4f 100644 --- a/crates/wdk-macros/tests/non-nightly/trybuild/wdf_driver_create_missing_arg.rs +++ b/crates/wdk-macros/tests/inputs/trybuild/wdf_driver_create_missing_arg.rs @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation // License: MIT OR Apache-2.0 - #![no_main] +#![deny(warnings)] + use wdk_sys::*; #[export_name = "DriverEntry"]// WDF expects a symbol with the name DriverEntry diff --git a/crates/wdk-macros/tests/non-nightly/trybuild/wdf_driver_create_wrong_arg_order.rs b/crates/wdk-macros/tests/inputs/trybuild/wdf_driver_create_wrong_arg_order.rs similarity index 97% rename from crates/wdk-macros/tests/non-nightly/trybuild/wdf_driver_create_wrong_arg_order.rs rename to crates/wdk-macros/tests/inputs/trybuild/wdf_driver_create_wrong_arg_order.rs index f66f5d19..d61ecb75 100644 --- a/crates/wdk-macros/tests/non-nightly/trybuild/wdf_driver_create_wrong_arg_order.rs +++ b/crates/wdk-macros/tests/inputs/trybuild/wdf_driver_create_wrong_arg_order.rs @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation // License: MIT OR Apache-2.0 - #![no_main] +#![deny(warnings)] + use wdk_sys::*; #[export_name = "DriverEntry"]// WDF expects a symbol with the name DriverEntry diff --git a/crates/wdk-macros/tests/inputs/trybuild/wdf_timer_create_missing_unsafe.rs b/crates/wdk-macros/tests/inputs/trybuild/wdf_timer_create_missing_unsafe.rs new file mode 100644 index 00000000..f3484e95 --- /dev/null +++ b/crates/wdk-macros/tests/inputs/trybuild/wdf_timer_create_missing_unsafe.rs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation +// License: MIT OR Apache-2.0 +#![no_main] +#![deny(warnings)] + +use wdk_sys::*; + +fn foo(timer_config: &mut WDF_TIMER_CONFIG, attributes: &mut WDF_OBJECT_ATTRIBUTES,) { + let mut timer = core::ptr::null_mut(); + let _nt_status = macros::call_unsafe_wdf_function_binding!( + WdfTimerCreate, + timer_config, + attributes, + &mut timer, + ); +} diff --git a/crates/wdk-macros/tests/integration_tests.rs b/crates/wdk-macros/tests/integration_tests.rs new file mode 100644 index 00000000..c44095a2 --- /dev/null +++ b/crates/wdk-macros/tests/integration_tests.rs @@ -0,0 +1,257 @@ +// Copyright (c) Microsoft Corporation +// License: MIT OR Apache-2.0 + +use std::{ + fs::File, + path::{Path, PathBuf}, +}; + +use fs4::FileExt; +use lazy_static::lazy_static; + +#[rustversion::stable] +const TOOLCHAIN_CHANNEL_NAME: &str = "stable"; + +#[rustversion::beta] +const TOOLCHAIN_CHANNEL_NAME: &str = "beta"; + +#[rustversion::nightly] +const TOOLCHAIN_CHANNEL_NAME: &str = "nightly"; + +lazy_static! { + static ref TESTS_FOLDER_PATH: PathBuf = [env!("CARGO_MANIFEST_DIR"), "tests"].iter().collect(); + static ref INPUTS_FOLDER_PATH: PathBuf = TESTS_FOLDER_PATH.join("inputs"); + static ref MACROTEST_INPUT_FOLDER_PATH: PathBuf = INPUTS_FOLDER_PATH.join("macrotest"); + static ref TRYBUILD_INPUT_FOLDER_PATH: PathBuf = INPUTS_FOLDER_PATH.join("trybuild"); + static ref OUTPUTS_FOLDER_PATH: PathBuf = TESTS_FOLDER_PATH.join("outputs"); + static ref TOOLCHAIN_SPECIFIC_OUTPUTS_FOLDER_PATH: PathBuf = + OUTPUTS_FOLDER_PATH.join(TOOLCHAIN_CHANNEL_NAME); + static ref MACROTEST_OUTPUT_FOLDER_PATH: PathBuf = + TOOLCHAIN_SPECIFIC_OUTPUTS_FOLDER_PATH.join("macrotest"); + static ref TRYBUILD_OUTPUT_FOLDER_PATH: PathBuf = + TOOLCHAIN_SPECIFIC_OUTPUTS_FOLDER_PATH.join("trybuild"); +} + +use std::{io::Write, stringify}; + +use owo_colors::OwoColorize; +use paste::paste; + +/// Given a filename `f` which contains code utilizing macros in +/// `wdk-macros`, generates a pair of tests to verify that code in `f` +/// expands as expected, and compiles successfully. The test output will +/// show `_expansion` as the names of the expansion tests and +/// `_compilation` as the name of the compilation test. `f` must +/// reside in the `tests/inputs/macrotest` folder, and may be a path to +/// a file relative to the `tests/inputs/macrotest` folder. This macro is +/// designed to use one test file per generated test to fully take advantage of +/// parallization of tests in cargo. +/// +/// Note: Due to limitations in `trybuild`, a successful compilation +/// test will include output that looks similar to the following: +/// ``` +/// test \\?\D:\git-repos\windows-drivers-rs\crates\wdk-macros\tests\macrotest\wdf_driver_create.rs ... error +/// Expected test case to fail to compile, but it succeeded. +/// ``` +/// This is because `trybuild` will run `cargo check` when calling +/// `TestCases::compile_fail`, but will run `cargo build` if calling +/// `TestCases::pass`. `cargo build` will fail at link stage due to +/// `trybuild` not allowing configuration to compile as a`cdylib`. To +/// work around this, `compile_fail` is used, and we mark the test as +/// expecting to panic with a specific message using the `should_panic` +/// attribute macro. +macro_rules! generate_macrotest_tests { + ($($filename:ident),+) => { + paste! { + + // This module's tests are deliberately not feature-gated by #[cfg(feature = "nightly")] and #[cfg(not(feature = "nightly"))] since macrotest can control whether to expand with the nightly feature or not + mod macro_expansion { + use super::*; + + $( + #[test] + fn [<$filename _expansion>]() { + let symlink_target = &MACROTEST_INPUT_FOLDER_PATH.join(format!("{}.rs", stringify!($filename))); + let symlink_path = &MACROTEST_OUTPUT_FOLDER_PATH.join(format!("{}.rs", stringify!($filename))); + create_symlink_if_nonexistent(symlink_path, symlink_target); + macrotest::expand(symlink_path); + } + )? + + mod nightly_feature { + use super::*; + + $( + #[test] + fn [<$filename _expansion>]() { + let symlink_target = &MACROTEST_INPUT_FOLDER_PATH.join(format!("{}.rs", stringify!($filename))); + let symlink_path = &MACROTEST_OUTPUT_FOLDER_PATH.join(format!("{}.rs", stringify!($filename))); + create_symlink_if_nonexistent(symlink_path, symlink_target); + macrotest::expand_args( + symlink_path, &["--features", "nightly"]); + } + )? + } + } + + mod macro_compilation { + use super::*; + + pub trait TestCasesExt { + fn pass_cargo_check + std::panic::UnwindSafe>(path: P); + } + + impl TestCasesExt for trybuild::TestCases { + fn pass_cargo_check + std::panic::UnwindSafe>(path: P) { + // "compile_fail" tests that pass cargo check result in this panic message + const SUCCESSFUL_CARGO_CHECK_STRING: &str = "1 of 1 tests failed"; + + let path = path.as_ref(); + + let failed_cargo_check = !std::panic::catch_unwind(|| { + // A new TestCases is required because it relies on running the tests upon drop + trybuild::TestCases::new().compile_fail(path); + }) + .is_err_and(|cause| { + if let Some(str) = cause.downcast_ref::<&str>() { + *str == SUCCESSFUL_CARGO_CHECK_STRING + } else if let Some(string) = cause.downcast_ref::() { + string == SUCCESSFUL_CARGO_CHECK_STRING + } else { + // Unexpected panic trait object type + false + } + }); + + if failed_cargo_check { + let failed_cargo_check_msg = format!( + "{}{}", + path.to_string_lossy().bold().red(), + " failed Cargo Check!".bold().red() + ); + + // Use writeln! to print even without passing --nocapture to the test harness + writeln!(&mut std::io::stderr(), "{failed_cargo_check_msg}").unwrap(); + + panic!("{failed_cargo_check_msg}"); + } else { + // Use writeln! to print even without passing --nocapture to the test harness + writeln!( + &mut std::io::stderr(), + "{}{}{}{}{}", + "Please ignore the above \"Expected test case to fail to compile, but it \ + succeeded.\" message (and its accompanying \"1 of 1 tests failed\" panic \ + message when run with --nocapture).\n" + .italic() + .yellow(), + "test ".bold(), + path.to_string_lossy().bold(), + " ... ".bold(), + "PASSED".bold().green() + ).unwrap(); + } + } + } + + $( + #[cfg(not(feature = "nightly"))] + #[test] + fn [<$filename _compilation>]() { + let symlink_target = &MACROTEST_INPUT_FOLDER_PATH.join(format!("{}.rs", stringify!($filename))); + let symlink_path = &MACROTEST_OUTPUT_FOLDER_PATH.join(format!("{}.rs", stringify!($filename))); + create_symlink_if_nonexistent(symlink_path, symlink_target); + trybuild::TestCases::pass_cargo_check(symlink_path); + } + )? + + #[cfg(feature = "nightly")] + mod nightly_feature { + use super::*; + + $( + #[test] + fn [<$filename _compilation>]() { + let symlink_target = &MACROTEST_INPUT_FOLDER_PATH.join(format!("{}.rs", stringify!($filename))); + let symlink_path = &MACROTEST_OUTPUT_FOLDER_PATH.join(format!("{}.rs", stringify!($filename))); + create_symlink_if_nonexistent(symlink_path, symlink_target); + trybuild::TestCases::pass_cargo_check(symlink_path); + } + )? + } + } + } + }; +} + +macro_rules! generate_trybuild_tests { + ($($filename:ident),+) => { + mod macro_usage_errors { + use super::*; + + /// This test leverages `trybuild` to ensure that developer misuse of + /// the macro cause compilation failures, with an appropriate message + $( + #[test] + fn $filename() { + let symlink_target = &TRYBUILD_INPUT_FOLDER_PATH.join(format!("{}.rs", stringify!($filename))); + let symlink_path = &TRYBUILD_OUTPUT_FOLDER_PATH.join(format!("{}.rs", stringify!($filename))); + create_symlink_if_nonexistent(symlink_path, symlink_target); + trybuild::TestCases::new().compile_fail(symlink_path); + } + )? + } + }; + +} + +fn create_symlink_if_nonexistent(link: &Path, target: &Path) { + // Use relative paths for symlink creation + let relative_target_path = + pathdiff::diff_paths(target, link.parent().expect("link.parent() should exist")) + .expect("target path should be resolvable as relative to link"); + + // Lock based off target_file so tests can run in parallel + let target_file = File::open( + target + .canonicalize() + .expect("canonicalize of symlink target should succeed"), + ) + .expect("target file should be successfully opened"); + target_file + .lock_exclusive() + .expect("exclusive lock should be successfully acquired"); + + // Only create a new symlink if there isn't an existing one, or if the existing + // one points to the wrong place + if !link.exists() { + std::os::windows::fs::symlink_file(relative_target_path, link) + .expect("symlink creation should succeed"); + } else if !link.is_symlink() + || std::fs::read_link(link).expect("read_link of symlink should succeed") != target + { + std::fs::remove_file(link).expect("stale symlink removal should succeed"); + // wait for deletion to complete + while !matches!(link.try_exists(), Ok(false)) {} + + std::os::windows::fs::symlink_file(relative_target_path, link) + .expect("symlink creation should succeed"); + } else { + // symlink already exists and points to the correct place + } +} + +generate_macrotest_tests!( + wdf_driver_create, + wdf_device_create, + wdf_device_create_device_interface, + wdf_spin_lock_acquire, + wdf_verifier_dbg_break_point +); + +generate_trybuild_tests!( + wdf_api_that_does_not_exist, + wdf_device_create_unused_return_type, + wdf_driver_create_missing_arg, + wdf_driver_create_wrong_arg_order, + wdf_timer_create_missing_unsafe +); diff --git a/crates/wdk-macros/tests/nightly/macrotest/wdf_device_create.expanded.rs b/crates/wdk-macros/tests/nightly/macrotest/wdf_device_create.expanded.rs deleted file mode 100644 index e368767f..00000000 --- a/crates/wdk-macros/tests/nightly/macrotest/wdf_device_create.expanded.rs +++ /dev/null @@ -1,45 +0,0 @@ -#![no_main] -#![feature(hint_must_use)] -use wdk_sys::*; -extern "C" fn evt_driver_device_add( - _driver: WDFDRIVER, - mut device_init: *mut WDFDEVICE_INIT, -) -> NTSTATUS { - let mut device_handle_output: WDFDEVICE = WDF_NO_HANDLE.cast(); - unsafe { - core::hint::must_use({ - unsafe fn force_unsafe() {} - force_unsafe(); - let wdf_function: wdk_sys::PFN_WDFDEVICECREATE = Some( - #[allow(unused_unsafe)] - #[allow(clippy::multiple_unsafe_ops_per_block)] - unsafe { - core::mem::transmute( - wdk_sys::WDF_FUNCTION_TABLE[wdk_sys::_WDFFUNCENUM::WdfDeviceCreateTableIndex - as usize], - ) - }, - ); - if let Some(wdf_function) = wdf_function { - #[allow(unused_unsafe)] #[allow(clippy::multiple_unsafe_ops_per_block)] - unsafe { - (wdf_function)( - wdk_sys::WdfDriverGlobals, - &mut device_init, - WDF_NO_OBJECT_ATTRIBUTES, - &mut device_handle_output, - ) - } - } else { - { - ::core::panicking::panic_fmt( - format_args!( - "internal error: entered unreachable code: {0}", - format_args!("Option should never be None"), - ), - ); - }; - } - }) - } -} diff --git a/crates/wdk-macros/tests/nightly/macrotest/wdf_device_create_device_interface.expanded.rs b/crates/wdk-macros/tests/nightly/macrotest/wdf_device_create_device_interface.expanded.rs deleted file mode 100644 index d1b07eb8..00000000 --- a/crates/wdk-macros/tests/nightly/macrotest/wdf_device_create_device_interface.expanded.rs +++ /dev/null @@ -1,47 +0,0 @@ -#![no_main] -#![feature(hint_must_use)] -use wdk_sys::*; -const GUID_DEVINTERFACE_COMPORT: GUID = GUID { - Data1: 0x86E0D1E0u32, - Data2: 0x8089u16, - Data3: 0x11D0u16, - Data4: [0x9Cu8, 0xE4u8, 0x08u8, 0x00u8, 0x3Eu8, 0x30u8, 0x1Fu8, 0x73u8], -}; -fn create_device_interface(wdf_device: WDFDEVICE) -> NTSTATUS { - unsafe { - core::hint::must_use({ - unsafe fn force_unsafe() {} - force_unsafe(); - let wdf_function: wdk_sys::PFN_WDFDEVICECREATEDEVICEINTERFACE = Some( - #[allow(unused_unsafe)] - #[allow(clippy::multiple_unsafe_ops_per_block)] - unsafe { - core::mem::transmute( - wdk_sys::WDF_FUNCTION_TABLE[wdk_sys::_WDFFUNCENUM::WdfDeviceCreateDeviceInterfaceTableIndex - as usize], - ) - }, - ); - if let Some(wdf_function) = wdf_function { - #[allow(unused_unsafe)] #[allow(clippy::multiple_unsafe_ops_per_block)] - unsafe { - (wdf_function)( - wdk_sys::WdfDriverGlobals, - wdf_device, - &GUID_DEVINTERFACE_COMPORT, - core::ptr::null(), - ) - } - } else { - { - ::core::panicking::panic_fmt( - format_args!( - "internal error: entered unreachable code: {0}", - format_args!("Option should never be None"), - ), - ); - }; - } - }) - } -} diff --git a/crates/wdk-macros/tests/nightly/macrotest/wdf_device_create_device_interface.rs b/crates/wdk-macros/tests/nightly/macrotest/wdf_device_create_device_interface.rs deleted file mode 100644 index d53ecb1c..00000000 --- a/crates/wdk-macros/tests/nightly/macrotest/wdf_device_create_device_interface.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft Corporation -// License: MIT OR Apache-2.0 - -#![no_main] -#![feature(hint_must_use)] -use wdk_sys::*; - -// {86E0D1E0-8089-11D0-9CE4-08003E301F73} -const GUID_DEVINTERFACE_COMPORT: GUID = GUID { - Data1: 0x86E0D1E0u32, - Data2: 0x8089u16, - Data3: 0x11D0u16, - Data4: [0x9Cu8, 0xE4u8, 0x08u8, 0x00u8, 0x3Eu8, 0x30u8, 0x1Fu8, 0x73u8], -}; - -fn create_device_interface(wdf_device: WDFDEVICE) -> NTSTATUS { - unsafe { - wdk_macros::call_unsafe_wdf_function_binding!( - WdfDeviceCreateDeviceInterface, - wdf_device, - &GUID_DEVINTERFACE_COMPORT, - core::ptr::null(), - ) - } -} diff --git a/crates/wdk-macros/tests/nightly/macrotest/wdf_driver_create.expanded.rs b/crates/wdk-macros/tests/nightly/macrotest/wdf_driver_create.expanded.rs deleted file mode 100644 index 9764e38a..00000000 --- a/crates/wdk-macros/tests/nightly/macrotest/wdf_driver_create.expanded.rs +++ /dev/null @@ -1,52 +0,0 @@ -#![no_main] -#![feature(hint_must_use)] -use wdk_sys::*; -#[export_name = "DriverEntry"] -pub extern "system" fn driver_entry( - driver: &mut DRIVER_OBJECT, - registry_path: PCUNICODE_STRING, -) -> NTSTATUS { - let mut driver_config = WDF_DRIVER_CONFIG { - Size: core::mem::size_of::() as ULONG, - ..WDF_DRIVER_CONFIG::default() - }; - let driver_handle_output = WDF_NO_HANDLE as *mut WDFDRIVER; - unsafe { - core::hint::must_use({ - unsafe fn force_unsafe() {} - force_unsafe(); - let wdf_function: wdk_sys::PFN_WDFDRIVERCREATE = Some( - #[allow(unused_unsafe)] - #[allow(clippy::multiple_unsafe_ops_per_block)] - unsafe { - core::mem::transmute( - wdk_sys::WDF_FUNCTION_TABLE[wdk_sys::_WDFFUNCENUM::WdfDriverCreateTableIndex - as usize], - ) - }, - ); - if let Some(wdf_function) = wdf_function { - #[allow(unused_unsafe)] #[allow(clippy::multiple_unsafe_ops_per_block)] - unsafe { - (wdf_function)( - wdk_sys::WdfDriverGlobals, - driver as PDRIVER_OBJECT, - registry_path, - WDF_NO_OBJECT_ATTRIBUTES, - &mut driver_config, - driver_handle_output, - ) - } - } else { - { - ::core::panicking::panic_fmt( - format_args!( - "internal error: entered unreachable code: {0}", - format_args!("Option should never be None"), - ), - ); - }; - } - }) - } -} diff --git a/crates/wdk-macros/tests/nightly/macrotest/wdf_driver_create.rs b/crates/wdk-macros/tests/nightly/macrotest/wdf_driver_create.rs deleted file mode 100644 index 981a4a2d..00000000 --- a/crates/wdk-macros/tests/nightly/macrotest/wdf_driver_create.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) Microsoft Corporation -// License: MIT OR Apache-2.0 - -#![no_main] -#![feature(hint_must_use)] -use wdk_sys::*; - -#[export_name = "DriverEntry"]// WDF expects a symbol with the name DriverEntry -pub extern "system" fn driver_entry( - driver: &mut DRIVER_OBJECT, - registry_path: PCUNICODE_STRING, -) -> NTSTATUS { - let mut driver_config = WDF_DRIVER_CONFIG { - Size: core::mem::size_of::() as ULONG, - ..WDF_DRIVER_CONFIG::default() - }; - let driver_handle_output = WDF_NO_HANDLE as *mut WDFDRIVER; - - unsafe { - wdk_macros::call_unsafe_wdf_function_binding!( - WdfDriverCreate, - driver as PDRIVER_OBJECT, - registry_path, - WDF_NO_OBJECT_ATTRIBUTES, - &mut driver_config, - driver_handle_output, - ) - } -} diff --git a/crates/wdk-macros/tests/nightly/trybuild/wdf_api_that_does_not_exist.rs b/crates/wdk-macros/tests/nightly/trybuild/wdf_api_that_does_not_exist.rs deleted file mode 100644 index 71e1dc79..00000000 --- a/crates/wdk-macros/tests/nightly/trybuild/wdf_api_that_does_not_exist.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Microsoft Corporation -// License: MIT OR Apache-2.0 - -#![no_main] -#![feature(hint_must_use)] -use wdk_sys::*; - -#[export_name = "DriverEntry"]// WDF expects a symbol with the name DriverEntry -pub extern "system" fn driver_entry( - driver: &mut DRIVER_OBJECT, - registry_path: PCUNICODE_STRING, -) -> NTSTATUS { - unsafe { - wdk_macros::call_unsafe_wdf_function_binding!( - WdfApiThatDoesNotExist, - driver as PDRIVER_OBJECT, - ) - } -} diff --git a/crates/wdk-macros/tests/nightly/trybuild/wdf_api_that_does_not_exist.stderr b/crates/wdk-macros/tests/nightly/trybuild/wdf_api_that_does_not_exist.stderr deleted file mode 100644 index fbe07aa5..00000000 --- a/crates/wdk-macros/tests/nightly/trybuild/wdf_api_that_does_not_exist.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0412]: cannot find type `PFN_WDFAPITHATDOESNOTEXIST` in crate `wdk_sys` - --> tests/nightly/trybuild/wdf_api_that_does_not_exist.rs - | - | / wdk_macros::call_unsafe_wdf_function_binding!( - | | WdfApiThatDoesNotExist, - | | driver as PDRIVER_OBJECT, - | | ) - | |_________^ not found in `wdk_sys` - | - = note: this error originates in the macro `wdk_macros::call_unsafe_wdf_function_binding` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0425]: cannot find value `WdfApiThatDoesNotExistTableIndex` in module `wdk_sys::_WDFFUNCENUM` - --> tests/nightly/trybuild/wdf_api_that_does_not_exist.rs - | - | / wdk_macros::call_unsafe_wdf_function_binding!( - | | WdfApiThatDoesNotExist, - | | driver as PDRIVER_OBJECT, - | | ) - | |_________^ not found in `wdk_sys::_WDFFUNCENUM` - | - = note: this error originates in the macro `wdk_macros::call_unsafe_wdf_function_binding` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/crates/wdk-macros/tests/nightly/trybuild/wdf_driver_create_missing_arg.rs b/crates/wdk-macros/tests/nightly/trybuild/wdf_driver_create_missing_arg.rs deleted file mode 100644 index a1fdb086..00000000 --- a/crates/wdk-macros/tests/nightly/trybuild/wdf_driver_create_missing_arg.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Microsoft Corporation -// License: MIT OR Apache-2.0 - -#![no_main] -#![feature(hint_must_use)] -use wdk_sys::*; - -#[export_name = "DriverEntry"]// WDF expects a symbol with the name DriverEntry -pub extern "system" fn driver_entry( - driver: &mut DRIVER_OBJECT, - registry_path: PCUNICODE_STRING, -) -> NTSTATUS { - let mut driver_config = WDF_DRIVER_CONFIG { - Size: core::mem::size_of::() as ULONG, - ..WDF_DRIVER_CONFIG::default() - }; - let driver_handle_output = WDF_NO_HANDLE as *mut WDFDRIVER; - - unsafe { - wdk_macros::call_unsafe_wdf_function_binding!( - WdfDriverCreate, - driver as PDRIVER_OBJECT, - registry_path, - // The object attributes are missing from this call! - // WDF_NO_OBJECT_ATTRIBUTES, - &mut driver_config, - driver_handle_output, - ) - } -} diff --git a/crates/wdk-macros/tests/nightly/trybuild/wdf_driver_create_missing_arg.stderr b/crates/wdk-macros/tests/nightly/trybuild/wdf_driver_create_missing_arg.stderr deleted file mode 100644 index 6b3a18da..00000000 --- a/crates/wdk-macros/tests/nightly/trybuild/wdf_driver_create_missing_arg.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error[E0061]: this function takes 6 arguments but 5 arguments were supplied - --> tests/nightly/trybuild/wdf_driver_create_missing_arg.rs - | - | / wdk_macros::call_unsafe_wdf_function_binding!( - | | WdfDriverCreate, - | | driver as PDRIVER_OBJECT, - | | registry_path, -... | - | | &mut driver_config, - | | ------------------ an argument of type `*mut _WDF_OBJECT_ATTRIBUTES` is missing - | | driver_handle_output, - | | ) - | |_________^ - | - = note: this error originates in the macro `wdk_macros::call_unsafe_wdf_function_binding` (in Nightly builds, run with -Z macro-backtrace for more info) -help: provide the argument - | -28 ~ )(wdk_macros::call_unsafe_wdf_function_binding!( -29 + WdfDriverCreate, -30 + driver as PDRIVER_OBJECT, -31 + registry_path, -32 + // The object attributes are missing from this call! -33 + // WDF_NO_OBJECT_ATTRIBUTES, -34 + &mut driver_config, -35 + driver_handle_output, -36 + ), driver as PDRIVER_OBJECT, registry_path, /* *mut _WDF_OBJECT_ATTRIBUTES */, &mut driver_config, driver_handle_output) - | diff --git a/crates/wdk-macros/tests/nightly/trybuild/wdf_driver_create_wrong_arg_order.rs b/crates/wdk-macros/tests/nightly/trybuild/wdf_driver_create_wrong_arg_order.rs deleted file mode 100644 index d0fa8b79..00000000 --- a/crates/wdk-macros/tests/nightly/trybuild/wdf_driver_create_wrong_arg_order.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Microsoft Corporation -// License: MIT OR Apache-2.0 - -#![no_main] -#![feature(hint_must_use)] -use wdk_sys::*; - -#[export_name = "DriverEntry"]// WDF expects a symbol with the name DriverEntry -pub extern "system" fn driver_entry( - driver: &mut DRIVER_OBJECT, - registry_path: PCUNICODE_STRING, -) -> NTSTATUS { - let mut driver_config = WDF_DRIVER_CONFIG { - Size: core::mem::size_of::() as ULONG, - ..WDF_DRIVER_CONFIG::default() - }; - let driver_handle_output = WDF_NO_HANDLE as *mut WDFDRIVER; - - unsafe { - wdk_macros::call_unsafe_wdf_function_binding!( - WdfDriverCreate, - driver as PDRIVER_OBJECT, - registry_path, - // The order of the next two arguments is swapped! - &mut driver_config, - WDF_NO_OBJECT_ATTRIBUTES, - driver_handle_output, - ) - } -} diff --git a/crates/wdk-macros/tests/nightly/trybuild/wdf_driver_create_wrong_arg_order.stderr b/crates/wdk-macros/tests/nightly/trybuild/wdf_driver_create_wrong_arg_order.stderr deleted file mode 100644 index 61f0d458..00000000 --- a/crates/wdk-macros/tests/nightly/trybuild/wdf_driver_create_wrong_arg_order.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error[E0308]: arguments to this function are incorrect - --> tests/nightly/trybuild/wdf_driver_create_wrong_arg_order.rs - | - | / wdk_macros::call_unsafe_wdf_function_binding!( - | | WdfDriverCreate, - | | driver as PDRIVER_OBJECT, - | | registry_path, - | | // The order of the next two arguments is swapped! - | | &mut driver_config, - | | ------------------ expected `*mut _WDF_OBJECT_ATTRIBUTES`, found `&mut _WDF_DRIVER_CONFIG` - | | WDF_NO_OBJECT_ATTRIBUTES, - | | ------------------------ expected `*mut _WDF_DRIVER_CONFIG`, found `*mut _WDF_OBJECT_ATTRIBUTES` - | | driver_handle_output, - | | ) - | |_________^ - | - = note: this error originates in the macro `wdk_macros::call_unsafe_wdf_function_binding` (in Nightly builds, run with -Z macro-backtrace for more info) -help: swap these arguments - | -28 ~ )(wdk_macros::call_unsafe_wdf_function_binding!( -29 + WdfDriverCreate, -30 + driver as PDRIVER_OBJECT, -31 + registry_path, -32 + // The order of the next two arguments is swapped! -33 + &mut driver_config, -34 + WDF_NO_OBJECT_ATTRIBUTES, -35 + driver_handle_output, -36 + ), driver as PDRIVER_OBJECT, registry_path, WDF_NO_OBJECT_ATTRIBUTES, &mut driver_config, driver_handle_output) - | diff --git a/crates/wdk-macros/tests/non-nightly/macrotest/wdf_device_create.expanded.rs b/crates/wdk-macros/tests/non-nightly/macrotest/wdf_device_create.expanded.rs deleted file mode 100644 index d667df58..00000000 --- a/crates/wdk-macros/tests/non-nightly/macrotest/wdf_device_create.expanded.rs +++ /dev/null @@ -1,44 +0,0 @@ -#![no_main] -use wdk_sys::*; -extern "C" fn evt_driver_device_add( - _driver: WDFDRIVER, - mut device_init: *mut WDFDEVICE_INIT, -) -> NTSTATUS { - let mut device_handle_output: WDFDEVICE = WDF_NO_HANDLE.cast(); - unsafe { - { - unsafe fn force_unsafe() {} - force_unsafe(); - let wdf_function: wdk_sys::PFN_WDFDEVICECREATE = Some( - #[allow(unused_unsafe)] - #[allow(clippy::multiple_unsafe_ops_per_block)] - unsafe { - core::mem::transmute( - wdk_sys::WDF_FUNCTION_TABLE[wdk_sys::_WDFFUNCENUM::WdfDeviceCreateTableIndex - as usize], - ) - }, - ); - if let Some(wdf_function) = wdf_function { - #[allow(unused_unsafe)] #[allow(clippy::multiple_unsafe_ops_per_block)] - unsafe { - (wdf_function)( - wdk_sys::WdfDriverGlobals, - &mut device_init, - WDF_NO_OBJECT_ATTRIBUTES, - &mut device_handle_output, - ) - } - } else { - { - ::core::panicking::panic_fmt( - format_args!( - "internal error: entered unreachable code: {0}", - format_args!("Option should never be None"), - ), - ); - }; - } - } - } -} diff --git a/crates/wdk-macros/tests/non-nightly/macrotest/wdf_device_create_device_interface.expanded.rs b/crates/wdk-macros/tests/non-nightly/macrotest/wdf_device_create_device_interface.expanded.rs deleted file mode 100644 index 2fa5f7bf..00000000 --- a/crates/wdk-macros/tests/non-nightly/macrotest/wdf_device_create_device_interface.expanded.rs +++ /dev/null @@ -1,46 +0,0 @@ -#![no_main] -use wdk_sys::*; -const GUID_DEVINTERFACE_COMPORT: GUID = GUID { - Data1: 0x86E0D1E0u32, - Data2: 0x8089u16, - Data3: 0x11D0u16, - Data4: [0x9Cu8, 0xE4u8, 0x08u8, 0x00u8, 0x3Eu8, 0x30u8, 0x1Fu8, 0x73u8], -}; -fn create_device_interface(wdf_device: WDFDEVICE) -> NTSTATUS { - unsafe { - { - unsafe fn force_unsafe() {} - force_unsafe(); - let wdf_function: wdk_sys::PFN_WDFDEVICECREATEDEVICEINTERFACE = Some( - #[allow(unused_unsafe)] - #[allow(clippy::multiple_unsafe_ops_per_block)] - unsafe { - core::mem::transmute( - wdk_sys::WDF_FUNCTION_TABLE[wdk_sys::_WDFFUNCENUM::WdfDeviceCreateDeviceInterfaceTableIndex - as usize], - ) - }, - ); - if let Some(wdf_function) = wdf_function { - #[allow(unused_unsafe)] #[allow(clippy::multiple_unsafe_ops_per_block)] - unsafe { - (wdf_function)( - wdk_sys::WdfDriverGlobals, - wdf_device, - &GUID_DEVINTERFACE_COMPORT, - core::ptr::null(), - ) - } - } else { - { - ::core::panicking::panic_fmt( - format_args!( - "internal error: entered unreachable code: {0}", - format_args!("Option should never be None"), - ), - ); - }; - } - } - } -} diff --git a/crates/wdk-macros/tests/non-nightly/macrotest/wdf_driver_create.expanded.rs b/crates/wdk-macros/tests/non-nightly/macrotest/wdf_driver_create.expanded.rs deleted file mode 100644 index 8370b086..00000000 --- a/crates/wdk-macros/tests/non-nightly/macrotest/wdf_driver_create.expanded.rs +++ /dev/null @@ -1,51 +0,0 @@ -#![no_main] -use wdk_sys::*; -#[export_name = "DriverEntry"] -pub extern "system" fn driver_entry( - driver: &mut DRIVER_OBJECT, - registry_path: PCUNICODE_STRING, -) -> NTSTATUS { - let mut driver_config = WDF_DRIVER_CONFIG { - Size: core::mem::size_of::() as ULONG, - ..WDF_DRIVER_CONFIG::default() - }; - let driver_handle_output = WDF_NO_HANDLE as *mut WDFDRIVER; - unsafe { - { - unsafe fn force_unsafe() {} - force_unsafe(); - let wdf_function: wdk_sys::PFN_WDFDRIVERCREATE = Some( - #[allow(unused_unsafe)] - #[allow(clippy::multiple_unsafe_ops_per_block)] - unsafe { - core::mem::transmute( - wdk_sys::WDF_FUNCTION_TABLE[wdk_sys::_WDFFUNCENUM::WdfDriverCreateTableIndex - as usize], - ) - }, - ); - if let Some(wdf_function) = wdf_function { - #[allow(unused_unsafe)] #[allow(clippy::multiple_unsafe_ops_per_block)] - unsafe { - (wdf_function)( - wdk_sys::WdfDriverGlobals, - driver as PDRIVER_OBJECT, - registry_path, - WDF_NO_OBJECT_ATTRIBUTES, - &mut driver_config, - driver_handle_output, - ) - } - } else { - { - ::core::panicking::panic_fmt( - format_args!( - "internal error: entered unreachable code: {0}", - format_args!("Option should never be None"), - ), - ); - }; - } - } - } -} diff --git a/crates/wdk-macros/tests/non-nightly/trybuild/wdf_api_that_does_not_exist.stderr b/crates/wdk-macros/tests/non-nightly/trybuild/wdf_api_that_does_not_exist.stderr deleted file mode 100644 index 9994fd11..00000000 --- a/crates/wdk-macros/tests/non-nightly/trybuild/wdf_api_that_does_not_exist.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0412]: cannot find type `PFN_WDFAPITHATDOESNOTEXIST` in crate `wdk_sys` - --> tests/non-nightly/trybuild/wdf_api_that_does_not_exist.rs - | - | / wdk_macros::call_unsafe_wdf_function_binding!( - | | WdfApiThatDoesNotExist, - | | driver as PDRIVER_OBJECT, - | | ) - | |_________^ not found in `wdk_sys` - | - = note: this error originates in the macro `wdk_macros::call_unsafe_wdf_function_binding` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0425]: cannot find value `WdfApiThatDoesNotExistTableIndex` in module `wdk_sys::_WDFFUNCENUM` - --> tests/non-nightly/trybuild/wdf_api_that_does_not_exist.rs - | - | / wdk_macros::call_unsafe_wdf_function_binding!( - | | WdfApiThatDoesNotExist, - | | driver as PDRIVER_OBJECT, - | | ) - | |_________^ not found in `wdk_sys::_WDFFUNCENUM` - | - = note: this error originates in the macro `wdk_macros::call_unsafe_wdf_function_binding` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/crates/wdk-macros/tests/non-nightly/trybuild/wdf_driver_create_missing_arg.stderr b/crates/wdk-macros/tests/non-nightly/trybuild/wdf_driver_create_missing_arg.stderr deleted file mode 100644 index e898b4eb..00000000 --- a/crates/wdk-macros/tests/non-nightly/trybuild/wdf_driver_create_missing_arg.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error[E0061]: this function takes 6 arguments but 5 arguments were supplied - --> tests/non-nightly/trybuild/wdf_driver_create_missing_arg.rs - | - | / wdk_macros::call_unsafe_wdf_function_binding!( - | | WdfDriverCreate, - | | driver as PDRIVER_OBJECT, - | | registry_path, -... | - | | &mut driver_config, - | | ------------------ an argument of type `*mut _WDF_OBJECT_ATTRIBUTES` is missing - | | driver_handle_output, - | | ) - | |_________^ - | - = note: this error originates in the macro `wdk_macros::call_unsafe_wdf_function_binding` (in Nightly builds, run with -Z macro-backtrace for more info) -help: provide the argument - | -27 ~ )(wdk_macros::call_unsafe_wdf_function_binding!( -28 + WdfDriverCreate, -29 + driver as PDRIVER_OBJECT, -30 + registry_path, -31 + // The object attributes are missing from this call! -32 + // WDF_NO_OBJECT_ATTRIBUTES, -33 + &mut driver_config, -34 + driver_handle_output, -35 + ), driver as PDRIVER_OBJECT, registry_path, /* *mut _WDF_OBJECT_ATTRIBUTES */, &mut driver_config, driver_handle_output) - | diff --git a/crates/wdk-macros/tests/non-nightly/trybuild/wdf_driver_create_wrong_arg_order.stderr b/crates/wdk-macros/tests/non-nightly/trybuild/wdf_driver_create_wrong_arg_order.stderr deleted file mode 100644 index 460008af..00000000 --- a/crates/wdk-macros/tests/non-nightly/trybuild/wdf_driver_create_wrong_arg_order.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error[E0308]: arguments to this function are incorrect - --> tests/non-nightly/trybuild/wdf_driver_create_wrong_arg_order.rs - | - | / wdk_macros::call_unsafe_wdf_function_binding!( - | | WdfDriverCreate, - | | driver as PDRIVER_OBJECT, - | | registry_path, - | | // The order of the next two arguments is swapped! - | | &mut driver_config, - | | ------------------ expected `*mut _WDF_OBJECT_ATTRIBUTES`, found `&mut _WDF_DRIVER_CONFIG` - | | WDF_NO_OBJECT_ATTRIBUTES, - | | ------------------------ expected `*mut _WDF_DRIVER_CONFIG`, found `*mut _WDF_OBJECT_ATTRIBUTES` - | | driver_handle_output, - | | ) - | |_________^ - | - = note: this error originates in the macro `wdk_macros::call_unsafe_wdf_function_binding` (in Nightly builds, run with -Z macro-backtrace for more info) -help: swap these arguments - | -27 ~ )(wdk_macros::call_unsafe_wdf_function_binding!( -28 + WdfDriverCreate, -29 + driver as PDRIVER_OBJECT, -30 + registry_path, -31 + // The order of the next two arguments is swapped! -32 + &mut driver_config, -33 + WDF_NO_OBJECT_ATTRIBUTES, -34 + driver_handle_output, -35 + ), driver as PDRIVER_OBJECT, registry_path, WDF_NO_OBJECT_ATTRIBUTES, &mut driver_config, driver_handle_output) - | diff --git a/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_device_create.expanded.rs b/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_device_create.expanded.rs new file mode 100644 index 00000000..0493e6bd --- /dev/null +++ b/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_device_create.expanded.rs @@ -0,0 +1,51 @@ +#![no_main] +#![deny(warnings)] +use wdk_sys::*; +extern "C" fn evt_driver_device_add( + _driver: WDFDRIVER, + mut device_init: *mut WDFDEVICE_INIT, +) -> NTSTATUS { + let mut device_handle_output: WDFDEVICE = WDF_NO_HANDLE.cast(); + unsafe { + { + #[must_use] + #[inline(always)] + unsafe fn wdf_device_create_impl( + DeviceInit: *mut wdk_sys::PWDFDEVICE_INIT, + DeviceAttributes: wdk_sys::PWDF_OBJECT_ATTRIBUTES, + Device: *mut wdk_sys::WDFDEVICE, + ) -> wdk_sys::NTSTATUS { + let wdf_function: wdk_sys::PFN_WDFDEVICECREATE = Some(unsafe { + core::mem::transmute( + wdk_sys::WDF_FUNCTION_TABLE[wdk_sys::_WDFFUNCENUM::WdfDeviceCreateTableIndex + as usize], + ) + }); + if let Some(wdf_function) = wdf_function { + unsafe { + (wdf_function)( + wdk_sys::WdfDriverGlobals, + DeviceInit, + DeviceAttributes, + Device, + ) + } + } else { + { + ::core::panicking::panic_fmt( + format_args!( + "internal error: entered unreachable code: {0}", + format_args!("Option should never be None"), + ), + ); + }; + } + } + wdf_device_create_impl( + &mut device_init, + WDF_NO_OBJECT_ATTRIBUTES, + &mut device_handle_output, + ) + } + } +} diff --git a/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_device_create.rs b/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_device_create.rs new file mode 120000 index 00000000..20bd5908 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_device_create.rs @@ -0,0 +1 @@ +../../../inputs/macrotest/wdf_device_create.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_device_create_device_interface.expanded.rs b/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_device_create_device_interface.expanded.rs new file mode 100644 index 00000000..afd81d27 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_device_create_device_interface.expanded.rs @@ -0,0 +1,53 @@ +#![no_main] +#![deny(warnings)] +use wdk_sys::*; +const GUID_DEVINTERFACE_COMPORT: GUID = GUID { + Data1: 0x86E0D1E0u32, + Data2: 0x8089u16, + Data3: 0x11D0u16, + Data4: [0x9Cu8, 0xE4u8, 0x08u8, 0x00u8, 0x3Eu8, 0x30u8, 0x1Fu8, 0x73u8], +}; +fn create_device_interface(wdf_device: WDFDEVICE) -> NTSTATUS { + unsafe { + { + #[must_use] + #[inline(always)] + unsafe fn wdf_device_create_device_interface_impl( + Device: wdk_sys::WDFDEVICE, + InterfaceClassGUID: *const wdk_sys::GUID, + ReferenceString: wdk_sys::PCUNICODE_STRING, + ) -> wdk_sys::NTSTATUS { + let wdf_function: wdk_sys::PFN_WDFDEVICECREATEDEVICEINTERFACE = Some(unsafe { + core::mem::transmute( + wdk_sys::WDF_FUNCTION_TABLE[wdk_sys::_WDFFUNCENUM::WdfDeviceCreateDeviceInterfaceTableIndex + as usize], + ) + }); + if let Some(wdf_function) = wdf_function { + unsafe { + (wdf_function)( + wdk_sys::WdfDriverGlobals, + Device, + InterfaceClassGUID, + ReferenceString, + ) + } + } else { + { + ::core::panicking::panic_fmt( + format_args!( + "internal error: entered unreachable code: {0}", + format_args!("Option should never be None"), + ), + ); + }; + } + } + wdf_device_create_device_interface_impl( + wdf_device, + &GUID_DEVINTERFACE_COMPORT, + core::ptr::null(), + ) + } + } +} diff --git a/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_device_create_device_interface.rs b/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_device_create_device_interface.rs new file mode 120000 index 00000000..e9f8c16b --- /dev/null +++ b/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_device_create_device_interface.rs @@ -0,0 +1 @@ +../../../inputs/macrotest/wdf_device_create_device_interface.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_driver_create.expanded.rs b/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_driver_create.expanded.rs new file mode 100644 index 00000000..ab9abe4a --- /dev/null +++ b/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_driver_create.expanded.rs @@ -0,0 +1,62 @@ +#![no_main] +#![deny(warnings)] +use wdk_sys::*; +#[export_name = "DriverEntry"] +pub extern "system" fn driver_entry( + driver: &mut DRIVER_OBJECT, + registry_path: PCUNICODE_STRING, +) -> NTSTATUS { + let mut driver_config = WDF_DRIVER_CONFIG { + Size: core::mem::size_of::() as ULONG, + ..WDF_DRIVER_CONFIG::default() + }; + let driver_handle_output = WDF_NO_HANDLE as *mut WDFDRIVER; + unsafe { + { + #[must_use] + #[inline(always)] + unsafe fn wdf_driver_create_impl( + DriverObject: wdk_sys::PDRIVER_OBJECT, + RegistryPath: wdk_sys::PCUNICODE_STRING, + DriverAttributes: wdk_sys::PWDF_OBJECT_ATTRIBUTES, + DriverConfig: wdk_sys::PWDF_DRIVER_CONFIG, + Driver: *mut wdk_sys::WDFDRIVER, + ) -> wdk_sys::NTSTATUS { + let wdf_function: wdk_sys::PFN_WDFDRIVERCREATE = Some(unsafe { + core::mem::transmute( + wdk_sys::WDF_FUNCTION_TABLE[wdk_sys::_WDFFUNCENUM::WdfDriverCreateTableIndex + as usize], + ) + }); + if let Some(wdf_function) = wdf_function { + unsafe { + (wdf_function)( + wdk_sys::WdfDriverGlobals, + DriverObject, + RegistryPath, + DriverAttributes, + DriverConfig, + Driver, + ) + } + } else { + { + ::core::panicking::panic_fmt( + format_args!( + "internal error: entered unreachable code: {0}", + format_args!("Option should never be None"), + ), + ); + }; + } + } + wdf_driver_create_impl( + driver as PDRIVER_OBJECT, + registry_path, + WDF_NO_OBJECT_ATTRIBUTES, + &mut driver_config, + driver_handle_output, + ) + } + } +} diff --git a/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_driver_create.rs b/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_driver_create.rs new file mode 120000 index 00000000..570f030b --- /dev/null +++ b/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_driver_create.rs @@ -0,0 +1 @@ +../../../inputs/macrotest/wdf_driver_create.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_spin_lock_acquire.expanded.rs b/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_spin_lock_acquire.expanded.rs new file mode 100644 index 00000000..1ba0841a --- /dev/null +++ b/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_spin_lock_acquire.expanded.rs @@ -0,0 +1,31 @@ +#![no_main] +#![deny(warnings)] +use wdk_sys::*; +fn acquire_lock(wdf_spin_lock: WDFSPINLOCK) { + unsafe { + { + #[inline(always)] + unsafe fn wdf_spin_lock_acquire_impl(SpinLock: wdk_sys::WDFSPINLOCK) { + let wdf_function: wdk_sys::PFN_WDFSPINLOCKACQUIRE = Some(unsafe { + core::mem::transmute( + wdk_sys::WDF_FUNCTION_TABLE[wdk_sys::_WDFFUNCENUM::WdfSpinLockAcquireTableIndex + as usize], + ) + }); + if let Some(wdf_function) = wdf_function { + unsafe { (wdf_function)(wdk_sys::WdfDriverGlobals, SpinLock) } + } else { + { + ::core::panicking::panic_fmt( + format_args!( + "internal error: entered unreachable code: {0}", + format_args!("Option should never be None"), + ), + ); + }; + } + } + wdf_spin_lock_acquire_impl(wdf_spin_lock) + }; + } +} diff --git a/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_spin_lock_acquire.rs b/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_spin_lock_acquire.rs new file mode 120000 index 00000000..e77fcc3f --- /dev/null +++ b/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_spin_lock_acquire.rs @@ -0,0 +1 @@ +../../../inputs/macrotest/wdf_spin_lock_acquire.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_verifier_dbg_break_point.expanded.rs b/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_verifier_dbg_break_point.expanded.rs new file mode 100644 index 00000000..ae3e107c --- /dev/null +++ b/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_verifier_dbg_break_point.expanded.rs @@ -0,0 +1,32 @@ +#![no_main] +#![deny(warnings)] +#[allow(unused_imports)] +use wdk_sys::*; +fn foo() { + unsafe { + { + #[inline(always)] + unsafe fn wdf_verifier_dbg_break_point_impl() { + let wdf_function: wdk_sys::PFN_WDFVERIFIERDBGBREAKPOINT = Some(unsafe { + core::mem::transmute( + wdk_sys::WDF_FUNCTION_TABLE[wdk_sys::_WDFFUNCENUM::WdfVerifierDbgBreakPointTableIndex + as usize], + ) + }); + if let Some(wdf_function) = wdf_function { + unsafe { (wdf_function)(wdk_sys::WdfDriverGlobals) } + } else { + { + ::core::panicking::panic_fmt( + format_args!( + "internal error: entered unreachable code: {0}", + format_args!("Option should never be None"), + ), + ); + }; + } + } + wdf_verifier_dbg_break_point_impl() + } + } +} diff --git a/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_verifier_dbg_break_point.rs b/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_verifier_dbg_break_point.rs new file mode 120000 index 00000000..f2bb2b51 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/beta/macrotest/wdf_verifier_dbg_break_point.rs @@ -0,0 +1 @@ +../../../inputs/macrotest/wdf_verifier_dbg_break_point.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_api_that_does_not_exist.rs b/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_api_that_does_not_exist.rs new file mode 120000 index 00000000..14059dc8 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_api_that_does_not_exist.rs @@ -0,0 +1 @@ +../../../inputs/trybuild/wdf_api_that_does_not_exist.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_api_that_does_not_exist.stderr b/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_api_that_does_not_exist.stderr new file mode 100644 index 00000000..4759c378 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_api_that_does_not_exist.stderr @@ -0,0 +1,5 @@ +error: Failed to find type alias definition for PFN_WDFAPITHATDOESNOTEXIST + --> tests/outputs/beta/trybuild/wdf_api_that_does_not_exist.rs + | + | WdfApiThatDoesNotExist, + | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_device_create_unused_return_type.rs b/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_device_create_unused_return_type.rs new file mode 120000 index 00000000..94c8088d --- /dev/null +++ b/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_device_create_unused_return_type.rs @@ -0,0 +1 @@ +../../../inputs/trybuild/wdf_device_create_unused_return_type.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_device_create_unused_return_type.stderr b/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_device_create_unused_return_type.stderr new file mode 100644 index 00000000..8fd0325b --- /dev/null +++ b/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_device_create_unused_return_type.stderr @@ -0,0 +1,18 @@ +error: unused return value of `wdf_device_create_impl` that must be used + --> tests/outputs/beta/trybuild/wdf_device_create_unused_return_type.rs + | + | / wdk_macros::call_unsafe_wdf_function_binding!( + | | WdfDeviceCreate, + | | &mut device_init, + | | WDF_NO_OBJECT_ATTRIBUTES, + | | &mut device_handle_output, + | | ) + | |_________^ + | +note: the lint level is defined here + --> tests/outputs/beta/trybuild/wdf_device_create_unused_return_type.rs + | + | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(unused_must_use)]` implied by `#[deny(warnings)]` + = note: this error originates in the macro `wdk_macros::call_unsafe_wdf_function_binding` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_driver_create_missing_arg.rs b/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_driver_create_missing_arg.rs new file mode 120000 index 00000000..a3123ce4 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_driver_create_missing_arg.rs @@ -0,0 +1 @@ +../../../inputs/trybuild/wdf_driver_create_missing_arg.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_driver_create_missing_arg.stderr b/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_driver_create_missing_arg.stderr new file mode 100644 index 00000000..6bcf0ec5 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_driver_create_missing_arg.stderr @@ -0,0 +1,35 @@ +error[E0061]: this function takes 5 arguments but 4 arguments were supplied + --> tests/outputs/beta/trybuild/wdf_driver_create_missing_arg.rs + | + | / wdk_macros::call_unsafe_wdf_function_binding!( + | | WdfDriverCreate, + | | driver as PDRIVER_OBJECT, + | | registry_path, +... | + | | &mut driver_config, + | | ------------------ an argument of type `*mut _WDF_OBJECT_ATTRIBUTES` is missing + | | driver_handle_output, + | | ) + | |_________^ + | +note: function defined here + --> tests/outputs/beta/trybuild/wdf_driver_create_missing_arg.rs + | + | / wdk_macros::call_unsafe_wdf_function_binding!( + | | WdfDriverCreate, + | | driver as PDRIVER_OBJECT, + | | registry_path, +... | + | | driver_handle_output, + | | ) + | |_________^ + | |_________| + | |_________| + | |_________| + | |_________| + | + = note: this error originates in the macro `wdk_macros::call_unsafe_wdf_function_binding` (in Nightly builds, run with -Z macro-backtrace for more info) +help: provide the argument + | +28 | )(driver as PDRIVER_OBJECT, registry_path, /* *mut _WDF_OBJECT_ATTRIBUTES */, &mut driver_config, driver_handle_output) + | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_driver_create_wrong_arg_order.rs b/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_driver_create_wrong_arg_order.rs new file mode 120000 index 00000000..ff8e6c8f --- /dev/null +++ b/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_driver_create_wrong_arg_order.rs @@ -0,0 +1 @@ +../../../inputs/trybuild/wdf_driver_create_wrong_arg_order.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_driver_create_wrong_arg_order.stderr b/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_driver_create_wrong_arg_order.stderr new file mode 100644 index 00000000..b275f134 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_driver_create_wrong_arg_order.stderr @@ -0,0 +1,37 @@ +error[E0308]: arguments to this function are incorrect + --> tests/outputs/beta/trybuild/wdf_driver_create_wrong_arg_order.rs + | + | / wdk_macros::call_unsafe_wdf_function_binding!( + | | WdfDriverCreate, + | | driver as PDRIVER_OBJECT, + | | registry_path, + | | // The order of the next two arguments is swapped! + | | &mut driver_config, + | | ------------------ expected `*mut _WDF_OBJECT_ATTRIBUTES`, found `&mut _WDF_DRIVER_CONFIG` + | | WDF_NO_OBJECT_ATTRIBUTES, + | | ------------------------ expected `*mut _WDF_DRIVER_CONFIG`, found `*mut _WDF_OBJECT_ATTRIBUTES` + | | driver_handle_output, + | | ) + | |_________^ + | +note: function defined here + --> tests/outputs/beta/trybuild/wdf_driver_create_wrong_arg_order.rs + | + | / wdk_macros::call_unsafe_wdf_function_binding!( + | | WdfDriverCreate, + | | driver as PDRIVER_OBJECT, + | | registry_path, +... | + | | driver_handle_output, + | | ) + | |_________^ + | |_________| + | |_________| + | |_________| + | |_________| + | + = note: this error originates in the macro `wdk_macros::call_unsafe_wdf_function_binding` (in Nightly builds, run with -Z macro-backtrace for more info) +help: swap these arguments + | +28 | )(driver as PDRIVER_OBJECT, registry_path, WDF_NO_OBJECT_ATTRIBUTES, &mut driver_config, driver_handle_output) + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_timer_create_missing_unsafe.rs b/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_timer_create_missing_unsafe.rs new file mode 120000 index 00000000..4a715fd0 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_timer_create_missing_unsafe.rs @@ -0,0 +1 @@ +../../../inputs/trybuild/wdf_timer_create_missing_unsafe.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_timer_create_missing_unsafe.stderr b/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_timer_create_missing_unsafe.stderr new file mode 100644 index 00000000..5575407b --- /dev/null +++ b/crates/wdk-macros/tests/outputs/beta/trybuild/wdf_timer_create_missing_unsafe.stderr @@ -0,0 +1,14 @@ +error[E0133]: call to unsafe function `wdf_timer_create_impl` is unsafe and requires unsafe function or block + --> tests/outputs/beta/trybuild/wdf_timer_create_missing_unsafe.rs + | + | let _nt_status = macros::call_unsafe_wdf_function_binding!( + | ______________________^ + | | WdfTimerCreate, + | | timer_config, + | | attributes, + | | &mut timer, + | | ); + | |_____^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + = note: this error originates in the macro `macros::call_unsafe_wdf_function_binding` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_device_create.expanded.rs b/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_device_create.expanded.rs new file mode 100644 index 00000000..0493e6bd --- /dev/null +++ b/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_device_create.expanded.rs @@ -0,0 +1,51 @@ +#![no_main] +#![deny(warnings)] +use wdk_sys::*; +extern "C" fn evt_driver_device_add( + _driver: WDFDRIVER, + mut device_init: *mut WDFDEVICE_INIT, +) -> NTSTATUS { + let mut device_handle_output: WDFDEVICE = WDF_NO_HANDLE.cast(); + unsafe { + { + #[must_use] + #[inline(always)] + unsafe fn wdf_device_create_impl( + DeviceInit: *mut wdk_sys::PWDFDEVICE_INIT, + DeviceAttributes: wdk_sys::PWDF_OBJECT_ATTRIBUTES, + Device: *mut wdk_sys::WDFDEVICE, + ) -> wdk_sys::NTSTATUS { + let wdf_function: wdk_sys::PFN_WDFDEVICECREATE = Some(unsafe { + core::mem::transmute( + wdk_sys::WDF_FUNCTION_TABLE[wdk_sys::_WDFFUNCENUM::WdfDeviceCreateTableIndex + as usize], + ) + }); + if let Some(wdf_function) = wdf_function { + unsafe { + (wdf_function)( + wdk_sys::WdfDriverGlobals, + DeviceInit, + DeviceAttributes, + Device, + ) + } + } else { + { + ::core::panicking::panic_fmt( + format_args!( + "internal error: entered unreachable code: {0}", + format_args!("Option should never be None"), + ), + ); + }; + } + } + wdf_device_create_impl( + &mut device_init, + WDF_NO_OBJECT_ATTRIBUTES, + &mut device_handle_output, + ) + } + } +} diff --git a/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_device_create.rs b/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_device_create.rs new file mode 120000 index 00000000..20bd5908 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_device_create.rs @@ -0,0 +1 @@ +../../../inputs/macrotest/wdf_device_create.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_device_create_device_interface.expanded.rs b/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_device_create_device_interface.expanded.rs new file mode 100644 index 00000000..afd81d27 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_device_create_device_interface.expanded.rs @@ -0,0 +1,53 @@ +#![no_main] +#![deny(warnings)] +use wdk_sys::*; +const GUID_DEVINTERFACE_COMPORT: GUID = GUID { + Data1: 0x86E0D1E0u32, + Data2: 0x8089u16, + Data3: 0x11D0u16, + Data4: [0x9Cu8, 0xE4u8, 0x08u8, 0x00u8, 0x3Eu8, 0x30u8, 0x1Fu8, 0x73u8], +}; +fn create_device_interface(wdf_device: WDFDEVICE) -> NTSTATUS { + unsafe { + { + #[must_use] + #[inline(always)] + unsafe fn wdf_device_create_device_interface_impl( + Device: wdk_sys::WDFDEVICE, + InterfaceClassGUID: *const wdk_sys::GUID, + ReferenceString: wdk_sys::PCUNICODE_STRING, + ) -> wdk_sys::NTSTATUS { + let wdf_function: wdk_sys::PFN_WDFDEVICECREATEDEVICEINTERFACE = Some(unsafe { + core::mem::transmute( + wdk_sys::WDF_FUNCTION_TABLE[wdk_sys::_WDFFUNCENUM::WdfDeviceCreateDeviceInterfaceTableIndex + as usize], + ) + }); + if let Some(wdf_function) = wdf_function { + unsafe { + (wdf_function)( + wdk_sys::WdfDriverGlobals, + Device, + InterfaceClassGUID, + ReferenceString, + ) + } + } else { + { + ::core::panicking::panic_fmt( + format_args!( + "internal error: entered unreachable code: {0}", + format_args!("Option should never be None"), + ), + ); + }; + } + } + wdf_device_create_device_interface_impl( + wdf_device, + &GUID_DEVINTERFACE_COMPORT, + core::ptr::null(), + ) + } + } +} diff --git a/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_device_create_device_interface.rs b/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_device_create_device_interface.rs new file mode 120000 index 00000000..e9f8c16b --- /dev/null +++ b/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_device_create_device_interface.rs @@ -0,0 +1 @@ +../../../inputs/macrotest/wdf_device_create_device_interface.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_driver_create.expanded.rs b/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_driver_create.expanded.rs new file mode 100644 index 00000000..ab9abe4a --- /dev/null +++ b/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_driver_create.expanded.rs @@ -0,0 +1,62 @@ +#![no_main] +#![deny(warnings)] +use wdk_sys::*; +#[export_name = "DriverEntry"] +pub extern "system" fn driver_entry( + driver: &mut DRIVER_OBJECT, + registry_path: PCUNICODE_STRING, +) -> NTSTATUS { + let mut driver_config = WDF_DRIVER_CONFIG { + Size: core::mem::size_of::() as ULONG, + ..WDF_DRIVER_CONFIG::default() + }; + let driver_handle_output = WDF_NO_HANDLE as *mut WDFDRIVER; + unsafe { + { + #[must_use] + #[inline(always)] + unsafe fn wdf_driver_create_impl( + DriverObject: wdk_sys::PDRIVER_OBJECT, + RegistryPath: wdk_sys::PCUNICODE_STRING, + DriverAttributes: wdk_sys::PWDF_OBJECT_ATTRIBUTES, + DriverConfig: wdk_sys::PWDF_DRIVER_CONFIG, + Driver: *mut wdk_sys::WDFDRIVER, + ) -> wdk_sys::NTSTATUS { + let wdf_function: wdk_sys::PFN_WDFDRIVERCREATE = Some(unsafe { + core::mem::transmute( + wdk_sys::WDF_FUNCTION_TABLE[wdk_sys::_WDFFUNCENUM::WdfDriverCreateTableIndex + as usize], + ) + }); + if let Some(wdf_function) = wdf_function { + unsafe { + (wdf_function)( + wdk_sys::WdfDriverGlobals, + DriverObject, + RegistryPath, + DriverAttributes, + DriverConfig, + Driver, + ) + } + } else { + { + ::core::panicking::panic_fmt( + format_args!( + "internal error: entered unreachable code: {0}", + format_args!("Option should never be None"), + ), + ); + }; + } + } + wdf_driver_create_impl( + driver as PDRIVER_OBJECT, + registry_path, + WDF_NO_OBJECT_ATTRIBUTES, + &mut driver_config, + driver_handle_output, + ) + } + } +} diff --git a/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_driver_create.rs b/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_driver_create.rs new file mode 120000 index 00000000..570f030b --- /dev/null +++ b/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_driver_create.rs @@ -0,0 +1 @@ +../../../inputs/macrotest/wdf_driver_create.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_spin_lock_acquire.expanded.rs b/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_spin_lock_acquire.expanded.rs new file mode 100644 index 00000000..1ba0841a --- /dev/null +++ b/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_spin_lock_acquire.expanded.rs @@ -0,0 +1,31 @@ +#![no_main] +#![deny(warnings)] +use wdk_sys::*; +fn acquire_lock(wdf_spin_lock: WDFSPINLOCK) { + unsafe { + { + #[inline(always)] + unsafe fn wdf_spin_lock_acquire_impl(SpinLock: wdk_sys::WDFSPINLOCK) { + let wdf_function: wdk_sys::PFN_WDFSPINLOCKACQUIRE = Some(unsafe { + core::mem::transmute( + wdk_sys::WDF_FUNCTION_TABLE[wdk_sys::_WDFFUNCENUM::WdfSpinLockAcquireTableIndex + as usize], + ) + }); + if let Some(wdf_function) = wdf_function { + unsafe { (wdf_function)(wdk_sys::WdfDriverGlobals, SpinLock) } + } else { + { + ::core::panicking::panic_fmt( + format_args!( + "internal error: entered unreachable code: {0}", + format_args!("Option should never be None"), + ), + ); + }; + } + } + wdf_spin_lock_acquire_impl(wdf_spin_lock) + }; + } +} diff --git a/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_spin_lock_acquire.rs b/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_spin_lock_acquire.rs new file mode 120000 index 00000000..e77fcc3f --- /dev/null +++ b/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_spin_lock_acquire.rs @@ -0,0 +1 @@ +../../../inputs/macrotest/wdf_spin_lock_acquire.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_verifier_dbg_break_point.expanded.rs b/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_verifier_dbg_break_point.expanded.rs new file mode 100644 index 00000000..ae3e107c --- /dev/null +++ b/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_verifier_dbg_break_point.expanded.rs @@ -0,0 +1,32 @@ +#![no_main] +#![deny(warnings)] +#[allow(unused_imports)] +use wdk_sys::*; +fn foo() { + unsafe { + { + #[inline(always)] + unsafe fn wdf_verifier_dbg_break_point_impl() { + let wdf_function: wdk_sys::PFN_WDFVERIFIERDBGBREAKPOINT = Some(unsafe { + core::mem::transmute( + wdk_sys::WDF_FUNCTION_TABLE[wdk_sys::_WDFFUNCENUM::WdfVerifierDbgBreakPointTableIndex + as usize], + ) + }); + if let Some(wdf_function) = wdf_function { + unsafe { (wdf_function)(wdk_sys::WdfDriverGlobals) } + } else { + { + ::core::panicking::panic_fmt( + format_args!( + "internal error: entered unreachable code: {0}", + format_args!("Option should never be None"), + ), + ); + }; + } + } + wdf_verifier_dbg_break_point_impl() + } + } +} diff --git a/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_verifier_dbg_break_point.rs b/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_verifier_dbg_break_point.rs new file mode 120000 index 00000000..f2bb2b51 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/nightly/macrotest/wdf_verifier_dbg_break_point.rs @@ -0,0 +1 @@ +../../../inputs/macrotest/wdf_verifier_dbg_break_point.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_api_that_does_not_exist.rs b/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_api_that_does_not_exist.rs new file mode 120000 index 00000000..14059dc8 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_api_that_does_not_exist.rs @@ -0,0 +1 @@ +../../../inputs/trybuild/wdf_api_that_does_not_exist.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_api_that_does_not_exist.stderr b/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_api_that_does_not_exist.stderr new file mode 100644 index 00000000..54e0d700 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_api_that_does_not_exist.stderr @@ -0,0 +1,5 @@ +error: Failed to find type alias definition for PFN_WDFAPITHATDOESNOTEXIST + --> tests/outputs/nightly/trybuild/wdf_api_that_does_not_exist.rs + | + | WdfApiThatDoesNotExist, + | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_device_create_unused_return_type.rs b/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_device_create_unused_return_type.rs new file mode 120000 index 00000000..94c8088d --- /dev/null +++ b/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_device_create_unused_return_type.rs @@ -0,0 +1 @@ +../../../inputs/trybuild/wdf_device_create_unused_return_type.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_device_create_unused_return_type.stderr b/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_device_create_unused_return_type.stderr new file mode 100644 index 00000000..6a23741c --- /dev/null +++ b/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_device_create_unused_return_type.stderr @@ -0,0 +1,18 @@ +error: unused return value of `wdf_device_create_impl` that must be used + --> tests/outputs/nightly/trybuild/wdf_device_create_unused_return_type.rs + | + | / wdk_macros::call_unsafe_wdf_function_binding!( + | | WdfDeviceCreate, + | | &mut device_init, + | | WDF_NO_OBJECT_ATTRIBUTES, + | | &mut device_handle_output, + | | ) + | |_________^ + | +note: the lint level is defined here + --> tests/outputs/nightly/trybuild/wdf_device_create_unused_return_type.rs + | + | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(unused_must_use)]` implied by `#[deny(warnings)]` + = note: this error originates in the macro `wdk_macros::call_unsafe_wdf_function_binding` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_driver_create_missing_arg.rs b/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_driver_create_missing_arg.rs new file mode 120000 index 00000000..a3123ce4 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_driver_create_missing_arg.rs @@ -0,0 +1 @@ +../../../inputs/trybuild/wdf_driver_create_missing_arg.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_driver_create_missing_arg.stderr b/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_driver_create_missing_arg.stderr new file mode 100644 index 00000000..a394afdb --- /dev/null +++ b/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_driver_create_missing_arg.stderr @@ -0,0 +1,35 @@ +error[E0061]: this function takes 5 arguments but 4 arguments were supplied + --> tests/outputs/nightly/trybuild/wdf_driver_create_missing_arg.rs + | + | / wdk_macros::call_unsafe_wdf_function_binding!( + | | WdfDriverCreate, + | | driver as PDRIVER_OBJECT, + | | registry_path, +... | + | | &mut driver_config, + | | ------------------ an argument of type `*mut _WDF_OBJECT_ATTRIBUTES` is missing + | | driver_handle_output, + | | ) + | |_________^ + | +note: function defined here + --> tests/outputs/nightly/trybuild/wdf_driver_create_missing_arg.rs + | + | / wdk_macros::call_unsafe_wdf_function_binding!( + | | WdfDriverCreate, + | | driver as PDRIVER_OBJECT, + | | registry_path, +... | + | | driver_handle_output, + | | ) + | |_________^ + | |_________| + | |_________| + | |_________| + | |_________| + | + = note: this error originates in the macro `wdk_macros::call_unsafe_wdf_function_binding` (in Nightly builds, run with -Z macro-backtrace for more info) +help: provide the argument + | +28 | )(driver as PDRIVER_OBJECT, registry_path, /* *mut _WDF_OBJECT_ATTRIBUTES */, &mut driver_config, driver_handle_output) + | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_driver_create_wrong_arg_order.rs b/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_driver_create_wrong_arg_order.rs new file mode 120000 index 00000000..ff8e6c8f --- /dev/null +++ b/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_driver_create_wrong_arg_order.rs @@ -0,0 +1 @@ +../../../inputs/trybuild/wdf_driver_create_wrong_arg_order.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_driver_create_wrong_arg_order.stderr b/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_driver_create_wrong_arg_order.stderr new file mode 100644 index 00000000..61c1bd51 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_driver_create_wrong_arg_order.stderr @@ -0,0 +1,37 @@ +error[E0308]: arguments to this function are incorrect + --> tests/outputs/nightly/trybuild/wdf_driver_create_wrong_arg_order.rs + | + | / wdk_macros::call_unsafe_wdf_function_binding!( + | | WdfDriverCreate, + | | driver as PDRIVER_OBJECT, + | | registry_path, + | | // The order of the next two arguments is swapped! + | | &mut driver_config, + | | ------------------ expected `*mut _WDF_OBJECT_ATTRIBUTES`, found `&mut _WDF_DRIVER_CONFIG` + | | WDF_NO_OBJECT_ATTRIBUTES, + | | ------------------------ expected `*mut _WDF_DRIVER_CONFIG`, found `*mut _WDF_OBJECT_ATTRIBUTES` + | | driver_handle_output, + | | ) + | |_________^ + | +note: function defined here + --> tests/outputs/nightly/trybuild/wdf_driver_create_wrong_arg_order.rs + | + | / wdk_macros::call_unsafe_wdf_function_binding!( + | | WdfDriverCreate, + | | driver as PDRIVER_OBJECT, + | | registry_path, +... | + | | driver_handle_output, + | | ) + | |_________^ + | |_________| + | |_________| + | |_________| + | |_________| + | + = note: this error originates in the macro `wdk_macros::call_unsafe_wdf_function_binding` (in Nightly builds, run with -Z macro-backtrace for more info) +help: swap these arguments + | +28 | )(driver as PDRIVER_OBJECT, registry_path, WDF_NO_OBJECT_ATTRIBUTES, &mut driver_config, driver_handle_output) + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_timer_create_missing_unsafe.rs b/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_timer_create_missing_unsafe.rs new file mode 120000 index 00000000..4a715fd0 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_timer_create_missing_unsafe.rs @@ -0,0 +1 @@ +../../../inputs/trybuild/wdf_timer_create_missing_unsafe.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_timer_create_missing_unsafe.stderr b/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_timer_create_missing_unsafe.stderr new file mode 100644 index 00000000..c2f6a1eb --- /dev/null +++ b/crates/wdk-macros/tests/outputs/nightly/trybuild/wdf_timer_create_missing_unsafe.stderr @@ -0,0 +1,14 @@ +error[E0133]: call to unsafe function `wdf_timer_create_impl` is unsafe and requires unsafe function or block + --> tests/outputs/nightly/trybuild/wdf_timer_create_missing_unsafe.rs + | + | let _nt_status = macros::call_unsafe_wdf_function_binding!( + | ______________________^ + | | WdfTimerCreate, + | | timer_config, + | | attributes, + | | &mut timer, + | | ); + | |_____^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + = note: this error originates in the macro `macros::call_unsafe_wdf_function_binding` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_device_create.expanded.rs b/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_device_create.expanded.rs new file mode 100644 index 00000000..0493e6bd --- /dev/null +++ b/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_device_create.expanded.rs @@ -0,0 +1,51 @@ +#![no_main] +#![deny(warnings)] +use wdk_sys::*; +extern "C" fn evt_driver_device_add( + _driver: WDFDRIVER, + mut device_init: *mut WDFDEVICE_INIT, +) -> NTSTATUS { + let mut device_handle_output: WDFDEVICE = WDF_NO_HANDLE.cast(); + unsafe { + { + #[must_use] + #[inline(always)] + unsafe fn wdf_device_create_impl( + DeviceInit: *mut wdk_sys::PWDFDEVICE_INIT, + DeviceAttributes: wdk_sys::PWDF_OBJECT_ATTRIBUTES, + Device: *mut wdk_sys::WDFDEVICE, + ) -> wdk_sys::NTSTATUS { + let wdf_function: wdk_sys::PFN_WDFDEVICECREATE = Some(unsafe { + core::mem::transmute( + wdk_sys::WDF_FUNCTION_TABLE[wdk_sys::_WDFFUNCENUM::WdfDeviceCreateTableIndex + as usize], + ) + }); + if let Some(wdf_function) = wdf_function { + unsafe { + (wdf_function)( + wdk_sys::WdfDriverGlobals, + DeviceInit, + DeviceAttributes, + Device, + ) + } + } else { + { + ::core::panicking::panic_fmt( + format_args!( + "internal error: entered unreachable code: {0}", + format_args!("Option should never be None"), + ), + ); + }; + } + } + wdf_device_create_impl( + &mut device_init, + WDF_NO_OBJECT_ATTRIBUTES, + &mut device_handle_output, + ) + } + } +} diff --git a/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_device_create.rs b/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_device_create.rs new file mode 120000 index 00000000..20bd5908 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_device_create.rs @@ -0,0 +1 @@ +../../../inputs/macrotest/wdf_device_create.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_device_create_device_interface.expanded.rs b/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_device_create_device_interface.expanded.rs new file mode 100644 index 00000000..afd81d27 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_device_create_device_interface.expanded.rs @@ -0,0 +1,53 @@ +#![no_main] +#![deny(warnings)] +use wdk_sys::*; +const GUID_DEVINTERFACE_COMPORT: GUID = GUID { + Data1: 0x86E0D1E0u32, + Data2: 0x8089u16, + Data3: 0x11D0u16, + Data4: [0x9Cu8, 0xE4u8, 0x08u8, 0x00u8, 0x3Eu8, 0x30u8, 0x1Fu8, 0x73u8], +}; +fn create_device_interface(wdf_device: WDFDEVICE) -> NTSTATUS { + unsafe { + { + #[must_use] + #[inline(always)] + unsafe fn wdf_device_create_device_interface_impl( + Device: wdk_sys::WDFDEVICE, + InterfaceClassGUID: *const wdk_sys::GUID, + ReferenceString: wdk_sys::PCUNICODE_STRING, + ) -> wdk_sys::NTSTATUS { + let wdf_function: wdk_sys::PFN_WDFDEVICECREATEDEVICEINTERFACE = Some(unsafe { + core::mem::transmute( + wdk_sys::WDF_FUNCTION_TABLE[wdk_sys::_WDFFUNCENUM::WdfDeviceCreateDeviceInterfaceTableIndex + as usize], + ) + }); + if let Some(wdf_function) = wdf_function { + unsafe { + (wdf_function)( + wdk_sys::WdfDriverGlobals, + Device, + InterfaceClassGUID, + ReferenceString, + ) + } + } else { + { + ::core::panicking::panic_fmt( + format_args!( + "internal error: entered unreachable code: {0}", + format_args!("Option should never be None"), + ), + ); + }; + } + } + wdf_device_create_device_interface_impl( + wdf_device, + &GUID_DEVINTERFACE_COMPORT, + core::ptr::null(), + ) + } + } +} diff --git a/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_device_create_device_interface.rs b/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_device_create_device_interface.rs new file mode 120000 index 00000000..e9f8c16b --- /dev/null +++ b/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_device_create_device_interface.rs @@ -0,0 +1 @@ +../../../inputs/macrotest/wdf_device_create_device_interface.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_driver_create.expanded.rs b/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_driver_create.expanded.rs new file mode 100644 index 00000000..ab9abe4a --- /dev/null +++ b/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_driver_create.expanded.rs @@ -0,0 +1,62 @@ +#![no_main] +#![deny(warnings)] +use wdk_sys::*; +#[export_name = "DriverEntry"] +pub extern "system" fn driver_entry( + driver: &mut DRIVER_OBJECT, + registry_path: PCUNICODE_STRING, +) -> NTSTATUS { + let mut driver_config = WDF_DRIVER_CONFIG { + Size: core::mem::size_of::() as ULONG, + ..WDF_DRIVER_CONFIG::default() + }; + let driver_handle_output = WDF_NO_HANDLE as *mut WDFDRIVER; + unsafe { + { + #[must_use] + #[inline(always)] + unsafe fn wdf_driver_create_impl( + DriverObject: wdk_sys::PDRIVER_OBJECT, + RegistryPath: wdk_sys::PCUNICODE_STRING, + DriverAttributes: wdk_sys::PWDF_OBJECT_ATTRIBUTES, + DriverConfig: wdk_sys::PWDF_DRIVER_CONFIG, + Driver: *mut wdk_sys::WDFDRIVER, + ) -> wdk_sys::NTSTATUS { + let wdf_function: wdk_sys::PFN_WDFDRIVERCREATE = Some(unsafe { + core::mem::transmute( + wdk_sys::WDF_FUNCTION_TABLE[wdk_sys::_WDFFUNCENUM::WdfDriverCreateTableIndex + as usize], + ) + }); + if let Some(wdf_function) = wdf_function { + unsafe { + (wdf_function)( + wdk_sys::WdfDriverGlobals, + DriverObject, + RegistryPath, + DriverAttributes, + DriverConfig, + Driver, + ) + } + } else { + { + ::core::panicking::panic_fmt( + format_args!( + "internal error: entered unreachable code: {0}", + format_args!("Option should never be None"), + ), + ); + }; + } + } + wdf_driver_create_impl( + driver as PDRIVER_OBJECT, + registry_path, + WDF_NO_OBJECT_ATTRIBUTES, + &mut driver_config, + driver_handle_output, + ) + } + } +} diff --git a/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_driver_create.rs b/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_driver_create.rs new file mode 120000 index 00000000..570f030b --- /dev/null +++ b/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_driver_create.rs @@ -0,0 +1 @@ +../../../inputs/macrotest/wdf_driver_create.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_spin_lock_acquire.expanded.rs b/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_spin_lock_acquire.expanded.rs new file mode 100644 index 00000000..1ba0841a --- /dev/null +++ b/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_spin_lock_acquire.expanded.rs @@ -0,0 +1,31 @@ +#![no_main] +#![deny(warnings)] +use wdk_sys::*; +fn acquire_lock(wdf_spin_lock: WDFSPINLOCK) { + unsafe { + { + #[inline(always)] + unsafe fn wdf_spin_lock_acquire_impl(SpinLock: wdk_sys::WDFSPINLOCK) { + let wdf_function: wdk_sys::PFN_WDFSPINLOCKACQUIRE = Some(unsafe { + core::mem::transmute( + wdk_sys::WDF_FUNCTION_TABLE[wdk_sys::_WDFFUNCENUM::WdfSpinLockAcquireTableIndex + as usize], + ) + }); + if let Some(wdf_function) = wdf_function { + unsafe { (wdf_function)(wdk_sys::WdfDriverGlobals, SpinLock) } + } else { + { + ::core::panicking::panic_fmt( + format_args!( + "internal error: entered unreachable code: {0}", + format_args!("Option should never be None"), + ), + ); + }; + } + } + wdf_spin_lock_acquire_impl(wdf_spin_lock) + }; + } +} diff --git a/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_spin_lock_acquire.rs b/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_spin_lock_acquire.rs new file mode 120000 index 00000000..e77fcc3f --- /dev/null +++ b/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_spin_lock_acquire.rs @@ -0,0 +1 @@ +../../../inputs/macrotest/wdf_spin_lock_acquire.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_verifier_dbg_break_point.expanded.rs b/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_verifier_dbg_break_point.expanded.rs new file mode 100644 index 00000000..ae3e107c --- /dev/null +++ b/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_verifier_dbg_break_point.expanded.rs @@ -0,0 +1,32 @@ +#![no_main] +#![deny(warnings)] +#[allow(unused_imports)] +use wdk_sys::*; +fn foo() { + unsafe { + { + #[inline(always)] + unsafe fn wdf_verifier_dbg_break_point_impl() { + let wdf_function: wdk_sys::PFN_WDFVERIFIERDBGBREAKPOINT = Some(unsafe { + core::mem::transmute( + wdk_sys::WDF_FUNCTION_TABLE[wdk_sys::_WDFFUNCENUM::WdfVerifierDbgBreakPointTableIndex + as usize], + ) + }); + if let Some(wdf_function) = wdf_function { + unsafe { (wdf_function)(wdk_sys::WdfDriverGlobals) } + } else { + { + ::core::panicking::panic_fmt( + format_args!( + "internal error: entered unreachable code: {0}", + format_args!("Option should never be None"), + ), + ); + }; + } + } + wdf_verifier_dbg_break_point_impl() + } + } +} diff --git a/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_verifier_dbg_break_point.rs b/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_verifier_dbg_break_point.rs new file mode 120000 index 00000000..f2bb2b51 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/stable/macrotest/wdf_verifier_dbg_break_point.rs @@ -0,0 +1 @@ +../../../inputs/macrotest/wdf_verifier_dbg_break_point.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_api_that_does_not_exist.rs b/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_api_that_does_not_exist.rs new file mode 120000 index 00000000..14059dc8 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_api_that_does_not_exist.rs @@ -0,0 +1 @@ +../../../inputs/trybuild/wdf_api_that_does_not_exist.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_api_that_does_not_exist.stderr b/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_api_that_does_not_exist.stderr new file mode 100644 index 00000000..9afb4cb6 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_api_that_does_not_exist.stderr @@ -0,0 +1,5 @@ +error: Failed to find type alias definition for PFN_WDFAPITHATDOESNOTEXIST + --> tests/outputs/stable/trybuild/wdf_api_that_does_not_exist.rs + | + | WdfApiThatDoesNotExist, + | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_device_create_unused_return_type.rs b/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_device_create_unused_return_type.rs new file mode 120000 index 00000000..94c8088d --- /dev/null +++ b/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_device_create_unused_return_type.rs @@ -0,0 +1 @@ +../../../inputs/trybuild/wdf_device_create_unused_return_type.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_device_create_unused_return_type.stderr b/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_device_create_unused_return_type.stderr new file mode 100644 index 00000000..e6f9f649 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_device_create_unused_return_type.stderr @@ -0,0 +1,18 @@ +error: unused return value of `wdf_device_create_impl` that must be used + --> tests/outputs/stable/trybuild/wdf_device_create_unused_return_type.rs + | + | / wdk_macros::call_unsafe_wdf_function_binding!( + | | WdfDeviceCreate, + | | &mut device_init, + | | WDF_NO_OBJECT_ATTRIBUTES, + | | &mut device_handle_output, + | | ) + | |_________^ + | +note: the lint level is defined here + --> tests/outputs/stable/trybuild/wdf_device_create_unused_return_type.rs + | + | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(unused_must_use)]` implied by `#[deny(warnings)]` + = note: this error originates in the macro `wdk_macros::call_unsafe_wdf_function_binding` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_driver_create_missing_arg.rs b/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_driver_create_missing_arg.rs new file mode 120000 index 00000000..a3123ce4 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_driver_create_missing_arg.rs @@ -0,0 +1 @@ +../../../inputs/trybuild/wdf_driver_create_missing_arg.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_driver_create_missing_arg.stderr b/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_driver_create_missing_arg.stderr new file mode 100644 index 00000000..64d2d63b --- /dev/null +++ b/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_driver_create_missing_arg.stderr @@ -0,0 +1,35 @@ +error[E0061]: this function takes 5 arguments but 4 arguments were supplied + --> tests/outputs/stable/trybuild/wdf_driver_create_missing_arg.rs + | + | / wdk_macros::call_unsafe_wdf_function_binding!( + | | WdfDriverCreate, + | | driver as PDRIVER_OBJECT, + | | registry_path, +... | + | | &mut driver_config, + | | ------------------ an argument of type `*mut _WDF_OBJECT_ATTRIBUTES` is missing + | | driver_handle_output, + | | ) + | |_________^ + | +note: function defined here + --> tests/outputs/stable/trybuild/wdf_driver_create_missing_arg.rs + | + | / wdk_macros::call_unsafe_wdf_function_binding!( + | | WdfDriverCreate, + | | driver as PDRIVER_OBJECT, + | | registry_path, +... | + | | driver_handle_output, + | | ) + | |_________^ + | |_________| + | |_________| + | |_________| + | |_________| + | + = note: this error originates in the macro `wdk_macros::call_unsafe_wdf_function_binding` (in Nightly builds, run with -Z macro-backtrace for more info) +help: provide the argument + | +28 | )(driver as PDRIVER_OBJECT, registry_path, /* *mut _WDF_OBJECT_ATTRIBUTES */, &mut driver_config, driver_handle_output) + | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_driver_create_wrong_arg_order.rs b/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_driver_create_wrong_arg_order.rs new file mode 120000 index 00000000..ff8e6c8f --- /dev/null +++ b/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_driver_create_wrong_arg_order.rs @@ -0,0 +1 @@ +../../../inputs/trybuild/wdf_driver_create_wrong_arg_order.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_driver_create_wrong_arg_order.stderr b/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_driver_create_wrong_arg_order.stderr new file mode 100644 index 00000000..88b06386 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_driver_create_wrong_arg_order.stderr @@ -0,0 +1,37 @@ +error[E0308]: arguments to this function are incorrect + --> tests/outputs/stable/trybuild/wdf_driver_create_wrong_arg_order.rs + | + | / wdk_macros::call_unsafe_wdf_function_binding!( + | | WdfDriverCreate, + | | driver as PDRIVER_OBJECT, + | | registry_path, + | | // The order of the next two arguments is swapped! + | | &mut driver_config, + | | ------------------ expected `*mut _WDF_OBJECT_ATTRIBUTES`, found `&mut _WDF_DRIVER_CONFIG` + | | WDF_NO_OBJECT_ATTRIBUTES, + | | ------------------------ expected `*mut _WDF_DRIVER_CONFIG`, found `*mut _WDF_OBJECT_ATTRIBUTES` + | | driver_handle_output, + | | ) + | |_________^ + | +note: function defined here + --> tests/outputs/stable/trybuild/wdf_driver_create_wrong_arg_order.rs + | + | / wdk_macros::call_unsafe_wdf_function_binding!( + | | WdfDriverCreate, + | | driver as PDRIVER_OBJECT, + | | registry_path, +... | + | | driver_handle_output, + | | ) + | |_________^ + | |_________| + | |_________| + | |_________| + | |_________| + | + = note: this error originates in the macro `wdk_macros::call_unsafe_wdf_function_binding` (in Nightly builds, run with -Z macro-backtrace for more info) +help: swap these arguments + | +28 | )(driver as PDRIVER_OBJECT, registry_path, WDF_NO_OBJECT_ATTRIBUTES, &mut driver_config, driver_handle_output) + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_timer_create_missing_unsafe.rs b/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_timer_create_missing_unsafe.rs new file mode 120000 index 00000000..4a715fd0 --- /dev/null +++ b/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_timer_create_missing_unsafe.rs @@ -0,0 +1 @@ +../../../inputs/trybuild/wdf_timer_create_missing_unsafe.rs \ No newline at end of file diff --git a/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_timer_create_missing_unsafe.stderr b/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_timer_create_missing_unsafe.stderr new file mode 100644 index 00000000..089f1ccb --- /dev/null +++ b/crates/wdk-macros/tests/outputs/stable/trybuild/wdf_timer_create_missing_unsafe.stderr @@ -0,0 +1,14 @@ +error[E0133]: call to unsafe function `wdf_timer_create_impl` is unsafe and requires unsafe function or block + --> tests/outputs/stable/trybuild/wdf_timer_create_missing_unsafe.rs + | + | let _nt_status = macros::call_unsafe_wdf_function_binding!( + | ______________________^ + | | WdfTimerCreate, + | | timer_config, + | | attributes, + | | &mut timer, + | | ); + | |_____^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + = note: this error originates in the macro `macros::call_unsafe_wdf_function_binding` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/crates/wdk/src/lib.rs b/crates/wdk/src/lib.rs index cc43641b..75139152 100644 --- a/crates/wdk/src/lib.rs +++ b/crates/wdk/src/lib.rs @@ -5,7 +5,6 @@ //! built on top of the raw FFI bindings provided by [`wdk-sys`], and provides a //! safe, idiomatic rust interface to the WDK. #![no_std] -#![cfg_attr(feature = "nightly", feature(hint_must_use))] #![deny(missing_docs)] #![deny(unsafe_op_in_unsafe_fn)] #![deny(clippy::all)] diff --git a/crates/wdk/src/wdf/spinlock.rs b/crates/wdk/src/wdf/spinlock.rs index a5a2e8ce..aaae3016 100644 --- a/crates/wdk/src/wdf/spinlock.rs +++ b/crates/wdk/src/wdf/spinlock.rs @@ -37,7 +37,6 @@ impl SpinLock { // accessible outside of this module, and this module guarantees that it is // always in a valid state. unsafe { - #![allow(clippy::multiple_unsafe_ops_per_block)] nt_status = macros::call_unsafe_wdf_function_binding!( WdfSpinLockCreate, attributes, @@ -62,11 +61,7 @@ impl SpinLock { // SAFETY: `wdf_spin_lock` is a private member of `SpinLock`, originally created // by WDF, and this module guarantees that it is always in a valid state. unsafe { - #![allow(clippy::multiple_unsafe_ops_per_block)] - let [()] = [macros::call_unsafe_wdf_function_binding!( - WdfSpinLockAcquire, - self.wdf_spin_lock - )]; + macros::call_unsafe_wdf_function_binding!(WdfSpinLockAcquire, self.wdf_spin_lock); } } @@ -75,11 +70,7 @@ impl SpinLock { // SAFETY: `wdf_spin_lock` is a private member of `SpinLock`, originally created // by WDF, and this module guarantees that it is always in a valid state. unsafe { - #![allow(clippy::multiple_unsafe_ops_per_block)] - let [()] = [macros::call_unsafe_wdf_function_binding!( - WdfSpinLockRelease, - self.wdf_spin_lock - )]; + macros::call_unsafe_wdf_function_binding!(WdfSpinLockRelease, self.wdf_spin_lock); } } } diff --git a/crates/wdk/src/wdf/timer.rs b/crates/wdk/src/wdf/timer.rs index c3e1bbfa..b9012c85 100644 --- a/crates/wdk/src/wdf/timer.rs +++ b/crates/wdk/src/wdf/timer.rs @@ -28,7 +28,6 @@ impl Timer { // accessible outside of this module, and this module guarantees that it is // always in a valid state. unsafe { - #![allow(clippy::multiple_unsafe_ops_per_block)] nt_status = macros::call_unsafe_wdf_function_binding!( WdfTimerCreate, timer_config, @@ -52,12 +51,12 @@ impl Timer { } /// Start the [`Timer`]'s clock + #[must_use] pub fn start(&self, due_time: i64) -> bool { let result; // SAFETY: `wdf_timer` is a private member of `Timer`, originally created by // WDF, and this module guarantees that it is always in a valid state. unsafe { - #![allow(clippy::multiple_unsafe_ops_per_block)] result = macros::call_unsafe_wdf_function_binding!(WdfTimerStart, self.wdf_timer, due_time); } @@ -65,12 +64,12 @@ impl Timer { } /// Stop the [`Timer`]'s clock + #[must_use] pub fn stop(&self, wait: bool) -> bool { let result; // SAFETY: `wdf_timer` is a private member of `Timer`, originally created by // WDF, and this module guarantees that it is always in a valid state. unsafe { - #![allow(clippy::multiple_unsafe_ops_per_block)] result = macros::call_unsafe_wdf_function_binding!( WdfTimerStop, self.wdf_timer,