소스 검색

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
Evan Almloff 3 달 전
부모
커밋
f4c59e1188
3개의 변경된 파일38개의 추가작업 그리고 9개의 파일을 삭제
  1. 17 6
      packages/rsx/src/component.rs
  2. 12 2
      packages/rsx/src/ifmt.rs
  3. 9 1
      packages/rsx/src/template_body.rs

+ 17 - 6
packages/rsx/src/component.rs

@@ -19,7 +19,7 @@
 use crate::innerlude::*;
 use proc_macro2::TokenStream as TokenStream2;
 use proc_macro2_diagnostics::SpanDiagnosticExt;
-use quote::{quote, ToTokens, TokenStreamExt};
+use quote::{quote, quote_spanned, ToTokens, TokenStreamExt};
 use std::{collections::HashSet, vec};
 use syn::{
     parse::{Parse, ParseStream},
@@ -211,11 +211,16 @@ impl Component {
 
         let name = &self.name;
         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() {
-            quote! { let mut __manual_props = #props; }
+            quote_spanned! { props.span() => let mut __manual_props = #props; }
         } 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(
@@ -224,17 +229,23 @@ impl Component {
 
         if !self.children.is_empty() {
             let children = &self.children;
+            // If the props don't accept children, attach the error to the first child
             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 {
-                tokens.append_all(quote! { .children( { #children } ) })
+                tokens.append_all(
+                    quote_spanned! { children.first_root_span() => .children( #children ) },
+                )
             }
         }
 
         if manual_props.is_some() {
             tokens.append_all(quote! { __manual_props })
         } 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

+ 12 - 2
packages/rsx/src/ifmt.rs

@@ -26,7 +26,11 @@ impl IfmtInput {
     }
 
     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 })
     }
 
@@ -320,7 +324,7 @@ impl FormattedSegmentType {
         } else {
             Err(Error::new(
                 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())
         );
     }
+
+    #[test]
+    fn error_spans() {
+        let input = syn::parse2::<IfmtInput>(quote! { "body {{ background: red; }" }).unwrap_err();
+        assert_eq!(input.span().byte_range(), 0..28);
+    }
 }

+ 9 - 1
packages/rsx/src/template_body.rs

@@ -56,7 +56,7 @@
 use self::location::DynIdx;
 use crate::innerlude::Attribute;
 use crate::*;
-use proc_macro2::TokenStream as TokenStream2;
+use proc_macro2::{Span, TokenStream as TokenStream2};
 use proc_macro2_diagnostics::SpanDiagnosticExt;
 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(),
+        }
+    }
 }