Fix span locations in ifmt and components (#3823)
* Fix span locations in ifmt * Fix component spans * Blame extra children on the first child element * fix clippy
This commit is contained in:
1 parent
0251221c69
commit
f4c59e1188
3 files changed
+38
-9
No files matched your search
@@ -19,7 +19,7 @@
|
|||||||
use crate::innerlude::*;
|
use crate::innerlude::*;
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
use proc_macro2_diagnostics::SpanDiagnosticExt;
|
use proc_macro2_diagnostics::SpanDiagnosticExt;
|
||||||
use quote::{quote, ToTokens, TokenStreamExt};
|
use quote::{quote, quote_spanned, ToTokens, TokenStreamExt};
|
||||||
use std::{collections::HashSet, vec};
|
use std::{collections::HashSet, vec};
|
||||||
use syn::{
|
use syn::{
|
||||||
parse::{Parse, ParseStream},
|
parse::{Parse, ParseStream},
|
||||||
@@ -211,11 +211,16 @@ impl Component {
|
|||||||
|
|
||||||
let name = &self.name;
|
let name = &self.name;
|
||||||
let generics = &self.generics;
|
let generics = &self.generics;
|
||||||
|
let inner_scope_span = self
|
||||||
|
.brace
|
||||||
|
.as_ref()
|
||||||
|
.map(|b| b.span.join())
|
||||||
|
.unwrap_or(self.name.span());
|
||||||
|
|
||||||
let mut tokens = if let Some(props) = manual_props.as_ref() {
|
let mut tokens = if let Some(props) = manual_props.as_ref() {
|
||||||
quote! { let mut __manual_props = #props; }
|
quote_spanned! { props.span() => let mut __manual_props = #props; }
|
||||||
} else {
|
} else {
|
||||||
quote! { fc_to_builder(#name #generics) }
|
quote_spanned! { self.name.span() => fc_to_builder(#name #generics) }
|
||||||
};
|
};
|
||||||
|
|
||||||
tokens.append_all(self.add_fields_to_builder(
|
tokens.append_all(self.add_fields_to_builder(
|
||||||
@@ -224,17 +229,23 @@ impl Component {
|
|||||||
|
|
||||||
if !self.children.is_empty() {
|
if !self.children.is_empty() {
|
||||||
let children = &self.children;
|
let children = &self.children;
|
||||||
|
// If the props don't accept children, attach the error to the first child
|
||||||
if manual_props.is_some() {
|
if manual_props.is_some() {
|
||||||
tokens.append_all(quote! { __manual_props.children = { #children }; })
|
tokens.append_all(
|
||||||
|
quote_spanned! { children.first_root_span() => __manual_props.children = #children; },
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
tokens.append_all(quote! { .children( { #children } ) })
|
tokens.append_all(
|
||||||
|
quote_spanned! { children.first_root_span() => .children( #children ) },
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if manual_props.is_some() {
|
if manual_props.is_some() {
|
||||||
tokens.append_all(quote! { __manual_props })
|
tokens.append_all(quote! { __manual_props })
|
||||||
} else {
|
} else {
|
||||||
tokens.append_all(quote! { .build() })
|
// If this does fail to build, point the compiler error at the Prop braces
|
||||||
|
tokens.append_all(quote_spanned! { inner_scope_span => .build() })
|
||||||
}
|
}
|
||||||
|
|
||||||
tokens
|
tokens
|
||||||
|
|||||||
@@ -26,7 +26,11 @@ impl IfmtInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_litstr(source: LitStr) -> Result<Self> {
|
pub fn new_litstr(source: LitStr) -> Result<Self> {
|
||||||
let segments = IfmtInput::from_raw(&source.value())?;
|
let segments = IfmtInput::from_raw(&source.value()).map_err(|e| {
|
||||||
|
// If there is an error creating the formatted string, attribute it to the litstr span
|
||||||
|
let span = source.span();
|
||||||
|
syn::Error::new(span, e)
|
||||||
|
})?;
|
||||||
Ok(Self { segments, source })
|
Ok(Self { segments, source })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,7 +324,7 @@ impl FormattedSegmentType {
|
|||||||
} else {
|
} else {
|
||||||
Err(Error::new(
|
Err(Error::new(
|
||||||
Span::call_site(),
|
Span::call_site(),
|
||||||
"Expected Ident or Expression",
|
"Failed to parse formatted segment: Expected Ident or Expression",
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -404,4 +408,10 @@ mod tests {
|
|||||||
Some("body { background: red; }".to_string())
|
Some("body { background: red; }".to_string())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn error_spans() {
|
||||||
|
let input = syn::parse2::<IfmtInput>(quote! { "body {{ background: red; }" }).unwrap_err();
|
||||||
|
assert_eq!(input.span().byte_range(), 0..28);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -56,7 +56,7 @@
|
|||||||
use self::location::DynIdx;
|
use self::location::DynIdx;
|
||||||
use crate::innerlude::Attribute;
|
use crate::innerlude::Attribute;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||||
use proc_macro2_diagnostics::SpanDiagnosticExt;
|
use proc_macro2_diagnostics::SpanDiagnosticExt;
|
||||||
use syn::parse_quote;
|
use syn::parse_quote;
|
||||||
|
|
||||||
@@ -386,4 +386,12 @@ impl TemplateBody {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the span of the first root of this template
|
||||||
|
pub(crate) fn first_root_span(&self) -> Span {
|
||||||
|
match self.roots.first() {
|
||||||
|
Some(root) => root.span(),
|
||||||
|
_ => Span::call_site(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user