diff --git a/askama_parser/src/target.rs b/askama_parser/src/target.rs index 02b5e506..a2999453 100644 --- a/askama_parser/src/target.rs +++ b/askama_parser/src/target.rs @@ -4,8 +4,8 @@ use winnow::{ModalParser, Parser}; use crate::{ CharLit, ErrorContext, Num, ParseErr, ParseResult, PathOrIdentifier, State, StrLit, WithSpan, - bool_lit, char_lit, identifier, is_rust_keyword, keyword, num_lit, path_or_identifier, str_lit, - ws, + bool_lit, can_be_variable_name, char_lit, identifier, is_rust_keyword, keyword, num_lit, + path_or_identifier, str_lit, ws, }; #[derive(Clone, Debug, PartialEq)] @@ -108,15 +108,24 @@ impl<'a> Target<'a> { return Ok(Self::Struct(path, targets)); } - // If the path only contains one item, we need to check the name. if let [name] = path.as_slice() { - if !crate::can_be_variable_name(name) { + // If the path only contains one item, we need to check the name. + if !can_be_variable_name(name) { + return Err(winnow::error::ErrMode::Cut(ErrorContext::new( + format!("`{name}` cannot be used as an identifier"), + *name, + ))); + } + } else { + // Otherwise we need to check every element but the first. + if let Some(name) = path.iter().skip(1).find(|n| !can_be_variable_name(n)) { return Err(winnow::error::ErrMode::Cut(ErrorContext::new( format!("`{name}` cannot be used as an identifier"), *name, ))); } } + *i = i_before_matching_with; return Ok(Self::Path(path)); } @@ -213,7 +222,7 @@ fn verify_name<'a>( format!("cannot use `{name}` as a name: it is a rust keyword"), input, ))) - } else if !crate::can_be_variable_name(name) { + } else if !can_be_variable_name(name) { Err(winnow::error::ErrMode::Cut(ErrorContext::new( format!("`{name}` cannot be used as an identifier"), input, diff --git a/testing/tests/ui/crate_identifier.rs b/testing/tests/ui/crate_identifier.rs index 2a959f36..a066ae88 100644 --- a/testing/tests/ui/crate_identifier.rs +++ b/testing/tests/ui/crate_identifier.rs @@ -100,4 +100,52 @@ struct SmallSelf3 { )] struct Regression {} +#[derive(Template)] +#[template(ext = "html", source = "{% match a %}{% when a::b::super %}{% endmatch %}")] +struct PathElemSuper { + a: u8, +} + +#[derive(Template)] +#[template(ext = "html", source = "{% match a %}{% when self::a::b::super %}{% endmatch %}")] +struct PathElemSuper2 { + a: u8, +} + +#[derive(Template)] +#[template(ext = "html", source = "{% match a %}{% when a::b::self %}{% endmatch %}")] +struct PathElemSelf { + a: u8, +} + +#[derive(Template)] +#[template(ext = "html", source = "{% match a %}{% when self::a::b::self %}{% endmatch %}")] +struct PathElemSelf2 { + a: u8, +} + +#[derive(Template)] +#[template(ext = "html", source = "{% match a %}{% when a::b::crate %}{% endmatch %}")] +struct PathElemCrate { + a: u8, +} + +#[derive(Template)] +#[template(ext = "html", source = "{% match a %}{% when self::a::b::crate %}{% endmatch %}")] +struct PathElemCrate2 { + a: u8, +} + +#[derive(Template)] +#[template(ext = "html", source = "{% match a %}{% when a::b::Self %}{% endmatch %}")] +struct PathElemSelfType { + a: u8, +} + +#[derive(Template)] +#[template(ext = "html", source = "{% match a %}{% when self::a::b::Self %}{% endmatch %}")] +struct PathElemSelfType2 { + a: u8, +} + fn main() {} diff --git a/testing/tests/ui/crate_identifier.stderr b/testing/tests/ui/crate_identifier.stderr index 83563c07..67be08f4 100644 --- a/testing/tests/ui/crate_identifier.stderr +++ b/testing/tests/ui/crate_identifier.stderr @@ -173,3 +173,67 @@ error: `crate` cannot be used as an identifier | 99 | source = "{{\u{c}KK3e331 :1:27 + "super %}{% endmatch %}" + --> tests/ui/crate_identifier.rs:104:35 + | +104 | #[template(ext = "html", source = "{% match a %}{% when a::b::super %}{% endmatch %}")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `super` cannot be used as an identifier + --> :1:33 + "super %}{% endmatch %}" + --> tests/ui/crate_identifier.rs:110:35 + | +110 | #[template(ext = "html", source = "{% match a %}{% when self::a::b::super %}{% endmatch %}")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `self` cannot be used as an identifier + --> :1:27 + "self %}{% endmatch %}" + --> tests/ui/crate_identifier.rs:116:35 + | +116 | #[template(ext = "html", source = "{% match a %}{% when a::b::self %}{% endmatch %}")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `self` cannot be used as an identifier + --> :1:33 + "self %}{% endmatch %}" + --> tests/ui/crate_identifier.rs:122:35 + | +122 | #[template(ext = "html", source = "{% match a %}{% when self::a::b::self %}{% endmatch %}")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `crate` cannot be used as an identifier + --> :1:27 + "crate %}{% endmatch %}" + --> tests/ui/crate_identifier.rs:128:35 + | +128 | #[template(ext = "html", source = "{% match a %}{% when a::b::crate %}{% endmatch %}")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `crate` cannot be used as an identifier + --> :1:33 + "crate %}{% endmatch %}" + --> tests/ui/crate_identifier.rs:134:35 + | +134 | #[template(ext = "html", source = "{% match a %}{% when self::a::b::crate %}{% endmatch %}")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `Self` cannot be used as an identifier + --> :1:27 + "Self %}{% endmatch %}" + --> tests/ui/crate_identifier.rs:140:35 + | +140 | #[template(ext = "html", source = "{% match a %}{% when a::b::Self %}{% endmatch %}")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `Self` cannot be used as an identifier + --> :1:33 + "Self %}{% endmatch %}" + --> tests/ui/crate_identifier.rs:146:35 + | +146 | #[template(ext = "html", source = "{% match a %}{% when self::a::b::Self %}{% endmatch %}")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^