Skip to content
Closed
6 changes: 6 additions & 0 deletions crates/libs/rdl/src/reader/attribute_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 10 additions & 3 deletions crates/libs/rdl/src/reader/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Binary file modified crates/samples/json/json_validator_winrt/sample.winmd
Binary file not shown.
Binary file modified crates/samples/robot/component/robot.winmd
Binary file not shown.
Binary file modified crates/samples/robot/component_cpp/robot.winmd
Binary file not shown.
6 changes: 6 additions & 0 deletions crates/tests/libs/rdl/tests/roundtrip/exclusive-to.rdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#[winrt]
mod Test {
class Foo {}
#[Windows::Foundation::Metadata::ExclusiveTo(Foo)]
interface IFoo {}
}
39 changes: 39 additions & 0 deletions crates/tests/libs/rdl/tests/use-declarations.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use windows_metadata::reader::TypeIndex;
use windows_metadata::TypeAttributes;
use windows_rdl::*;

#[test]
Expand Down Expand Up @@ -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()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot the only thing this needs to be testing is that the resulting TypeDef in the winmd is not public.

  1. Use reader().input_str("class ... interface ... ") ... to write a winmd with an exclusive interface.
  2. Use windows-metadata reader to check the interface TypeAttributes::Public flag is present on the class but not present on the interface.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 8d61cb6. The test now:

  1. Uses reader().input_str(...) with use Windows::Foundation::Metadata::* + #[ExclusiveTo(Foo)]
  2. Reads back the winmd via windows_metadata::reader::TypeIndex and asserts Foo has TypeAttributes::Public while IFoo does not.

.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"
);
}
Binary file modified crates/tests/misc/component/component.winmd
Binary file not shown.
Binary file modified crates/tests/winrt/events/metadata.winmd
Binary file not shown.
Binary file modified crates/tests/winrt/reference/metadata.winmd
Binary file not shown.
Loading