deny functions with reserved names or in control flow

This commit is contained in:
ConnorSkees 2020-06-22 11:35:15 -04:00
parent ac2d15b776
commit aea7c9c408
2 changed files with 47 additions and 8 deletions

View File

@ -14,18 +14,48 @@ use crate::{
use super::{NeverEmptyVec, Parser, Stmt};
impl<'a> Parser<'a> {
pub(super) fn parse_function(&mut self) -> SassResult<()> {
if self.in_mixin {
return Err((
"Mixins may not contain function declarations.",
self.span_before,
)
.into());
/// Names that functions are not allowed to have
const FORBIDDEN_IDENTIFIERS: [&str; 7] =
["calc", "element", "expression", "url", "and", "or", "not"];
fn unvendor<'a>(name: &'a str) -> &'a str {
let mut chars = name.chars();
if !matches!(chars.next(), Some('-')) {
return name;
}
if matches!(chars.next(), Some('-')) {
return name;
}
if name.chars().count() < 2 {
return name;
}
let mut pos = 2;
for c in chars {
if c == '-' {
return &name[pos..];
}
pos += 1;
}
name
}
impl<'a> Parser<'a> {
pub(super) fn parse_function(&mut self) -> SassResult<()> {
self.whitespace_or_comment();
let Spanned { node: name, span } = self.parse_identifier()?;
if self.in_mixin {
return Err(("Mixins may not contain function declarations.", span).into());
}
if self.in_control_flow {
return Err(("Functions may not be declared in control directives.", span).into());
}
if FORBIDDEN_IDENTIFIERS.contains(&unvendor(&name)) {
return Err(("Invalid function name.", span).into());
}
self.whitespace_or_comment();
let args = match self.toks.next() {
Some(Token { kind: '(', .. }) => self.parse_func_args()?,

View File

@ -121,3 +121,12 @@ test!(
}",
"a {\n color: \"success!\";\n}\n"
);
error!(
denies_function_declaration_in_control_flow,
"@if true {\n @function foo() {}\n}\n",
"Error: Functions may not be declared in control directives."
);
error!(
denies_function_declaration_with_reserved_name,
"@function url() {}", "Error: Invalid function name."
);