mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Report invalid selectors (bug 1384216).
This commit is contained in:
parent
408c34a76d
commit
9a7cceb0a1
3 changed files with 51 additions and 14 deletions
|
@ -90,6 +90,12 @@ impl<Impl: SelectorImpl> SelectorBuilder<Impl> {
|
||||||
self.simple_selectors.is_empty()
|
self.simple_selectors.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if combinators have ever been pushed to this builder.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn has_combinators(&self) -> bool {
|
||||||
|
!self.combinators.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
/// Consumes the builder, producing a Selector.
|
/// Consumes the builder, producing a Selector.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn build(&mut self, parsed_pseudo: bool) -> ThinArc<SpecificityAndFlags, Component<Impl>> {
|
pub fn build(&mut self, parsed_pseudo: bool) -> ThinArc<SpecificityAndFlags, Component<Impl>> {
|
||||||
|
|
|
@ -54,16 +54,19 @@ pub enum SelectorParseError<'i, T> {
|
||||||
NegationSelectorComponentNotNamespace,
|
NegationSelectorComponentNotNamespace,
|
||||||
NegationSelectorComponentNotLocalName,
|
NegationSelectorComponentNotLocalName,
|
||||||
EmptySelector,
|
EmptySelector,
|
||||||
|
DanglingCombinator,
|
||||||
NonSimpleSelectorInNegation,
|
NonSimpleSelectorInNegation,
|
||||||
UnexpectedTokenInAttributeSelector(Token<'i>),
|
UnexpectedTokenInAttributeSelector(Token<'i>),
|
||||||
PseudoElementExpectedColon,
|
PseudoElementExpectedColon(Token<'i>),
|
||||||
PseudoElementExpectedIdent,
|
PseudoElementExpectedIdent(Token<'i>),
|
||||||
|
NoIdentForPseudo(Token<'i>),
|
||||||
UnsupportedPseudoClassOrElement(CowRcStr<'i>),
|
UnsupportedPseudoClassOrElement(CowRcStr<'i>),
|
||||||
UnexpectedIdent(CowRcStr<'i>),
|
UnexpectedIdent(CowRcStr<'i>),
|
||||||
ExpectedNamespace(CowRcStr<'i>),
|
ExpectedNamespace(CowRcStr<'i>),
|
||||||
ExpectedBarInAttr(Token<'i>),
|
ExpectedBarInAttr(Token<'i>),
|
||||||
BadValueInAttr(Token<'i>),
|
BadValueInAttr(Token<'i>),
|
||||||
InvalidQualNameInAttr(Token<'i>),
|
InvalidQualNameInAttr(Token<'i>),
|
||||||
|
ExplicitNamespaceUnexpectedToken(Token<'i>),
|
||||||
Custom(T),
|
Custom(T),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1044,7 +1047,12 @@ fn parse_selector<'i, 't, P, E, Impl>(
|
||||||
let mut parsed_pseudo_element;
|
let mut parsed_pseudo_element;
|
||||||
'outer_loop: loop {
|
'outer_loop: loop {
|
||||||
// Parse a sequence of simple selectors.
|
// Parse a sequence of simple selectors.
|
||||||
parsed_pseudo_element = parse_compound_selector(parser, input, &mut builder)?;
|
parsed_pseudo_element = match parse_compound_selector(parser, input, &mut builder) {
|
||||||
|
Ok(result) => result,
|
||||||
|
Err(ParseError::Custom(SelectorParseError::EmptySelector)) if builder.has_combinators() =>
|
||||||
|
return Err(SelectorParseError::DanglingCombinator.into()),
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
};
|
||||||
if parsed_pseudo_element {
|
if parsed_pseudo_element {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1109,9 +1117,10 @@ fn parse_type_selector<'i, 't, P, E, Impl, S>(parser: &P, input: &mut CssParser<
|
||||||
Impl: SelectorImpl,
|
Impl: SelectorImpl,
|
||||||
S: Push<Component<Impl>>,
|
S: Push<Component<Impl>>,
|
||||||
{
|
{
|
||||||
match parse_qualified_name(parser, input, /* in_attr_selector = */ false)? {
|
match parse_qualified_name(parser, input, /* in_attr_selector = */ false) {
|
||||||
OptionalQName::None(_) => Ok(false),
|
Err(ParseError::Basic(BasicParseError::EndOfInput)) |
|
||||||
OptionalQName::Some(namespace, local_name) => {
|
Ok(OptionalQName::None(_)) => Ok(false),
|
||||||
|
Ok(OptionalQName::Some(namespace, local_name)) => {
|
||||||
match namespace {
|
match namespace {
|
||||||
QNamePrefix::ImplicitAnyNamespace => {}
|
QNamePrefix::ImplicitAnyNamespace => {}
|
||||||
QNamePrefix::ImplicitDefaultNamespace(url) => {
|
QNamePrefix::ImplicitDefaultNamespace(url) => {
|
||||||
|
@ -1160,6 +1169,7 @@ fn parse_type_selector<'i, 't, P, E, Impl, S>(parser: &P, input: &mut CssParser<
|
||||||
}
|
}
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
Err(e) => Err(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1212,7 +1222,7 @@ fn parse_qualified_name<'i, 't, P, E, Impl>
|
||||||
Ok(OptionalQName::Some(namespace, Some(local_name.clone())))
|
Ok(OptionalQName::Some(namespace, Some(local_name.clone())))
|
||||||
},
|
},
|
||||||
Ok(t) if in_attr_selector => Err(SelectorParseError::InvalidQualNameInAttr(t.clone()).into()),
|
Ok(t) if in_attr_selector => Err(SelectorParseError::InvalidQualNameInAttr(t.clone()).into()),
|
||||||
Ok(t) => Err(ParseError::Basic(BasicParseError::UnexpectedToken(t.clone()))),
|
Ok(t) => Err(SelectorParseError::ExplicitNamespaceUnexpectedToken(t.clone()).into()),
|
||||||
Err(e) => Err(ParseError::Basic(e)),
|
Err(e) => Err(ParseError::Basic(e)),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1499,14 +1509,15 @@ fn parse_compound_selector<'i, 't, P, E, Impl>(
|
||||||
match input.next_including_whitespace() {
|
match input.next_including_whitespace() {
|
||||||
Ok(&Token::Colon) => {},
|
Ok(&Token::Colon) => {},
|
||||||
Ok(&Token::WhiteSpace(_)) | Err(_) => break,
|
Ok(&Token::WhiteSpace(_)) | Err(_) => break,
|
||||||
_ => return Err(SelectorParseError::PseudoElementExpectedColon.into()),
|
Ok(t) =>
|
||||||
|
return Err(SelectorParseError::PseudoElementExpectedColon(t.clone()).into()),
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(emilio): Functional pseudo-classes too?
|
// TODO(emilio): Functional pseudo-classes too?
|
||||||
// We don't need it for now.
|
// We don't need it for now.
|
||||||
let name = match input.next_including_whitespace() {
|
let name = match input.next_including_whitespace()? {
|
||||||
Ok(&Token::Ident(ref name)) => name.clone(),
|
&Token::Ident(ref name) => name.clone(),
|
||||||
_ => return Err(SelectorParseError::PseudoElementExpectedIdent.into()),
|
t => return Err(SelectorParseError::NoIdentForPseudo(t.clone()).into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let pseudo_class =
|
let pseudo_class =
|
||||||
|
@ -1626,7 +1637,7 @@ fn parse_one_simple_selector<'i, 't, P, E, Impl>(parser: &P,
|
||||||
let (name, is_functional) = match next_token {
|
let (name, is_functional) = match next_token {
|
||||||
Token::Ident(name) => (name, false),
|
Token::Ident(name) => (name, false),
|
||||||
Token::Function(name) => (name, true),
|
Token::Function(name) => (name, true),
|
||||||
t => return Err(ParseError::Basic(BasicParseError::UnexpectedToken(t))),
|
t => return Err(SelectorParseError::PseudoElementExpectedIdent(t).into()),
|
||||||
};
|
};
|
||||||
let is_pseudo_element = !is_single_colon ||
|
let is_pseudo_element = !is_single_colon ||
|
||||||
P::is_pseudo_element_allows_single_colon(&name);
|
P::is_pseudo_element_allows_single_colon(&name);
|
||||||
|
|
|
@ -161,7 +161,7 @@ fn token_to_str<'a>(t: Token<'a>) -> String {
|
||||||
format!("{}{}", i, escape_css_ident(&*unit)),
|
format!("{}{}", i, escape_css_ident(&*unit)),
|
||||||
Token::Dimension { value, ref unit, .. } =>
|
Token::Dimension { value, ref unit, .. } =>
|
||||||
format!("{}{}", value, escape_css_ident(&*unit)),
|
format!("{}{}", value, escape_css_ident(&*unit)),
|
||||||
Token::WhiteSpace(_) => "whitespace".into(),
|
Token::WhiteSpace(s) => s.into(),
|
||||||
Token::Comment(_) => "comment".into(),
|
Token::Comment(_) => "comment".into(),
|
||||||
Token::Colon => ":".into(),
|
Token::Colon => ":".into(),
|
||||||
Token::Semicolon => ";".into(),
|
Token::Semicolon => ";".into(),
|
||||||
|
@ -251,7 +251,11 @@ fn extract_error_params<'a>(err: ParseError<'a>) -> Option<ErrorParams<'a>> {
|
||||||
CssParseError::Custom(SelectorParseError::BadValueInAttr(t)) |
|
CssParseError::Custom(SelectorParseError::BadValueInAttr(t)) |
|
||||||
CssParseError::Custom(SelectorParseError::ExpectedBarInAttr(t)) |
|
CssParseError::Custom(SelectorParseError::ExpectedBarInAttr(t)) |
|
||||||
CssParseError::Custom(SelectorParseError::NoQualifiedNameInAttributeSelector(t)) |
|
CssParseError::Custom(SelectorParseError::NoQualifiedNameInAttributeSelector(t)) |
|
||||||
CssParseError::Custom(SelectorParseError::InvalidQualNameInAttr(t)) =>
|
CssParseError::Custom(SelectorParseError::InvalidQualNameInAttr(t)) |
|
||||||
|
CssParseError::Custom(SelectorParseError::ExplicitNamespaceUnexpectedToken(t)) |
|
||||||
|
CssParseError::Custom(SelectorParseError::PseudoElementExpectedIdent(t)) |
|
||||||
|
CssParseError::Custom(SelectorParseError::NoIdentForPseudo(t)) |
|
||||||
|
CssParseError::Custom(SelectorParseError::PseudoElementExpectedColon(t)) =>
|
||||||
(None, Some(ErrorString::UnexpectedToken(t))),
|
(None, Some(ErrorString::UnexpectedToken(t))),
|
||||||
|
|
||||||
CssParseError::Custom(SelectorParseError::ExpectedNamespace(namespace)) =>
|
CssParseError::Custom(SelectorParseError::ExpectedNamespace(namespace)) =>
|
||||||
|
@ -260,6 +264,10 @@ fn extract_error_params<'a>(err: ParseError<'a>) -> Option<ErrorParams<'a>> {
|
||||||
CssParseError::Custom(SelectorParseError::UnsupportedPseudoClassOrElement(p)) =>
|
CssParseError::Custom(SelectorParseError::UnsupportedPseudoClassOrElement(p)) =>
|
||||||
(None, Some(ErrorString::Ident(p))),
|
(None, Some(ErrorString::Ident(p))),
|
||||||
|
|
||||||
|
CssParseError::Custom(SelectorParseError::EmptySelector) |
|
||||||
|
CssParseError::Custom(SelectorParseError::DanglingCombinator) =>
|
||||||
|
(None, None),
|
||||||
|
|
||||||
err => match extract_error_param(err) {
|
err => match extract_error_param(err) {
|
||||||
Some(e) => (Some(e), None),
|
Some(e) => (Some(e), None),
|
||||||
None => return None,
|
None => return None,
|
||||||
|
@ -344,10 +352,22 @@ impl<'a> ErrorHelpers<'a> for ContextualParseError<'a> {
|
||||||
Some(&b"PEAttributeNameOrNamespaceExpected\0"[..]),
|
Some(&b"PEAttributeNameOrNamespaceExpected\0"[..]),
|
||||||
CssParseError::Custom(SelectorParseError::InvalidQualNameInAttr(_)) =>
|
CssParseError::Custom(SelectorParseError::InvalidQualNameInAttr(_)) =>
|
||||||
Some(&b"PEAttributeNameExpected\0"[..]),
|
Some(&b"PEAttributeNameExpected\0"[..]),
|
||||||
|
CssParseError::Custom(SelectorParseError::ExplicitNamespaceUnexpectedToken(_)) =>
|
||||||
|
Some(&b"PETypeSelNotType\0"[..]),
|
||||||
CssParseError::Custom(SelectorParseError::ExpectedNamespace(_)) =>
|
CssParseError::Custom(SelectorParseError::ExpectedNamespace(_)) =>
|
||||||
Some(&b"PEUnknownNamespacePrefix\0"[..]),
|
Some(&b"PEUnknownNamespacePrefix\0"[..]),
|
||||||
|
CssParseError::Custom(SelectorParseError::EmptySelector) =>
|
||||||
|
Some(&b"PESelectorGroupNoSelector\0"[..]),
|
||||||
|
CssParseError::Custom(SelectorParseError::DanglingCombinator) =>
|
||||||
|
Some(&b"PESelectorGroupExtraCombinator\0"[..]),
|
||||||
CssParseError::Custom(SelectorParseError::UnsupportedPseudoClassOrElement(_)) =>
|
CssParseError::Custom(SelectorParseError::UnsupportedPseudoClassOrElement(_)) =>
|
||||||
Some(&b"PEPseudoSelUnknown\0"[..]),
|
Some(&b"PEPseudoSelUnknown\0"[..]),
|
||||||
|
CssParseError::Custom(SelectorParseError::PseudoElementExpectedColon(_)) =>
|
||||||
|
Some(&b"PEPseudoSelEndOrUserActionPC\0"[..]),
|
||||||
|
CssParseError::Custom(SelectorParseError::NoIdentForPseudo(_)) =>
|
||||||
|
Some(&b"PEPseudoClassArgNotIdent\0"[..]),
|
||||||
|
CssParseError::Custom(SelectorParseError::PseudoElementExpectedIdent(_)) =>
|
||||||
|
Some(&b"PEPseudoSelBadName\0"[..]),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
return (prefix, b"PEBadSelectorRSIgnored\0", Action::Nothing);
|
return (prefix, b"PEBadSelectorRSIgnored\0", Action::Nothing);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue