From c48532fb17832e720131cccf96bce996d48d4a50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kijewski?= Date: Thu, 18 Apr 2024 04:35:44 +0200 Subject: [PATCH] Implement `Render` even if parsing failed This makes error messages much more readable. --- askama_derive/src/heritage.rs | 2 +- askama_derive/src/input.rs | 8 ++++++++ askama_derive/src/lib.rs | 18 +++++++++++++++++- testing/tests/ui/filter_block_ws.stderr | 13 ------------- 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/askama_derive/src/heritage.rs b/askama_derive/src/heritage.rs index 2d70c081..76894cb6 100644 --- a/askama_derive/src/heritage.rs +++ b/askama_derive/src/heritage.rs @@ -36,7 +36,7 @@ impl Heritage<'_> { type BlockAncestry<'a> = HashMap<&'a str, Vec<(&'a Context<'a>, &'a BlockDef<'a>)>>; -#[derive(Clone)] +#[derive(Default, Clone)] pub(crate) struct Context<'a> { pub(crate) nodes: &'a [Node<'a>], pub(crate) extends: Option>, diff --git a/askama_derive/src/input.rs b/askama_derive/src/input.rs index 4139ca87..462e73b6 100644 --- a/askama_derive/src/input.rs +++ b/askama_derive/src/input.rs @@ -332,6 +332,14 @@ impl TemplateArgs { Ok(args) } + pub(crate) fn fallback() -> Self { + Self { + source: Some(Source::Source("".to_string())), + ext: Some("txt".to_string()), + ..Self::default() + } + } + pub(crate) fn config(&self) -> Result { read_config_file(self.config.as_deref()) } diff --git a/askama_derive/src/lib.rs b/askama_derive/src/lib.rs index fd2b5c0f..2f1626a9 100644 --- a/askama_derive/src/lib.rs +++ b/askama_derive/src/lib.rs @@ -23,10 +23,26 @@ pub fn derive_template(input: TokenStream) -> TokenStream { let ast = syn::parse::(input).unwrap(); match build_template(&ast) { Ok(source) => source.parse().unwrap(), - Err(e) => e.into_compile_error(), + Err(e) => { + let mut e = e.into_compile_error(); + if let Ok(source) = build_skeleton(&ast) { + let source: TokenStream = source.parse().unwrap(); + e.extend(source); + } + e + } } } +fn build_skeleton(ast: &syn::DeriveInput) -> Result { + let template_args = TemplateArgs::fallback(); + let config = Config::new("", None)?; + let input = TemplateInput::new(ast, &config, &template_args)?; + let mut contexts = HashMap::new(); + contexts.insert(&input.path, Context::default()); + Generator::new(&input, &contexts, None, MapChain::default()).build(&contexts[&input.path]) +} + /// Takes a `syn::DeriveInput` and generates source code for it /// /// Reads the metadata from the `template()` attribute to get the template diff --git a/testing/tests/ui/filter_block_ws.stderr b/testing/tests/ui/filter_block_ws.stderr index 7e30f697..2740efef 100644 --- a/testing/tests/ui/filter_block_ws.stderr +++ b/testing/tests/ui/filter_block_ws.stderr @@ -6,16 +6,3 @@ error: failed to parse template source at row 1, column 27 near: | ^^^^^^^^ | = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0599]: no method named `render` found for struct `A` in the current scope - --> tests/ui/filter_block_ws.rs:11:7 - | -8 | struct A; - | -------- method `render` not found for this struct -... -11 | A.render().unwrap(); - | ^^^^^^ method not found in `A` - | - = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `render`, perhaps you need to implement it: - candidate #1: `Template`