mirror of
https://github.com/askama-rs/askama.git
synced 2025-09-27 13:00:57 +00:00
parser: reject illegal raw identifiers in attribute access
This commit is contained in:
parent
76b26cd5fa
commit
3f380721a2
@ -42,61 +42,47 @@ struct Allowed {
|
||||
|
||||
fn check_expr<'a>(expr: &WithSpan<'a, Expr<'a>>, allowed: Allowed) -> Result<(), ParseErr<'a>> {
|
||||
match &expr.inner {
|
||||
Expr::Var(name) => {
|
||||
&Expr::Var(name) => {
|
||||
// List can be found in rust compiler "can_be_raw" function (although in our case, it's
|
||||
// also used in cases like `match`, so `self` is allowed in this case).
|
||||
if (!allowed.super_keyword && *name == "super") || matches!(*name, "crate" | "Self") {
|
||||
Err(winnow::error::ErrMode::Cut(ErrorContext::new(
|
||||
format!("`{name}` cannot be used as an identifier"),
|
||||
expr.span,
|
||||
)))
|
||||
} else if !allowed.underscore && *name == "_" {
|
||||
Err(winnow::error::ErrMode::Cut(ErrorContext::new(
|
||||
"reserved keyword `_` cannot be used here",
|
||||
expr.span,
|
||||
)))
|
||||
if (!allowed.super_keyword && name == "super") || matches!(name, "crate" | "Self") {
|
||||
Err(err_reserved_identifier(name))
|
||||
} else if !allowed.underscore && name == "_" {
|
||||
Err(err_underscore_identifier(name))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Expr::IsDefined(var) | Expr::IsNotDefined(var) => {
|
||||
if *var == "_" {
|
||||
Err(winnow::error::ErrMode::Cut(ErrorContext::new(
|
||||
"reserved keyword `_` cannot be used here",
|
||||
expr.span,
|
||||
)))
|
||||
&Expr::IsDefined(var) | &Expr::IsNotDefined(var) => {
|
||||
if var == "_" {
|
||||
Err(err_underscore_identifier(var))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Expr::Path(path) => {
|
||||
if let [name] = path.as_slice() {
|
||||
if let &[name] = path.as_slice() {
|
||||
if !crate::can_be_variable_name(name) {
|
||||
return Err(winnow::error::ErrMode::Cut(ErrorContext::new(
|
||||
format!("`{name}` cannot be used as an identifier"),
|
||||
*name,
|
||||
)));
|
||||
return Err(err_reserved_identifier(name));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Expr::BoolLit(_)
|
||||
| Expr::NumLit(_, _)
|
||||
| Expr::StrLit(_)
|
||||
| Expr::CharLit(_)
|
||||
| Expr::Attr(_, _)
|
||||
| Expr::Filter(_)
|
||||
| Expr::NamedArgument(_, _)
|
||||
| Expr::RustMacro(_, _)
|
||||
| Expr::Try(_)
|
||||
| Expr::FilterSource
|
||||
| Expr::LetCond(_) => Ok(()),
|
||||
Expr::Array(elems) | Expr::Tuple(elems) | Expr::Concat(elems) => {
|
||||
for elem in elems {
|
||||
check_expr(elem, allowed)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Expr::Attr(elem, attr) => {
|
||||
if attr.name == "_" {
|
||||
Err(err_underscore_identifier(attr.name))
|
||||
} else if !crate::can_be_variable_name(attr.name) {
|
||||
Err(err_reserved_identifier(attr.name))
|
||||
} else {
|
||||
check_expr(elem, Allowed::default())
|
||||
}
|
||||
}
|
||||
Expr::Index(elem1, elem2) | Expr::BinOp(_, elem1, elem2) => {
|
||||
check_expr(elem1, Allowed::default())?;
|
||||
check_expr(elem2, Allowed::default())
|
||||
@ -130,9 +116,33 @@ fn check_expr<'a>(expr: &WithSpan<'a, Expr<'a>>, allowed: Allowed) -> Result<(),
|
||||
"unreachable",
|
||||
expr.span,
|
||||
))),
|
||||
Expr::BoolLit(_)
|
||||
| Expr::NumLit(_, _)
|
||||
| Expr::StrLit(_)
|
||||
| Expr::CharLit(_)
|
||||
| Expr::Filter(_)
|
||||
| Expr::NamedArgument(_, _)
|
||||
| Expr::RustMacro(_, _)
|
||||
| Expr::Try(_)
|
||||
| Expr::FilterSource
|
||||
| Expr::LetCond(_) => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn err_underscore_identifier(name: &str) -> winnow::error::ErrMode<ErrorContext<'_>> {
|
||||
winnow::error::ErrMode::Cut(ErrorContext::new(
|
||||
"reserved keyword `_` cannot be used here",
|
||||
name,
|
||||
))
|
||||
}
|
||||
|
||||
fn err_reserved_identifier(name: &str) -> winnow::error::ErrMode<ErrorContext<'_>> {
|
||||
winnow::error::ErrMode::Cut(ErrorContext::new(
|
||||
format!("`{name}` cannot be used as an identifier"),
|
||||
name,
|
||||
))
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Expr<'a> {
|
||||
BoolLit(bool),
|
||||
|
@ -0,0 +1 @@
|
||||
˙˙˙{{crate.4}}˙˙˙˙e˙
|
@ -148,4 +148,32 @@ struct PathElemSelfType2 {
|
||||
a: u8,
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(ext = "html", source = "{{ Self.4 }}")]
|
||||
struct InvalidRawIdentifierSelfTyInAttr1;
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(ext = "html", source = "{{ super.4 }}")]
|
||||
struct InvalidRawIdentifierSuperInAttr1;
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(ext = "html", source = "{{ crate.4 }}")]
|
||||
struct InvalidRawIdentifierCrateInAttr1;
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(ext = "html", source = "{{ self.Self.4 }}")]
|
||||
struct InvalidRawIdentifierSelfTyInAttr2;
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(ext = "html", source = "{{ self.super.4 }}")]
|
||||
struct InvalidRawIdentifierSuperInAttr2;
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(ext = "html", source = "{{ self.crate.4 }}")]
|
||||
struct InvalidRawIdentifierCrateInAttr2;
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(ext = "html", source = "{{ self.self.4 }}")]
|
||||
struct InvalidRawIdentifierSelfInAttr;
|
||||
|
||||
fn main() {}
|
||||
|
@ -237,3 +237,59 @@ error: `Self` cannot be used as an identifier
|
||||
|
|
||||
146 | #[template(ext = "html", source = "{% match a %}{% when self::a::b::Self %}{% endmatch %}")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `Self` cannot be used as an identifier
|
||||
--> <source attribute>:1:3
|
||||
"Self.4 }}"
|
||||
--> tests/ui/crate_identifier.rs:152:35
|
||||
|
|
||||
152 | #[template(ext = "html", source = "{{ Self.4 }}")]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: `super` cannot be used as an identifier
|
||||
--> <source attribute>:1:3
|
||||
"super.4 }}"
|
||||
--> tests/ui/crate_identifier.rs:156:35
|
||||
|
|
||||
156 | #[template(ext = "html", source = "{{ super.4 }}")]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: `crate` cannot be used as an identifier
|
||||
--> <source attribute>:1:3
|
||||
"crate.4 }}"
|
||||
--> tests/ui/crate_identifier.rs:160:35
|
||||
|
|
||||
160 | #[template(ext = "html", source = "{{ crate.4 }}")]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: `Self` cannot be used as an identifier
|
||||
--> <source attribute>:1:8
|
||||
"Self.4 }}"
|
||||
--> tests/ui/crate_identifier.rs:164:35
|
||||
|
|
||||
164 | #[template(ext = "html", source = "{{ self.Self.4 }}")]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `super` cannot be used as an identifier
|
||||
--> <source attribute>:1:8
|
||||
"super.4 }}"
|
||||
--> tests/ui/crate_identifier.rs:168:35
|
||||
|
|
||||
168 | #[template(ext = "html", source = "{{ self.super.4 }}")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `crate` cannot be used as an identifier
|
||||
--> <source attribute>:1:8
|
||||
"crate.4 }}"
|
||||
--> tests/ui/crate_identifier.rs:172:35
|
||||
|
|
||||
172 | #[template(ext = "html", source = "{{ self.crate.4 }}")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `self` cannot be used as an identifier
|
||||
--> <source attribute>:1:8
|
||||
"self.4 }}"
|
||||
--> tests/ui/crate_identifier.rs:176:35
|
||||
|
|
||||
176 | #[template(ext = "html", source = "{{ self.self.4 }}")]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
Loading…
x
Reference in New Issue
Block a user