diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 8b7bd22..8f48064 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -33,7 +33,7 @@ jobs: run: cargo build --all-targets --all-features --locked - name: Test - run: TRYBUILD=overwrite cargo test --locked --all-targets --all-features + run: cargo test --locked --all-targets --all-features - name: Clippy run: cargo clippy --locked --all-targets --all-features -- -D warnings diff --git a/Cargo.lock b/Cargo.lock index c6e221f..100626e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,7 +40,7 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "proc-macro-warning" -version = "0.4.2" +version = "1.0.0-rc.1" dependencies = [ "derive", "proc-macro2", @@ -50,9 +50,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.68" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "5b1106fec09662ec6dd98ccac0f81cef56984d0b49f75c92d8cbad76e20c005c" dependencies = [ "unicode-ident", ] @@ -94,9 +94,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.105" +version = "1.0.107" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" dependencies = [ "itoa", "ryu", @@ -105,9 +105,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.29" +version = "2.0.38" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" dependencies = [ "proc-macro2", "quote", @@ -116,18 +116,18 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.2.0" +version = "1.3.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" dependencies = [ "winapi-util", ] [[package]] name = "trybuild" -version = "1.0.83" +version = "1.0.85" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "6df60d81823ed9c520ee897489573da4b1d79ffbe006b8134f46de1a1aa03555" +checksum = "196a58260a906cedb9bf6d8034b6379d0c11f552416960452f267402ceeddff1" dependencies = [ "basic-toml", "glob", @@ -148,9 +148,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "winapi" @@ -170,9 +170,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.6" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] diff --git a/Cargo.toml b/Cargo.toml index 67a68ce..f4c2049 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ readme = "README.md" members = [ "proc-macro-warning", + "ui-tests/derive", "ui-tests/ui", ] diff --git a/README.md b/README.md index c0161c3..9ff956f 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Building a warning is easy with the builder pattern. ```rust use proc_macro_warning::Warning; -let warning = Warning::new_deprecated("my_macro") +let warning = Warning::new_deprecated("OldStuffUsed") .old("my_macro()") .new("my_macro::new()") .help_link("https:://example.com") diff --git a/proc-macro-warning/Cargo.toml b/proc-macro-warning/Cargo.toml index 279d022..1acd318 100644 --- a/proc-macro-warning/Cargo.toml +++ b/proc-macro-warning/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "proc-macro-warning" -version = "0.4.2" +version = "1.0.0-rc.1" edition = "2021" license = "GPL-3.0 OR Apache-2.0" authors = ["Oliver Tale-Yazdi "] @@ -11,12 +11,14 @@ readme.workspace = true build = "build.rs" [dependencies] -proc-macro2 = { version = "1.0.66", default-features = false } +proc-macro2 = { version = "1.0.68", default-features = false } quote = { version = "1.0.33", default-features = false } -syn = { version = "2.0.29", default-features = false } +syn = { version = "2.0.38", default-features = false } [dev-dependencies] derive = { path = "../ui-tests/derive" } [features] -default = [] +default = ["derive_debug"] + +derive_debug = [] diff --git a/proc-macro-warning/src/lib.rs b/proc-macro-warning/src/lib.rs index a437955..903c12c 100644 --- a/proc-macro-warning/src/lib.rs +++ b/proc-macro-warning/src/lib.rs @@ -5,22 +5,30 @@ #![doc = include_str!(env!("README_PATH"))] #![deny(unsafe_code)] +#![deny(missing_docs)] use core::ops::Deref; use proc_macro2::Span; use quote::{quote_spanned, ToTokens}; +use syn::{spanned::Spanned, Ident}; mod test; /// Creates a compile-time warning for proc macro use. See [DeprecatedWarningBuilder] for usage. #[derive(Clone)] +#[cfg_attr(feature = "derive_debug", derive(Debug))] pub enum Warning { /// A *deprecation* warning that notifies users of outdated types and functions. Deprecated { + /// The name of the warning. name: String, + /// The index of the warning. Name++Index must be unique. index: Option, + /// The message of the warning. message: String, + /// The help links to be displayed next to the message. links: Vec, + /// The span of the warning. span: Span, }, } @@ -29,6 +37,7 @@ pub enum Warning { /// /// Any content will be pasted as-is. #[derive(Clone)] +#[cfg_attr(feature = "derive_debug", derive(Debug))] pub enum FormattedWarning { /// A *deprecation* warning. Deprecated { @@ -36,7 +45,7 @@ pub enum FormattedWarning { /// /// Must be unique in the case that multiple of these warnings are emitted, for example by /// appending a counter. - name: syn::Ident, + name: Ident, /// The exact note to be used for `note = ""`. note: String, /// The span of the warning. @@ -49,13 +58,13 @@ pub enum FormattedWarning { impl FormattedWarning { /// Create a new deprecated warning that already was formatted by the caller. #[must_use] - pub fn new_deprecated<'a, S, T>(name: S, note: T, span: Span) -> Self + pub fn new_deprecated(name: S, note: T, span: Span) -> Self where - S: Into<&'a str>, + S: AsRef, T: Into, { Self::Deprecated { - name: syn::Ident::new(name.into(), span), + name: Ident::new(name.as_ref(), span), note: note.into(), span: Some(span), } @@ -89,7 +98,8 @@ impl FormattedWarning { /// } /// }; /// ``` -#[derive(Default)] +#[derive(Default, Clone)] +#[cfg_attr(feature = "derive_debug", derive(Debug))] pub struct DeprecatedWarningBuilder { title: String, index: Option, @@ -104,53 +114,59 @@ impl DeprecatedWarningBuilder { /// /// The title must be unique for each warning. #[must_use] - pub fn from_title(title: &str) -> DeprecatedWarningBuilder { - DeprecatedWarningBuilder { title: title.into(), ..Default::default() } + pub fn from_title>(title: S) -> Self { + Self { title: title.into(), ..Default::default() } } /// Set an optional index in case that a warning appears multiple times. /// /// Must be set if a warning appears multiple times. #[must_use] - pub fn index(self, index: usize) -> DeprecatedWarningBuilder { - DeprecatedWarningBuilder { index: Some(index), ..self } + pub fn index>(self, index: S) -> Self { + Self { index: Some(index.into()), ..self } } /// The old *deprecated* way of doing something. /// /// Should complete the sentence "It is deprecated to ...". #[must_use] - pub fn old(self, old: &str) -> DeprecatedWarningBuilder { - DeprecatedWarningBuilder { old: Some(old.into()), ..self } + pub fn old>(self, old: S) -> Self { + Self { old: Some(old.into()), ..self } } /// The *new* way of doing something. /// /// Should complete the sentence "Please instead ...". #[must_use] - pub fn new(self, new: &str) -> DeprecatedWarningBuilder { - DeprecatedWarningBuilder { new: Some(new.into()), ..self } + pub fn new>(self, new: S) -> Self { + Self { new: Some(new.into()), ..self } } /// A help link for the user to explain the transition and justification. #[must_use] - pub fn help_link(self, link: &str) -> DeprecatedWarningBuilder { - DeprecatedWarningBuilder { links: vec![link.into()], ..self } + pub fn help_link>(self, link: S) -> Self { + Self { links: vec![link.into()], ..self } } /// Multiple help links for the user to explain the transition and justification. #[must_use] - pub fn help_links(self, links: &[&str]) -> DeprecatedWarningBuilder { - DeprecatedWarningBuilder { links: links.iter().map(|s| s.deref().into()).collect(), ..self } + pub fn help_links(self, links: &[&str]) -> Self { + Self { links: links.iter().map(|s| s.deref().into()).collect(), ..self } } - /// The span of the warning. + /// Set the span of the warning. #[must_use] - pub fn span(self, span: Span) -> DeprecatedWarningBuilder { - DeprecatedWarningBuilder { span: Some(span), ..self } + pub fn span(self, span: Span) -> Self { + Self { span: Some(span), ..self } } - /// Build the warning. + /// Set the span of the warning to the span of `s`. + #[must_use] + pub fn spanned(self, spanned: S) -> Self { + Self { span: Some(spanned.span()), ..self } + } + + /// Fallibly build a warning. pub fn maybe_build(self) -> Result { let span = self.span.unwrap_or_else(Span::call_site); let title = self.title; @@ -171,14 +187,14 @@ impl DeprecatedWarningBuilder { impl Warning { /// Create a new *deprecated* warning. #[must_use] - pub fn new_deprecated(title: &str) -> DeprecatedWarningBuilder { + pub fn new_deprecated>(title: S) -> DeprecatedWarningBuilder { DeprecatedWarningBuilder::from_title(title) } /// Sanitize the warning message. fn final_deprecated_message(&self) -> String { let (message, links) = match self { - Warning::Deprecated { message, links, .. } => (message, links), + Self::Deprecated { message, links, .. } => (message, links), }; let lines = message.trim().lines().map(|line| line.trim_start()); @@ -195,23 +211,24 @@ impl Warning { } /// Sanitize the warning name. - fn final_deprecated_name(&self) -> syn::Ident { + fn final_deprecated_name(&self) -> Ident { let (index, name, span) = match self { - Warning::Deprecated { index, name, span, .. } => (*index, name, *span), + Self::Deprecated { index, name, span, .. } => (*index, name, *span), }; let name = match index { Some(i) => format!("{}_{}", name, i), None => name.clone(), }; - syn::Ident::new(&name, span) + + Ident::new(&name, span) } } impl From for FormattedWarning { fn from(val: Warning) -> Self { match val { - Warning::Deprecated { span, .. } => FormattedWarning::Deprecated { + Warning::Deprecated { span, .. } => Self::Deprecated { name: val.final_deprecated_name(), note: val.final_deprecated_message(), span: Some(span), @@ -230,7 +247,7 @@ impl ToTokens for Warning { impl ToTokens for FormattedWarning { fn to_tokens(&self, stream: &mut proc_macro2::TokenStream) { let (name, note, span) = match self { - FormattedWarning::Deprecated { name, note, span } => (name, note, span), + Self::Deprecated { name, note, span } => (name, note, span), }; let span = span.unwrap_or_else(Span::call_site); diff --git a/proc-macro-warning/src/test.rs b/proc-macro-warning/src/test.rs index e7624a7..d2a1242 100644 --- a/proc-macro-warning/src/test.rs +++ b/proc-macro-warning/src/test.rs @@ -38,3 +38,69 @@ fn example_works() { assert_eq!(got_tokens.to_string(), want_tokens.to_string()); } + +/// Check the functions that accepting `Into` work as expected. +#[test] +fn type_inferring_into_string_works() { + macro_rules! test_into_string_inference { + ($($warning:tt)+) => { + let _ = $($warning)+ (""); + let _ = $($warning)+ (String::new()); + let _ = $($warning)+ (&String::new()); + + #[allow(clippy::from_over_into)] + { + struct Custom; + impl Into for Custom { + fn into(self) -> String { + String::new() + } + } + let _ = $($warning)+ (Custom); + } + } + } + + test_into_string_inference!(DeprecatedWarningBuilder::from_title); + + test_into_string_inference!(Warning::new_deprecated); + test_into_string_inference!(Warning::new_deprecated("").old); + test_into_string_inference!(Warning::new_deprecated("").new); + test_into_string_inference!(Warning::new_deprecated("").help_link); +} + +/// Check the functions that accepting `Spanned` work as expected. +#[test] +fn type_inferring_spanned_works() { + let ident = syn::Ident::new("foo", proc_macro2::Span::call_site()); + + let _ = Warning::new_deprecated("").spanned(&ident); + let _ = Warning::new_deprecated("").spanned(ident); +} + +#[test] +#[cfg(feature = "derive_debug")] +fn warning_debug_works() { + let warning = Warning::new_deprecated("my_macro") + .old("my_macro()") + .new("my_macro::new()") + .help_link("https:://example.com") + .span(proc_macro2::Span::call_site()) + .build(); + let _ = format!("{:?}", warning); +} + +#[test] +#[cfg(feature = "derive_debug")] +fn formatted_warning_debug_works() { + let warning = + FormattedWarning::new_deprecated("my_macro", "my_macro()", proc_macro2::Span::call_site()); + let _ = format!("{:?}", warning); +} + +#[test] +#[cfg(feature = "derive_debug")] +fn deprecated_warning_builder_debug_works() { + let builder = DeprecatedWarningBuilder::from_title("my_macro"); + let _ = format!("{:?}", builder); +} diff --git a/ui-tests/Cargo.toml b/ui-tests/Cargo.toml deleted file mode 100644 index 061fc0b..0000000 --- a/ui-tests/Cargo.toml +++ /dev/null @@ -1,5 +0,0 @@ -[workspace] -members = [ - "derive", - "ui" -] diff --git a/ui-tests/derive/Cargo.toml b/ui-tests/derive/Cargo.toml index e57b7b9..f40852a 100644 --- a/ui-tests/derive/Cargo.toml +++ b/ui-tests/derive/Cargo.toml @@ -10,4 +10,4 @@ proc-macro = true [dependencies] proc-macro-warning = { path = "../../proc-macro-warning" } quote = "1.0.33" -syn = "2.0.29" +syn = "2.0.38" diff --git a/ui-tests/ui/Cargo.toml b/ui-tests/ui/Cargo.toml index f61780d..f588a29 100644 --- a/ui-tests/ui/Cargo.toml +++ b/ui-tests/ui/Cargo.toml @@ -5,5 +5,5 @@ edition = "2021" publish = false [dev-dependencies] -trybuild = "1.0.83" +trybuild = "1.0.85" derive = { path = "../derive" }