From ca6c03f807ab85df25a8c9d7c53c891f88ce2f99 Mon Sep 17 00:00:00 2001 From: Muhammad Hamza Date: Tue, 4 Oct 2022 01:46:41 +0500 Subject: [PATCH] Improve diagnostics --- .../yew-macro/src/html_tree/html_component.rs | 45 ++++++++++++++++--- .../tests/html_macro/component-fail.rs | 30 +++++++++++++ .../tests/html_macro/component-fail.stderr | 14 ++++++ .../html_macro/generic-component-fail.rs | 6 +++ .../html_macro/generic-component-fail.stderr | 36 +++++++++------ 5 files changed, 113 insertions(+), 18 deletions(-) diff --git a/packages/yew-macro/src/html_tree/html_component.rs b/packages/yew-macro/src/html_tree/html_component.rs index 9f8dd962cb8..751f255f751 100644 --- a/packages/yew-macro/src/html_tree/html_component.rs +++ b/packages/yew-macro/src/html_tree/html_component.rs @@ -1,5 +1,6 @@ use proc_macro2::Span; use quote::{quote, quote_spanned, ToTokens}; +use syn::parse::discouraged::Speculative; use syn::parse::{Parse, ParseStream}; use syn::spanned::Spanned; use syn::{Token, Type}; @@ -45,7 +46,7 @@ impl Parse for HtmlComponent { } let mut children = HtmlChildrenTree::new(); - loop { + let close = loop { if input.is_empty() { return Err(syn::Error::new_spanned( open.to_spanned(), @@ -54,12 +55,46 @@ impl Parse for HtmlComponent { } if trying_to_close() { - break; + let cursor = input.cursor(); + let _ = cursor + .punct() + .and_then(|(_, cursor)| cursor.punct()) + .and_then(|(_, cursor)| cursor.ident()) + .ok_or_else(|| { + syn::Error::new(Span::call_site(), "expected a valid closing tag (e.g.: )") + })?; + + let fork = input.fork(); + let lt = fork.parse::()?; + let div = Some(fork.parse::()?); + let ty = fork.parse::()?; + if ty != open.ty { + fn format_token_stream(ts: impl ToTokens) -> String { + let string = ts.to_token_stream().to_string(); + // remove unnecessary spaces + string.replace(' ', "") + } + let open_ty = open.ty; + return Err(syn::Error::new_spanned( + quote!(#open_ty #ty), + format!( + "mismatched closing tags: expected `{}`, found `{}`", + format_token_stream(open_ty), + format_token_stream(ty) + ), + )); + } else { + let gt = fork.parse::]>()?; + let close = HtmlComponentClose { + tag: TagTokens { lt, div, gt }, + ty, + }; + input.advance_to(&fork); + break close; + } } children.parse_child(input)?; - } - - let close = input.parse::()?; + }; if !children.is_empty() { if let Some(children_prop) = open.props.children() { diff --git a/packages/yew-macro/tests/html_macro/component-fail.rs b/packages/yew-macro/tests/html_macro/component-fail.rs index 5da187d2f5e..cdf9ccb34d2 100644 --- a/packages/yew-macro/tests/html_macro/component-fail.rs +++ b/packages/yew-macro/tests/html_macro/component-fail.rs @@ -148,4 +148,34 @@ fn not_expressions() { html! { }; } +fn mismatch_closing_tags() { + pub struct A; + impl Component for A { + type Message = (); + type Properties = (); + + fn create(_ctx: &Context) -> Self { + unimplemented!() + } + fn view(&self, _ctx: &Context) -> Html { + unimplemented!() + } + } + + pub struct B; + impl Component for B { + type Message = (); + type Properties = (); + + fn create(_ctx: &Context) -> Self { + unimplemented!() + } + fn view(&self, _ctx: &Context) -> Html { + unimplemented!() + } + } + let _ = html! { }; + let _ = html! { }; +} + fn main() {} diff --git a/packages/yew-macro/tests/html_macro/component-fail.stderr b/packages/yew-macro/tests/html_macro/component-fail.stderr index 33f60e1a6a3..88716431599 100644 --- a/packages/yew-macro/tests/html_macro/component-fail.stderr +++ b/packages/yew-macro/tests/html_macro/component-fail.stderr @@ -386,6 +386,20 @@ error: only an expression may be assigned as a property. Consider removing this 148 | html! { }; | ^ +error: mismatched closing tags: expected `A`, found `B` + --> tests/html_macro/component-fail.rs:177:22 + | +177 | let _ = html! { }; + | ^^^^^ + +error: expected a valid closing tag (e.g.: ) + --> tests/html_macro/component-fail.rs:178:13 + | +178 | let _ = html! { }; + | ^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0425]: cannot find value `blah` in this scope --> tests/html_macro/component-fail.rs:82:22 | diff --git a/packages/yew-macro/tests/html_macro/generic-component-fail.rs b/packages/yew-macro/tests/html_macro/generic-component-fail.rs index ed2163bcfc5..7d06180caab 100644 --- a/packages/yew-macro/tests/html_macro/generic-component-fail.rs +++ b/packages/yew-macro/tests/html_macro/generic-component-fail.rs @@ -40,9 +40,15 @@ where }} fn compile_fail() { + #[allow(unused_imports)] + use std::path::Path; + html! { > }; html! { > }; html! { >>> }; + + html! { >> }; + html! { > }; } fn main() {} diff --git a/packages/yew-macro/tests/html_macro/generic-component-fail.stderr b/packages/yew-macro/tests/html_macro/generic-component-fail.stderr index 7ce8f5a802d..aa7dbd2b589 100644 --- a/packages/yew-macro/tests/html_macro/generic-component-fail.stderr +++ b/packages/yew-macro/tests/html_macro/generic-component-fail.stderr @@ -1,21 +1,31 @@ error: this opening tag has no corresponding closing tag - --> tests/html_macro/generic-component-fail.rs:43:13 + --> tests/html_macro/generic-component-fail.rs:46:13 | -43 | html! { > }; +46 | html! { > }; | ^^^^^^^^^^^^^^^^^ -error[E0107]: missing generics for struct `Generic` - --> tests/html_macro/generic-component-fail.rs:44:32 +error: mismatched closing tags: expected `Generic`, found `Generic` + --> tests/html_macro/generic-component-fail.rs:47:14 | -44 | html! { > }; - | ^^^^^^^ expected 1 generic argument +47 | html! { > }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: mismatched closing tags: expected `Generic`, found `Generic>` + --> tests/html_macro/generic-component-fail.rs:48:14 + | +48 | html! { >>> }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: mismatched closing tags: expected `Generic`, found `Generic` + --> tests/html_macro/generic-component-fail.rs:50:14 | -note: struct defined here, with 1 generic parameter: `T` - --> tests/html_macro/generic-component-fail.rs:4:12 +50 | html! { >> }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected a valid closing tag (e.g.: ) + --> tests/html_macro/generic-component-fail.rs:51:5 | -4 | pub struct Generic { - | ^^^^^^^ - -help: add missing generic argument +51 | html! { > }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -44 | html! { >> }; - | ~~~~~~~~~~ + = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)