Skip to content

Commit c68eb26

Browse files
authored
Merge pull request #4 from ggwpez/dev
v0.4.0
2 parents c4f4f16 + cd2b0a9 commit c68eb26

File tree

19 files changed

+341
-70
lines changed

19 files changed

+341
-70
lines changed

.github/workflows/rust.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,14 @@ jobs:
2626
- name: Format
2727
run: cargo fmt --all -- --check
2828

29+
- name: Check no-std
30+
run: cargo check --all-targets --no-default-features # still broken --locked
31+
2932
- name: Build
30-
run: cargo build --all-targets --all-features # --locked TODO
33+
run: cargo build --all-targets --all-features --locked
3134

3235
- name: Test
33-
run: cargo test --locked --all-targets --all-features
36+
run: TRYBUILD=overwrite cargo test --locked --all-targets --all-features
3437

3538
- name: Clippy
3639
run: cargo clippy --locked --all-targets --all-features -- -D warnings

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
/target/
2+
**/target
3+
24
Cargo.lock
35
**/*.rs.bk
6+
7+
.vscode/

Cargo.toml

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,7 @@
1-
[package]
2-
name = "proc-macro-warning"
3-
version = "0.3.1"
4-
edition = "2021"
5-
license = "GPL-3.0 OR Apache-2.0"
6-
authors = ["Oliver Tale-Yazdi <[email protected]>"]
7-
description = "Emit warnings from inside proc macros."
8-
repository = "https://github.com/ggwpez/proc-macro-warning"
1+
[workspace]
92

10-
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
11-
12-
[dependencies]
13-
proc-macro2 = { version = "1.0.56", default-features = false }
14-
quote = { version = "1.0.26", default-features = false }
15-
syn = { version = "2.0.15", default-features = false }
16-
17-
[features]
18-
default = []
3+
members = [
4+
"proc-macro-warning",
5+
"ui-tests/derive",
6+
"ui-tests/ui",
7+
]

README.md

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Building a warning is easy with the builder pattern.
2424

2525
```rust
2626
use proc_macro_warning::Warning;
27+
2728
let warning = Warning::new_deprecated("my_macro")
2829
.old("my_macro()")
2930
.new("my_macro::new()")
@@ -35,11 +36,45 @@ let warning = Warning::new_deprecated("my_macro")
3536
let tokens = quote::quote!(#warning);
3637
```
3738

39+
This works in derive-macros, but you **must** set a span; otherwise it will not show up in the compile output.
40+
41+
The difference to a `#[deprecated]` attribute is that it emits the warning either way. For example when creating a custom `Deprecated` derive macro, it will warn without the struct being constructed.
42+
43+
```rust
44+
#[derive(derive::Deprecated)]
45+
struct Test {}
46+
47+
fn main() {
48+
// Warning triggers although we never used `Test`.
49+
// Otherwise use a normal `#[deprecated]`.
50+
}
51+
```
52+
53+
## Un-opinionated Formatting
54+
55+
The normal aforementioned way of creating a warning will impose specific unified grammar and formatting rules.
56+
You can opt out of this and use your own instead by using `FormattedWarning::new_deprecated`:
57+
58+
```rust
59+
use proc_macro_warning::FormattedWarning;
60+
61+
let warning = FormattedWarning::new_deprecated(
62+
"my_macro",
63+
"looooooooooooooooooooooooooooooong line that will not be brokeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeen ;)",
64+
proc_macro2::Span::call_site(),
65+
);
66+
67+
// Use the warning in a proc macro
68+
let tokens = quote::quote!(#warning);
69+
```
70+
71+
The output of a [similar example](ui-tests/derive/src/lib.rs) is in [derive_raw.stderr](ui-tests/ui/src/warn/derive_raw.stderr).
72+
3873
## Used In
3974

40-
Substrate (since [#13798](https://github.com/paritytech/substrate/pull/13798)) uses this to emit warnings for its FRAME eDSL on deprecated behaviour.
75+
Substrate uses it to emit warnings for its eDSL (FRAME) on deprecated behaviour. The integration was done in [#13798](https://github.com/paritytech/substrate/pull/13798) and shows how to use these warnings in macro expansion.
4176

42-
For example not putting a `call_index` on your functions produces:
77+
The warnings are uniformly formatted and have consistent grammar:
4378
```pre
4479
warning: use of deprecated constant `pallet::warnings::ImplicitCallIndex_0::_w`:
4580
It is deprecated to use implicit call indices.
@@ -55,7 +90,7 @@ warning: use of deprecated constant `pallet::warnings::ImplicitCallIndex_0::_w`:
5590
|
5691
```
5792

58-
Or using a hard-coded weight:
93+
A different one:
5994
```pre
6095
warning: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`:
6196
It is deprecated to use hard-coded constant as call weight.
@@ -69,13 +104,12 @@ warning: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`:
69104
|
70105
```
71106

72-
73107
## License
74108

75109
Licensed under either of at your own choice:
76110

77-
* GNU GENERAL PUBLIC LICENSE, Version 3 ([LICENSE-GPL3](./LICENSE-GPL3) or https://www.gnu.org/licenses/gpl-3.0.txt)
78-
* Apache License, Version 2.0 ([LICENSE-APACHE2](/LICENSE-APACHE2) or https://www.apache.org/licenses/LICENSE-2.0.txt).
111+
* GNU GENERAL PUBLIC LICENSE, Version 3 ([LICENSE-GPL3](./LICENSE-GPL3) or [gnu.org](https://www.gnu.org/licenses/gpl-3.0.txt>))
112+
* Apache License, Version 2.0 ([LICENSE-APACHE2](/LICENSE-APACHE2) or [apache.org](https://www.apache.org/licenses/LICENSE-2.0.txt>)).
79113

80114
### Contribution
81115

proc-macro-warning/Cargo.toml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[package]
2+
name = "proc-macro-warning"
3+
version = "0.4.0"
4+
edition = "2021"
5+
license = "GPL-3.0 OR Apache-2.0"
6+
authors = ["Oliver Tale-Yazdi <[email protected]>"]
7+
description = "Emit warnings from inside proc macros."
8+
repository = "https://github.com/ggwpez/proc-macro-warning"
9+
10+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
11+
12+
[dependencies]
13+
proc-macro2 = { version = "1.0.56", default-features = false }
14+
quote = { version = "1.0.27", default-features = false }
15+
syn = { version = "2.0.16", default-features = false }
16+
17+
[dev-dependencies]
18+
derive = { path = "../ui-tests/derive" }
19+
20+
[features]
21+
default = []

src/lib.rs renamed to proc-macro-warning/src/lib.rs

Lines changed: 100 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* SPDX-License-Identifier: (GPL-3.0 or Apache-2.0)
44
*/
55

6-
//! Emit warnings from inside proc macros.
6+
#![doc = include_str!("../../README.md")]
77

88
use core::ops::Deref;
99
use proc_macro2::Span;
@@ -12,32 +12,74 @@ use quote::{quote_spanned, ToTokens};
1212
mod test;
1313

1414
/// Creates a compile-time warning for proc macro use. See [DeprecatedWarningBuilder] for usage.
15-
pub struct Warning {
16-
pub name: String,
17-
pub index: Option<usize>,
18-
pub message: String,
19-
pub links: Vec<String>,
20-
pub span: Span,
15+
#[derive(Clone)]
16+
pub enum Warning {
17+
/// A *deprecation* warning that notifies users of outdated types and functions.
18+
Deprecated {
19+
name: String,
20+
index: Option<usize>,
21+
message: String,
22+
links: Vec<String>,
23+
span: Span,
24+
},
2125
}
2226

23-
/// Gradually build a "deprecated" `Warning`.
27+
/// A compile-time warning that was already subject to formatting.
28+
///
29+
/// Any content will be pasted as-is.
30+
#[derive(Clone)]
31+
pub enum FormattedWarning {
32+
/// A *deprecation* warning.
33+
Deprecated {
34+
/// Unique name of this warning.
35+
///
36+
/// Must be unique in the case that multiple of these warnings are emitted, for example by
37+
/// appending a counter.
38+
name: syn::Ident,
39+
/// The exact note to be used for `note = ""`.
40+
note: String,
41+
/// The span of the warning.
42+
///
43+
/// Should be set to the original location of where the warning should be emitted.
44+
span: Option<Span>,
45+
},
46+
}
47+
48+
impl FormattedWarning {
49+
/// Create a new deprecated warning that already was formatted by the caller.
50+
#[must_use]
51+
pub fn new_deprecated<'a, S, T>(name: S, note: T, span: Span) -> Self
52+
where
53+
S: Into<&'a str>,
54+
T: Into<String>,
55+
{
56+
Self::Deprecated {
57+
name: syn::Ident::new(name.into(), span),
58+
note: note.into(),
59+
span: Some(span),
60+
}
61+
}
62+
}
63+
64+
/// Gradually build a *deprecation* `Warning`.
2465
///
2566
/// # Example
26-
/// ```
67+
///
68+
/// ```rust
2769
/// use proc_macro_warning::Warning;
2870
///
2971
/// let warning = Warning::new_deprecated("my_macro")
3072
/// .old("my_macro()")
3173
/// .new("my_macro::new()")
3274
/// .help_link("https:://example.com")
75+
/// // Normally you use the input span, but this is an example:
3376
/// .span(proc_macro2::Span::call_site())
3477
/// .build();
3578
///
36-
/// // Use the warning in a proc macro
37-
/// let tokens = quote::quote!(#warning);
79+
/// let mut warnings = vec![warning];
80+
/// // When adding more, you will need to build each with `.index`.
3881
///
39-
/// let warnings = vec![warning];
40-
/// // In a proc macro you would expand them inside a module:
82+
/// // In a proc macro you can expand them in a private module:
4183
/// quote::quote! {
4284
/// mod warnings {
4385
/// #(
@@ -115,7 +157,7 @@ impl DeprecatedWarningBuilder {
115157
let new = self.new.ok_or("Missing new")?;
116158
let message = format!("It is deprecated to {}.\nPlease instead {}.", old, new);
117159

118-
Ok(Warning { name: title, index: self.index, message, links: self.links, span })
160+
Ok(Warning::Deprecated { name: title, index: self.index, message, links: self.links, span })
119161
}
120162

121163
/// Unwraps [`Self::maybe_build`] for convenience.
@@ -126,66 +168,80 @@ impl DeprecatedWarningBuilder {
126168
}
127169

128170
impl Warning {
129-
/// Create a new *raw* warnings.
130-
pub fn new_raw(
131-
name: String,
132-
index: Option<usize>,
133-
message: String,
134-
help_links: Vec<String>,
135-
span: Span,
136-
) -> Warning {
137-
Warning { name, index, message, links: help_links, span }
138-
}
139-
140171
/// Create a new *deprecated* warning.
141172
#[must_use]
142173
pub fn new_deprecated(title: &str) -> DeprecatedWarningBuilder {
143174
DeprecatedWarningBuilder::from_title(title)
144175
}
145176

146177
/// Sanitize the warning message.
147-
fn final_message(&self) -> String {
148-
let lines = self.message.trim().lines().map(|line| line.trim_start());
178+
fn final_deprecated_message(&self) -> String {
179+
let (message, links) = match self {
180+
Warning::Deprecated { message, links, .. } => (message, links),
181+
};
182+
183+
let lines = message.trim().lines().map(|line| line.trim_start());
149184
// Prepend two tabs to each line
150185
let message = lines.map(|line| format!("\t\t{}", line)).collect::<Vec<_>>().join("\n");
151186

152-
if !self.links.is_empty() {
153-
let link = self
154-
.links
155-
.iter()
156-
.map(|l| format!("<{}>", l))
157-
.collect::<Vec<_>>()
158-
.join("\n\t\t\t");
187+
if !links.is_empty() {
188+
let link =
189+
links.iter().map(|l| format!("<{}>", l)).collect::<Vec<_>>().join("\n\t\t\t");
159190
format!("\n{}\n\n\t\tFor more info see:\n\t\t\t{}", message, link)
160191
} else {
161192
format!("\n{}", message)
162193
}
163194
}
164195

165196
/// Sanitize the warning name.
166-
fn final_name(&self) -> syn::Ident {
167-
let name = match self.index {
168-
Some(i) => format!("{}_{}", self.name, i),
169-
None => self.name.clone(),
197+
fn final_deprecated_name(&self) -> syn::Ident {
198+
let (index, name, span) = match self {
199+
Warning::Deprecated { index, name, span, .. } => (*index, name, *span),
200+
};
201+
202+
let name = match index {
203+
Some(i) => format!("{}_{}", name, i),
204+
None => name.clone(),
170205
};
171-
syn::Ident::new(&name, self.span)
206+
syn::Ident::new(&name, span)
207+
}
208+
}
209+
210+
impl From<Warning> for FormattedWarning {
211+
fn from(val: Warning) -> Self {
212+
match val {
213+
Warning::Deprecated { span, .. } => FormattedWarning::Deprecated {
214+
name: val.final_deprecated_name(),
215+
note: val.final_deprecated_message(),
216+
span: Some(span),
217+
},
218+
}
172219
}
173220
}
174221

175222
impl ToTokens for Warning {
176223
fn to_tokens(&self, stream: &mut proc_macro2::TokenStream) {
177-
let name = self.final_name();
178-
let message = self.final_message();
224+
let formatted: FormattedWarning = self.clone().into();
225+
formatted.to_tokens(stream);
226+
}
227+
}
228+
229+
impl ToTokens for FormattedWarning {
230+
fn to_tokens(&self, stream: &mut proc_macro2::TokenStream) {
231+
let (name, note, span) = match self {
232+
FormattedWarning::Deprecated { name, note, span } => (name, note, span),
233+
};
234+
let span = span.unwrap_or_else(Span::call_site);
179235

180-
let q = quote_spanned!(self.span =>
236+
let q = quote_spanned!(span =>
181237
/// This function should not be called and only exists to emit a compiler warning.
182238
///
183-
/// It is a No-OP if you want try it anyway ;)
239+
/// It is a No-OP in any case.
184240
#[allow(dead_code)]
185241
#[allow(non_camel_case_types)]
186242
#[allow(non_snake_case)]
187243
fn #name() {
188-
#[deprecated(note = #message)]
244+
#[deprecated(note = #note)]
189245
#[allow(non_upper_case_globals)]
190246
const _w: () = ();
191247
let _ = _w;

src/test.rs renamed to proc-macro-warning/src/test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ fn example_works() {
2222
let want_tokens = quote!(
2323
/// This function should not be called and only exists to emit a compiler warning.
2424
///
25-
/// It is a No-OP if you want try it anyway ;)
25+
/// It is a No-OP in any case.
2626
#[allow(dead_code)]
2727
#[allow(non_camel_case_types)]
2828
#[allow(non_snake_case)]

ui-tests/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[workspace]
2+
members = [
3+
"derive",
4+
"ui"
5+
]

ui-tests/derive/Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "derive"
3+
version = "0.1.0"
4+
edition = "2021"
5+
publish = false
6+
7+
[lib]
8+
proc-macro = true
9+
10+
[dependencies]
11+
proc-macro-warning = { path = "../../proc-macro-warning" }
12+
quote = "1.0.27"
13+
syn = "2.0.16"

0 commit comments

Comments
 (0)