Skip to content

Commit d54a0f8

Browse files
authored
Merge pull request #59 from jbr/better-spans
feat: improved diagnostic spans
2 parents 22bb8c7 + 25f9b5e commit d54a0f8

File tree

7 files changed

+102
-44
lines changed

7 files changed

+102
-44
lines changed

src/field.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ pub(crate) struct Field {
1515

1616
impl Field {
1717
pub(crate) fn build(field: &SynField, index: usize) -> syn::Result<Field> {
18-
let span = field.span();
1918
let member = match field.ident.clone() {
2019
Some(ident) => Member::Named(ident),
2120
None => Member::Unnamed(Index {
@@ -27,6 +26,8 @@ impl Field {
2726

2827
let ty = field.ty.clone();
2928

29+
let span = member.span().join(ty.span()).unwrap_or(ty.span());
30+
3031
let doc = field
3132
.attrs
3233
.iter()

src/field_attributes.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub(crate) struct FieldAttributes {
1616
pub(crate) decorated: bool,
1717
pub(crate) fn_ident: Option<Ident>,
1818
pub(crate) argument_ident: Option<Ident>,
19-
pub(crate) method_attributes: MethodSettings<FieldMethodAttributes>,
19+
pub(crate) method_attributes: MethodSettings<(Span, FieldMethodAttributes)>,
2020
pub(crate) deref: Option<Type>,
2121

2222
pub(crate) common_settings: CommonSettings,
@@ -96,7 +96,7 @@ impl FieldAttributes {
9696
)
9797
})?;
9898
self.method_attributes
99-
.insert(method, FieldMethodAttributes::build(args)?);
99+
.insert(method, (expr.span(), FieldMethodAttributes::build(args)?));
100100
}
101101

102102
func => {
@@ -152,7 +152,7 @@ impl FieldAttributes {
152152
..FieldMethodAttributes::default()
153153
};
154154

155-
self.method_attributes.insert(method, fma);
155+
self.method_attributes.insert(method, (span, fma));
156156
}
157157
}
158158
}
@@ -178,7 +178,7 @@ impl FieldAttributes {
178178
..FieldMethodAttributes::default()
179179
};
180180

181-
self.method_attributes.insert(method, fma);
181+
self.method_attributes.insert(method, (span, fma));
182182
}
183183
}
184184
Ok(())
@@ -198,7 +198,7 @@ impl FieldAttributes {
198198
..FieldMethodAttributes::default()
199199
};
200200

201-
self.method_attributes.insert(method, fma);
201+
self.method_attributes.insert(method, (span, fma));
202202
Ok(())
203203
}
204204
}

src/query.rs

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,16 @@ use crate::{
88
option_handling::{extract_option_type, strip_ref},
99
};
1010
use Method::{Get, GetMut, Set, With, Without};
11+
use proc_macro2::Span;
1112
use syn::{Expr, Ident, Member, Type, Visibility, parse_quote};
1213

1314
#[cfg_attr(feature = "debug", derive(Debug))]
1415
pub(crate) struct Query<'a> {
15-
method: &'a Method,
1616
field: &'a Field,
17-
struct_attributes: &'a StructAttributes,
1817
field_method_attributes: Option<&'a FieldMethodAttributes>,
18+
method: &'a Method,
19+
span: &'a Span,
20+
struct_attributes: &'a StructAttributes,
1921
struct_method_attributes: Option<&'a StructMethodAttributes>,
2022
}
2123

@@ -25,14 +27,20 @@ impl<'a> Query<'a> {
2527
field: &'a Field,
2628
struct_attributes: &'a StructAttributes,
2729
) -> Self {
28-
let field_method_attributes = field.attributes.method_attributes.retrieve(*method);
30+
let (span, field_method_attributes) = field
31+
.attributes
32+
.method_attributes
33+
.retrieve(*method)
34+
.map_or((None, None), |(s, fma)| (Some(s), Some(fma)));
2935
let struct_method_attributes = struct_attributes.methods.retrieve(*method);
36+
let span = span.unwrap_or(&field.span);
3037

3138
Self {
32-
method,
3339
field,
34-
struct_attributes,
3540
field_method_attributes,
41+
method,
42+
span,
43+
struct_attributes,
3644
struct_method_attributes,
3745
}
3846
}
@@ -41,6 +49,7 @@ impl<'a> Query<'a> {
4149
if !self.enabled() {
4250
return None;
4351
}
52+
let span = *self.span;
4453
let method = *self.method;
4554
let vis = self.vis();
4655
let fn_ident = self.fn_ident()?;
@@ -58,18 +67,19 @@ impl<'a> Query<'a> {
5867
let argument_ident_and_ty = argument_ty.map(|ty| (argument_ident, ty));
5968

6069
Some(Resolved {
61-
method,
62-
vis,
63-
fn_ident,
64-
variable_ident,
6570
argument_ident_and_ty,
66-
ty,
67-
doc,
68-
get_copy,
71+
assigned_value,
6972
chainable_set,
7073
deref_type,
74+
doc,
75+
fn_ident,
76+
get_copy,
77+
method,
7178
option_borrow_inner,
72-
assigned_value,
79+
span,
80+
ty,
81+
variable_ident,
82+
vis,
7383
})
7484
}
7585

src/resolved.rs

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
11
use crate::{Method, query::OptionHandling};
22
use Method::{Get, GetMut, Set, With, Without};
3-
use proc_macro2::TokenStream as TokenStream2;
4-
use quote::quote;
3+
use proc_macro2::{Span, TokenStream as TokenStream2};
4+
use quote::{quote, quote_spanned};
55
use std::borrow::Cow;
66
use syn::{Expr, Ident, Member, Type, Visibility};
77

88
#[cfg_attr(feature = "debug", derive(Debug))]
99
pub(crate) struct Resolved<'a> {
10-
pub(crate) method: Method,
11-
pub(crate) vis: Cow<'a, Visibility>,
12-
pub(crate) fn_ident: Cow<'a, Ident>,
13-
pub(crate) variable_ident: &'a Member,
1410
pub(crate) argument_ident_and_ty: Option<(Cow<'a, Ident>, Cow<'a, Type>)>,
15-
pub(crate) ty: &'a Type,
16-
pub(crate) doc: Option<Cow<'a, str>>,
17-
pub(crate) get_copy: bool,
11+
pub(crate) assigned_value: Expr,
1812
pub(crate) chainable_set: bool,
1913
pub(crate) deref_type: Option<Cow<'a, Type>>,
14+
pub(crate) doc: Option<Cow<'a, str>>,
15+
pub(crate) fn_ident: Cow<'a, Ident>,
16+
pub(crate) get_copy: bool,
17+
pub(crate) method: Method,
2018
pub(crate) option_borrow_inner: Option<OptionHandling<'a>>,
21-
pub(crate) assigned_value: Expr,
19+
pub(crate) span: Span,
20+
pub(crate) ty: &'a Type,
21+
pub(crate) variable_ident: &'a Member,
22+
pub(crate) vis: Cow<'a, Visibility>,
2223
}
2324

2425
impl Resolved<'_> {
@@ -32,41 +33,42 @@ impl Resolved<'_> {
3233
get_copy,
3334
deref_type,
3435
option_borrow_inner,
36+
span,
3537
..
3638
} = self;
3739
let doc = doc.as_deref().map(|d| quote!(#[doc = #d]));
3840

3941
if *get_copy {
40-
quote! {
42+
quote_spanned! {*span=>
4143
#doc
4244
#vis fn #fn_ident(&self) -> #ty {
4345
self.#variable_ident
4446
}
4547
}
4648
} else if let Some(oh) = option_borrow_inner {
4749
match oh {
48-
OptionHandling::Deref(ty) => quote! {
50+
OptionHandling::Deref(ty) => quote_spanned! {*span=>
4951
#doc
5052
#vis fn #fn_ident(&self) -> Option<&#ty> {
5153
self.#variable_ident.as_deref()
5254
}
5355
},
54-
OptionHandling::Ref(ty) => quote! {
56+
OptionHandling::Ref(ty) => quote_spanned! {*span=>
5557
#doc
5658
#vis fn #fn_ident(&self) -> Option<&#ty> {
5759
self.#variable_ident.as_ref()
5860
}
5961
},
6062
}
6163
} else if let Some(deref) = deref_type {
62-
quote! {
64+
quote_spanned! {*span=>
6365
#doc
6466
#vis fn #fn_ident(&self) -> &#deref {
6567
&*self.#variable_ident
6668
}
6769
}
6870
} else {
69-
quote! {
71+
quote_spanned! {*span=>
7072
#doc
7173
#vis fn #fn_ident(&self) -> &#ty {
7274
&self.#variable_ident
@@ -84,6 +86,7 @@ impl Resolved<'_> {
8486
chainable_set,
8587
assigned_value,
8688
argument_ident_and_ty,
89+
span,
8790
..
8891
} = self;
8992

@@ -94,15 +97,15 @@ impl Resolved<'_> {
9497
let doc = doc.as_deref().map(|d| quote!(#[doc = #d]));
9598

9699
if *chainable_set {
97-
quote! {
100+
quote_spanned! {*span=>
98101
#doc
99102
#vis fn #fn_ident(&mut self, #argument_ident: #argument_ty) -> &mut Self {
100103
self.#variable_ident = #assigned_value;
101104
self
102105
}
103106
}
104107
} else {
105-
quote! {
108+
quote_spanned! {*span=>
106109
#doc
107110
#vis fn #fn_ident(&mut self, #argument_ident: #argument_ty) {
108111
self.#variable_ident = #assigned_value;
@@ -120,34 +123,35 @@ impl Resolved<'_> {
120123
doc,
121124
deref_type,
122125
option_borrow_inner,
126+
span,
123127
..
124128
} = self;
125129
let doc = doc.as_deref().map(|d| quote!(#[doc = #d]));
126130

127131
if let Some(oh) = option_borrow_inner {
128132
match oh {
129-
OptionHandling::Deref(ty) => quote! {
133+
OptionHandling::Deref(ty) => quote_spanned! {*span=>
130134
#doc
131135
#vis fn #fn_ident(&mut self) -> Option<&mut #ty> {
132136
self.#variable_ident.as_deref_mut()
133137
}
134138
},
135-
OptionHandling::Ref(ty) => quote! {
139+
OptionHandling::Ref(ty) => quote_spanned! {*span=>
136140
#doc
137141
#vis fn #fn_ident(&mut self) -> Option<&mut #ty> {
138142
self.#variable_ident.as_mut()
139143
}
140144
},
141145
}
142146
} else if let Some(deref) = deref_type {
143-
quote! {
147+
quote_spanned! {*span=>
144148
#doc
145149
#vis fn #fn_ident(&mut self) -> &mut #deref {
146150
&mut *self.#variable_ident
147151
}
148152
}
149153
} else {
150-
quote! {
154+
quote_spanned! {*span=>
151155
#doc
152156
#vis fn #fn_ident(&mut self) -> &mut #ty {
153157
&mut self.#variable_ident
@@ -164,11 +168,12 @@ impl Resolved<'_> {
164168
argument_ident_and_ty,
165169
doc,
166170
assigned_value,
171+
span,
167172
..
168173
} = self;
169174
let doc = doc.as_deref().map(|d| quote!(#[doc = #d]));
170175
if let Some((argument_ident, argument_ty)) = argument_ident_and_ty {
171-
quote! {
176+
quote_spanned! {*span=>
172177
#doc
173178
#[must_use]
174179
#vis fn #fn_ident(mut self, #argument_ident: #argument_ty) -> Self {
@@ -177,7 +182,7 @@ impl Resolved<'_> {
177182
}
178183
}
179184
} else {
180-
quote! {
185+
quote_spanned! {*span=>
181186
#doc
182187
#[must_use]
183188
#vis fn #fn_ident(mut self) -> Self {
@@ -205,11 +210,12 @@ impl Resolved<'_> {
205210
variable_ident,
206211
doc,
207212
assigned_value,
213+
span,
208214
..
209215
} = self;
210216
let doc = doc.as_deref().map(|d| quote!(#[doc = #d]));
211217

212-
quote! {
218+
quote_spanned! {*span=>
213219
#doc
214220
#[must_use]
215221
#vis fn #fn_ident(mut self) -> Self {

tests/test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ fn ui_tests() {
1212

1313
#[rustversion::not(stable)]
1414
#[test]
15-
#[ignore]
15+
#[ignore = "to run ui tests, use the stable toolchain"]
1616
fn ui_tests() {
1717
ui_tests_impl()
1818
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#[derive(fieldwork::Fieldwork)]
2+
struct Something {
3+
#[fieldwork(get, deref = "()")]
4+
string: String,
5+
}
6+
7+
#[derive(fieldwork::Fieldwork)]
8+
#[fieldwork(get)]
9+
struct SomethingElse {
10+
#[fieldwork(deref = "()")]
11+
string: String,
12+
}
13+
14+
fn main() {}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0308]: mismatched types
2+
--> tests/ui/compile_error_in_generated_content.rs:3:17
3+
|
4+
3 | #[fieldwork(get, deref = "()")]
5+
| ^----------------
6+
| |
7+
| _________________expected `&()` because of return type
8+
| |
9+
4 | | string: String,
10+
| |__________^ expected `&()`, found `&str`
11+
|
12+
= note: expected reference `&()`
13+
found reference `&str`
14+
15+
error[E0308]: mismatched types
16+
--> tests/ui/compile_error_in_generated_content.rs:11:5
17+
|
18+
10 | #[fieldwork(deref = "()")]
19+
| _________________________-
20+
11 | | string: String,
21+
| | ^^^^^^^^^^^^^-
22+
| |_____|____________|
23+
| | expected `&()` because of return type
24+
| expected `&()`, found `&str`
25+
|
26+
= note: expected reference `&()`
27+
found reference `&str`

0 commit comments

Comments
 (0)