Skip to content

Commit 10b792e

Browse files
committed
fix: span for conflicting error
1 parent b774777 commit 10b792e

File tree

7 files changed

+70
-44
lines changed

7 files changed

+70
-44
lines changed

CHANGELOG.md

+12-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [0.5.0] - 2023-03-02
8+
9+
### Added
10+
- `IdentValue` to keep hold of both value and the source ident
11+
12+
### Changed
13+
- **Breaking Change**: `ConvertParsed::aggregate()` now takes/returns
14+
`IdentValue`
15+
- Improved span for conflicting values
16+
717
## [0.4.0] - 2023-03-02
818
### Changed
919
- **Breaking Change**: Moved some syn types behind feature `full`
@@ -12,5 +22,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1222
- **Breaking Change**: Compile time verify if ident is given through helper
1323
trait
1424

15-
[unreleased]: https://github.com/ModProg/attribute-derive/compare/v0.4.0...HEAD
25+
[unreleased]: https://github.com/ModProg/attribute-derive/compare/v0.5.0...HEAD
26+
[0.5.0]: https://github.com/ModProg/attribute-derive/compare/v0.3.1...v0.5.0
1627
[0.4.0]: https://github.com/ModProg/attribute-derive/compare/v0.3.1...v0.4.0

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ syn = "1"
2323
syn-full = ["syn/full"]
2424

2525
[dependencies.attribute-derive-macro]
26-
version = "0.4.0"
26+
version = "0.5.0"
2727
path = "macro"
2828

2929
[workspace]

example/tests/ui/custom.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,16 @@ error: missing flag `mandatory_flag`
1919
= note: this error originates in the derive macro `Custom` (in Nightly builds, run with -Z macro-backtrace for more info)
2020

2121
error: conflict_a !!! conflict_b
22-
--> tests/ui/custom.rs:23:18
22+
--> tests/ui/custom.rs:23:5
2323
|
2424
23 | #[a(conflict_a = "hey")]
25-
| ^^^^^
25+
| ^^^^^^^^^^
2626

2727
error: conflict_b !!! conflict_a
28-
--> tests/ui/custom.rs:24:18
28+
--> tests/ui/custom.rs:24:5
2929
|
3030
24 | #[b(conflict_b = "hi")]
31-
| ^^^^
31+
| ^^^^^^^^^^
3232

3333
error: found `hello` but expected one of `optional_implicit`, `optional_explicit`, `optional_default`, `default`, `conflict_a`, `conflict_b`, `example`, `flag`, `mandatory_flag`
3434
--> tests/ui/custom.rs:28:9

example/tests/ui/normal.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,16 @@ error: required `mandatory_flag` is not specified
1919
= note: this error originates in the derive macro `Normal` (in Nightly builds, run with -Z macro-backtrace for more info)
2020

2121
error: `conflict_a` conflicts with mutually exclusive `conflict_b`
22-
--> tests/ui/normal.rs:23:18
22+
--> tests/ui/normal.rs:23:5
2323
|
2424
23 | #[a(conflict_a = "hey")]
25-
| ^^^^^
25+
| ^^^^^^^^^^
2626

2727
error: `conflict_b` conflicts with mutually exclusive `conflict_a`
28-
--> tests/ui/normal.rs:24:18
28+
--> tests/ui/normal.rs:24:5
2929
|
3030
24 | #[b(conflict_b = "hi")]
31-
| ^^^^
31+
| ^^^^^^^^^^
3232

3333
error: supported fields are `optional_implicit`, `optional_explicit`, `optional_default`, `default`, `conflict_a`, `conflict_b`, `example`, `flag` and `mandatory_flag`
3434
--> tests/ui/normal.rs:28:9

macro/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ keywords = ["derive", "macro"]
77
license = "MIT"
88
readme = "README.md"
99
repository = "https://github.com/ModProg/attribute-derive"
10-
version = "0.4.0"
10+
version = "0.5.0"
1111
edition = "2021"
1212
name = "attribute-derive-macro"
1313

macro/src/lib.rs

+24-22
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ pub fn attribute_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStre
410410
}
411411

412412
options_ty
413-
.push(quote!(#ident: Option<<#ty as ::attribute_derive::ConvertParsed>::Type>));
413+
.push(quote!(#ident: Option<::attribute_derive::IdentValue<<#ty as ::attribute_derive::ConvertParsed>::Type>>));
414414

415415
let error = format(
416416
struct_error.duplicate_field(),
@@ -468,22 +468,24 @@ pub fn attribute_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStre
468468
// } else {
469469
parsing.push(quote! {
470470
# use ::attribute_derive::__private::{syn, proc_macro2};
471+
# use ::attribute_derive::IdentValue;
471472
#ident_str => {
472-
$parser.#ident = Some(
473-
if let Some(Some(__value)) = $is_flag.then(|| <#ty as ::attribute_derive::ConvertParsed>::as_flag()) {
474-
__value
475-
} else {
476-
$input.step(|__cursor| match __cursor.punct() {
477-
Some((__punct, __rest))
478-
if __punct.as_char() == '=' && __punct.spacing() == proc_macro2::Spacing::Alone =>
479-
{
480-
Ok(((), __rest))
481-
}
482-
_ => Err(__cursor.error("expected assignment `=`")),
483-
})?;
484-
syn::parse::Parse::parse($input)#error?
485-
}
486-
);
473+
$parser.#ident = Some(IdentValue{
474+
value: if let Some(Some(__value)) = $is_flag.then(|| <#ty as ::attribute_derive::ConvertParsed>::as_flag()) {
475+
__value
476+
} else {
477+
$input.step(|__cursor| match __cursor.punct() {
478+
Some((__punct, __rest))
479+
if __punct.as_char() == '=' && __punct.spacing() == proc_macro2::Spacing::Alone =>
480+
{
481+
Ok(((), __rest))
482+
}
483+
_ => Err(__cursor.error("expected assignment `=`")),
484+
})?;
485+
syn::parse::Parse::parse($input)#error?
486+
},
487+
ident: $variable
488+
});
487489
}
488490
});
489491
// }
@@ -531,14 +533,14 @@ pub fn attribute_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStre
531533
assignments.push(match optional{
532534
Some(true) => {
533535
quote! {
534-
#ident: $parser.#ident.map(|t| ::attribute_derive::ConvertParsed::convert(t)).unwrap_or_else(|| Ok(#default))?
536+
#ident: $parser.#ident.map(|t| ::attribute_derive::ConvertParsed::convert(t.value)).unwrap_or_else(|| Ok(#default))?
535537
}
536538
}
537539
Some(false) => {
538540
quote! {
539541
# use ::attribute_derive::__private::{syn, proc_macro2};
540542
# use ::attribute_derive::{ConvertParsed};
541-
#ident: match $parser.#ident.map(|t| ConvertParsed::convert(t)) {
543+
#ident: match $parser.#ident.map(|t| ConvertParsed::convert(t.value)) {
542544
Some(__option) => __option?,
543545
None if <#ty as ConvertParsed>::as_flag().is_some() => Err(syn::Error::new(proc_macro2::Span::call_site(), #flag_error))?,
544546
_ => Err(syn::Error::new(proc_macro2::Span::call_site(), #field_error))?,
@@ -549,7 +551,7 @@ pub fn attribute_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStre
549551
quote! {
550552
# use ::attribute_derive::__private::{syn, proc_macro2};
551553
# use ::attribute_derive::{ConvertParsed};
552-
#ident: match $parser.#ident.map(|t| ConvertParsed::convert(t)) {
554+
#ident: match $parser.#ident.map(|t| ConvertParsed::convert(t.value)) {
553555
Some(__option) => __option?,
554556
None if <#ty as ConvertParsed>::default_by_default() => <#ty as ConvertParsed>::default(),
555557
_ => Err(syn::Error::new(proc_macro2::Span::call_site(), #field_error))?,
@@ -583,11 +585,11 @@ pub fn attribute_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStre
583585
# use ::attribute_derive::__private::proc_macro2;
584586
# use ::attribute_derive::__private::syn::{Error, Spanned};
585587
if let (Some($a), Some($b)) = (&$parser.#a, &$parser.#b) {
586-
if let Some($joined_span) = $a.span().join($b.span()) {
588+
if let Some($joined_span) = $a.ident.span().join($b.ident.span()) {
587589
return Err(Error::new($joined_span, #error_a_to_b));
588590
} else {
589-
let mut $error = Error::new_spanned(&$a, #error_a_to_b);
590-
$error.combine(Error::new_spanned(&$b, #error_b_to_a));
591+
let mut $error = Error::new_spanned(&$a.ident, #error_a_to_b);
592+
$error.combine(Error::new_spanned(&$b.ident, #error_b_to_a));
591593
return Err($error);
592594
}
593595
}

src/lib.rs

+24-11
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ use syn::{
170170

171171
#[doc(hidden)]
172172
pub mod __private {
173-
pub use {proc_macro2, syn};
173+
pub use {proc_macro2, quote, syn};
174174
}
175175

176176
/// Helper trait providing the path for an attribute.
@@ -393,16 +393,16 @@ where
393393
/// Currently this is only implemented for [`Arrays`](Array)
394394
#[allow(unused)]
395395
fn aggregate(
396-
this: Option<Self::Type>,
397-
other: Option<Self::Type>,
396+
this: Option<IdentValue<Self::Type>>,
397+
other: Option<IdentValue<Self::Type>>,
398398
error_msg: &str,
399-
) -> Result<Option<Self::Type>> {
399+
) -> Result<Option<IdentValue<Self::Type>>> {
400400
match (this, other) {
401401
(None, value) => Ok(value),
402402
(value, None) => Ok(value),
403403
(Some(this), Some(other)) => {
404-
let mut error = this.error(error_msg);
405-
syn::Error::combine(&mut error, other.error(error_msg));
404+
let mut error = this.ident.error(error_msg);
405+
syn::Error::combine(&mut error, other.ident.error(error_msg));
406406
Err(error)
407407
}
408408
}
@@ -425,6 +425,14 @@ where
425425
}
426426
}
427427

428+
/// Helper struct to hold a value and the ident of its property
429+
pub struct IdentValue<T> {
430+
/// The value
431+
pub value: T,
432+
/// The ident
433+
pub ident: Ident,
434+
}
435+
428436
/// Macro to easily implement [`ConvertParsed`] for syn types
429437
macro_rules! convert_parsed {
430438
($(#[$meta:meta])* $type:path) => {
@@ -507,17 +515,22 @@ where
507515
}
508516

509517
fn aggregate(
510-
this: Option<Self::Type>,
511-
other: Option<Self::Type>,
518+
this: Option<IdentValue<Self::Type>>,
519+
other: Option<IdentValue<Self::Type>>,
512520
_: &str,
513-
) -> Result<Option<Self::Type>> {
521+
) -> Result<Option<IdentValue<Self::Type>>> {
514522
Ok(match (this, other) {
515523
(None, None) => None,
516524
(None, value) => value,
517525
(value, None) => value,
518526
(Some(mut this), Some(other)) => {
519-
this.data.extend_from_slice(&other.data);
520-
this.span = this.span.join(other.span).unwrap_or(this.span);
527+
this.value.data.extend_from_slice(&other.value.data);
528+
this.value.span = this
529+
.value
530+
.span
531+
.join(other.value.span)
532+
.unwrap_or(this.value.span);
533+
// TODO figure out what to do with the idents
521534
Some(this)
522535
}
523536
})

0 commit comments

Comments
 (0)