diff --git a/crates/libs/rdl/src/reader/attribute_ref.rs b/crates/libs/rdl/src/reader/attribute_ref.rs index 42f3902bad..f2711c68c2 100644 --- a/crates/libs/rdl/src/reader/attribute_ref.rs +++ b/crates/libs/rdl/src/reader/attribute_ref.rs @@ -491,6 +491,12 @@ impl Encoder<'_> { .unwrap_or(false) } + pub fn is_exclusive_to_attribute(&self, attr: &syn::Attribute) -> bool { + self.find_attribute_type(attr.path()) + .map(|info| &info.type_name == ("Windows.Foundation.Metadata", "ExclusiveToAttribute")) + .unwrap_or(false) + } + /// Processes `#[guid(0x…)]` and `#[no_guid]` pseudo-attributes in `attrs`, emitting a /// `GuidAttribute` on `target` when an explicit GUID is supplied. Returns `true` when the /// attribute list already carries GUID information (explicit `#[guid]`, `#[no_guid]`, or an diff --git a/crates/libs/rdl/src/reader/interface.rs b/crates/libs/rdl/src/reader/interface.rs index f4eeff174e..21236f1b4e 100644 --- a/crates/libs/rdl/src/reader/interface.rs +++ b/crates/libs/rdl/src/reader/interface.rs @@ -120,9 +120,16 @@ impl syn::parse::Parse for Interface { impl Encoder<'_> { pub fn encode_interface(&mut self, item: &Interface) -> Result<(), Error> { - let mut flags = metadata::TypeAttributes::Public - | metadata::TypeAttributes::Abstract - | metadata::TypeAttributes::Interface; + let has_exclusive_to = item + .attrs + .iter() + .any(|attr| self.is_exclusive_to_attribute(attr)); + + let mut flags = metadata::TypeAttributes::Abstract | metadata::TypeAttributes::Interface; + + if !has_exclusive_to { + flags |= metadata::TypeAttributes::Public; + } if item.winrt { flags |= metadata::TypeAttributes::WindowsRuntime; diff --git a/crates/samples/json/json_validator_winrt/sample.winmd b/crates/samples/json/json_validator_winrt/sample.winmd index 92827b52f1..617fe29c5f 100644 Binary files a/crates/samples/json/json_validator_winrt/sample.winmd and b/crates/samples/json/json_validator_winrt/sample.winmd differ diff --git a/crates/samples/robot/component/robot.winmd b/crates/samples/robot/component/robot.winmd index 16cd30eb71..a951210982 100644 Binary files a/crates/samples/robot/component/robot.winmd and b/crates/samples/robot/component/robot.winmd differ diff --git a/crates/samples/robot/component_cpp/robot.winmd b/crates/samples/robot/component_cpp/robot.winmd index 16cd30eb71..a951210982 100644 Binary files a/crates/samples/robot/component_cpp/robot.winmd and b/crates/samples/robot/component_cpp/robot.winmd differ diff --git a/crates/tests/libs/rdl/tests/roundtrip/exclusive-to.rdl b/crates/tests/libs/rdl/tests/roundtrip/exclusive-to.rdl new file mode 100644 index 0000000000..b023832b52 --- /dev/null +++ b/crates/tests/libs/rdl/tests/roundtrip/exclusive-to.rdl @@ -0,0 +1,6 @@ +#[winrt] +mod Test { + class Foo {} + #[Windows::Foundation::Metadata::ExclusiveTo(Foo)] + interface IFoo {} +} diff --git a/crates/tests/libs/rdl/tests/use-declarations.rs b/crates/tests/libs/rdl/tests/use-declarations.rs index 18cec0c7c9..a2a4e42b6b 100644 --- a/crates/tests/libs/rdl/tests/use-declarations.rs +++ b/crates/tests/libs/rdl/tests/use-declarations.rs @@ -1,3 +1,5 @@ +use windows_metadata::reader::TypeIndex; +use windows_metadata::TypeAttributes; use windows_rdl::*; #[test] @@ -32,3 +34,40 @@ pub fn parse_with_reference() { .write() .unwrap(); } + +// Verify that `#[ExclusiveTo(Foo)]` written with a `use` glob import correctly suppresses +// `TypeAttributes::Public` on the exclusive interface (while the class remains public). +#[test] +pub fn exclusive_to_with_use() { + reader() + .input_str( + r#" +use Windows::Foundation::Metadata::*; + +#[winrt] +mod Test { + class Foo {} + #[ExclusiveTo(Foo)] + interface IFoo {} +} +"#, + ) + .input("../../../libs/bindgen/default/Windows.winmd") + .output("tests/exclusive-to-use.winmd") + .write() + .unwrap(); + + let index = TypeIndex::read("tests/exclusive-to-use.winmd").expect("failed to read winmd"); + + let foo = index.expect("Test", "Foo"); + assert!( + foo.flags().contains(TypeAttributes::Public), + "class Foo should be Public" + ); + + let ifoo = index.expect("Test", "IFoo"); + assert!( + !ifoo.flags().contains(TypeAttributes::Public), + "exclusive interface IFoo should not be Public" + ); +} diff --git a/crates/tests/misc/component/component.winmd b/crates/tests/misc/component/component.winmd index 58177f2c5c..016b1bf3a7 100644 Binary files a/crates/tests/misc/component/component.winmd and b/crates/tests/misc/component/component.winmd differ diff --git a/crates/tests/winrt/events/metadata.winmd b/crates/tests/winrt/events/metadata.winmd index dfc9bb29e4..770e0fee22 100644 Binary files a/crates/tests/winrt/events/metadata.winmd and b/crates/tests/winrt/events/metadata.winmd differ diff --git a/crates/tests/winrt/reference/metadata.winmd b/crates/tests/winrt/reference/metadata.winmd index 8e9bd6d50c..1ff0861a0f 100644 Binary files a/crates/tests/winrt/reference/metadata.winmd and b/crates/tests/winrt/reference/metadata.winmd differ