Skip to content

Commit

Permalink
Add UI test for invalid module items (#124)
Browse files Browse the repository at this point in the history
This commit introduces a compile time error for invalid module items.

For example, the following will now give a descriptive compile time
error:

```rust
#[swift_bridge::bridge]
mod ffi {
    use std;
    fn foo() {}
}

// error: Only `extern` blocks, structs and enums are supported.
//  --> tests/ui/invalid-module-item.rs:6:5
//   |
// 3 |     use std;
//   |     ^^^^^^^^
//
// error: Only `extern` blocks, structs and enums are supported.
//  --> tests/ui/invalid-module-item.rs:7:5
//   |
// 4 |     fn foo() {}
//   |     ^^^^^^^^^^^
//
```

Before this commit we would simply panic with an unhelpful message.
  • Loading branch information
chinedufn committed Dec 15, 2022
1 parent bb46ca6 commit 6a10cc2
Show file tree
Hide file tree
Showing 9 changed files with 72 additions and 40 deletions.
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "swift-bridge"
version = "0.1.41"
version = "0.1.42"
edition = "2021"
keywords = ["swift", "ffi", "bindings", "ios", "mac"]
description = "Generate FFI bindings for safe interop between Rust and Swift."
Expand All @@ -14,10 +14,10 @@ default = []
async = ["tokio", "once_cell"]

[build-dependencies]
swift-bridge-build = {version = "0.1.41", path = "crates/swift-bridge-build"}
swift-bridge-build = {version = "0.1.42", path = "crates/swift-bridge-build"}

[dependencies]
swift-bridge-macro = {version = "0.1.41", path = "crates/swift-bridge-macro"}
swift-bridge-macro = {version = "0.1.42", path = "crates/swift-bridge-macro"}

################################################################################
# Optional features used for async function support.
Expand Down
4 changes: 2 additions & 2 deletions crates/swift-bridge-build/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "swift-bridge-build"
version = "0.1.41"
version = "0.1.42"
edition = "2021"
keywords = ["swift", "ffi", "bindings", "ios", "mac"]
description = "Parse Rust files for swift-bridge modules and generate the corresponding Swift and C code for them."
Expand All @@ -9,6 +9,6 @@ license = "Apache-2.0/MIT"

[dependencies]
proc-macro2 = "1"
swift-bridge-ir = {version = "0.1.41", path = "../swift-bridge-ir"}
swift-bridge-ir = {version = "0.1.42", path = "../swift-bridge-ir"}
syn = {version = "1"}
tempfile = "3.3"
4 changes: 2 additions & 2 deletions crates/swift-bridge-cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "swift-bridge-cli"
version = "0.1.41"
version = "0.1.42"
edition = "2021"
keywords = ["swift", "ffi", "bindings", "ios", "mac"]
description = "Parse Rust files for swift-bridge modules and generate the corresponding Swift and C code for them."
Expand All @@ -9,4 +9,4 @@ license = "Apache-2.0/MIT"

[dependencies]
clap = "3"
swift-bridge-build = { version = "0.1.41", path = "../swift-bridge-build" }
swift-bridge-build = { version = "0.1.42", path = "../swift-bridge-build" }
2 changes: 1 addition & 1 deletion crates/swift-bridge-ir/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "swift-bridge-ir"
version = "0.1.41"
version = "0.1.42"
edition = "2021"
keywords = ["swift", "ffi", "bindings", "ios", "mac"]
description = "Holds the data structures and logic for bridge module parsing and code generation."
Expand Down
37 changes: 15 additions & 22 deletions crates/swift-bridge-ir/src/errors/parse_error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use proc_macro2::Ident;
use quote::ToTokens;
use syn::{Error, FnArg, Receiver};
use syn::{Error, FnArg, Item, Receiver};
use syn::{ForeignItemType, LitStr};
use syn::{Token, Type};

Expand All @@ -19,46 +19,35 @@ pub(crate) enum ParseError {
},
/// `fn foo (&self)`
/// ----
AmbiguousSelf {
self_: Receiver,
},
AmbiguousSelf { self_: Receiver },
/// fn foo (bar: &Bar);
/// If Bar wasn't declared using a `type Bar` declaration.
UndeclaredType {
ty: Type,
},
UndeclaredType { ty: Type },
/// Declared a type that we already support.
/// Example: `type u32`
DeclaredBuiltInType {
ty: ForeignItemType,
},
DeclaredBuiltInType { ty: ForeignItemType },
/// A bridge module struct with one or more fields must have a
/// `#\[swift_bridge(swift_repr ="...")\[\]` attribute so that we know whether to create a
/// `struct` or `class` on the Swift side.
StructMissingSwiftRepr {
struct_ident: Ident,
},
StructMissingSwiftRepr { struct_ident: Ident },
/// Only "class" and "struct" can be used as swift_repr.
StructInvalidSwiftRepr {
swift_repr_attr_value: LitStr,
},
StructInvalidSwiftRepr { swift_repr_attr_value: LitStr },
/// A struct was declared with an unrecognized attribute.
StructUnrecognizedAttribute {
attribute: Ident,
},
StructUnrecognizedAttribute { attribute: Ident },
/// There is no reason to use `swift_repr = "class"` on an empty struct.
/// It's extra overhead with no advantages.
EmptyStructHasSwiftReprClass {
struct_ident: Ident,
swift_repr_attr_value: LitStr,
},
/// See [`FunctionAttributeParseError`]
FunctionAttribute(FunctionAttributeParseError),
/// The function argument is a mutable reference to a Copy opaque type.
/// We do not currently support passing mutable references to Copy opaque types across FFI.
// Would need to Box the copy type and pass a pointer between languages.
ArgCopyAndRefMut {
arg: FnArg,
},
ArgCopyAndRefMut { arg: FnArg },
/// There was an unsupported item in the module, such as a `use` statement.
InvalidModuleItem { item: Item },
}

/// An error while parsing a function attribute.
Expand Down Expand Up @@ -191,6 +180,10 @@ struct {struct_name};
format!(r#"Mutable references to opaque Copy types are not yet supported."#);
Error::new_spanned(arg, message)
}
ParseError::InvalidModuleItem { item } => {
let message = format!(r#"Only `extern` blocks, structs and enums are supported."#);
Error::new_spanned(item, message)
}
}
}
}
34 changes: 26 additions & 8 deletions crates/swift-bridge-ir/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,9 @@ impl Parse for SwiftBridgeModuleAndErrors {
TypeDeclaration::Shared(SharedTypeDeclaration::Enum(shared_enum)),
);
}
_ => {
todo!(
r#"
Push an error that the module may only contain `extern` blocks, structs
and enums
"#
)
invalid_item => {
let error = ParseError::InvalidModuleItem { item: invalid_item };
errors.push(error);
}
};
}
Expand Down Expand Up @@ -146,7 +142,7 @@ impl Parse for SwiftBridgeModuleAndErrors {
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::parse_ok;
use crate::test_utils::{parse_errors, parse_ok};

/// Verify that we can parse a cfg feature from a module.
#[test]
Expand All @@ -167,4 +163,26 @@ mod tests {
}
};
}

/// Verify that we get an error when parsing an unsupported module item, such as a
/// `use` statement.
#[test]
fn invalid_module_item() {
let tokens = quote! {
#[swift_bridge::bridge]
mod foo {
use std;
}
};

let errors = parse_errors(tokens);

assert_eq!(errors.len(), 1);
match &errors[0] {
ParseError::InvalidModuleItem { item } => {
assert!(matches!(item, Item::Use(_)))
}
_ => panic!(),
}
}
}
4 changes: 2 additions & 2 deletions crates/swift-bridge-macro/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "swift-bridge-macro"
version = "0.1.41"
version = "0.1.42"
edition = "2021"
keywords = ["swift", "ffi", "bindings", "ios", "mac"]
description = "Powers swift-bridge module code generation."
Expand All @@ -14,7 +14,7 @@ proc-macro = true
proc-macro2 = "1"
quote = "1"
syn = { version = "1", features = ["full"] }
swift-bridge-ir = {version = "0.1.41", path = "../swift-bridge-ir"}
swift-bridge-ir = {version = "0.1.42", path = "../swift-bridge-ir"}

[dev-dependencies]
swift-bridge = {path = "../../"}
Expand Down
10 changes: 10 additions & 0 deletions crates/swift-bridge-macro/tests/ui/invalid-module-item.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//! # To Run
//! cargo test -p swift-bridge-macro -- ui trybuild=invalid-module-item.rs

#[swift_bridge::bridge]
mod ffi {
use std;
fn foo() {}
}

fn main() {}
11 changes: 11 additions & 0 deletions crates/swift-bridge-macro/tests/ui/invalid-module-item.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error: Only `extern` blocks, structs and enums are supported.
--> tests/ui/invalid-module-item.rs:6:5
|
6 | use std;
| ^^^^^^^^

error: Only `extern` blocks, structs and enums are supported.
--> tests/ui/invalid-module-item.rs:7:5
|
7 | fn foo() {}
| ^^^^^^^^^^^

0 comments on commit 6a10cc2

Please sign in to comment.