mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
style: Add a CSS error to the console when using non-featureless :host selectors
(which would never match by definition). Differential Revision: https://phabricator.services.mozilla.com/D111610
This commit is contained in:
parent
7425f2d922
commit
90a2687545
3 changed files with 51 additions and 3 deletions
|
@ -859,7 +859,7 @@ impl<'a, Impl: 'a + SelectorImpl> SelectorIter<'a, Impl> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn is_featureless_host_selector(&mut self) -> bool {
|
pub(crate) fn is_featureless_host_selector(&mut self) -> bool {
|
||||||
self.selector_length() > 0 &&
|
self.selector_length() > 0 &&
|
||||||
self.all(|component| matches!(*component, Component::Host(..))) &&
|
self.all(|component| component.is_host()) &&
|
||||||
self.next_sequence().is_none()
|
self.next_sequence().is_none()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1123,10 +1123,17 @@ pub enum Component<Impl: SelectorImpl> {
|
||||||
|
|
||||||
impl<Impl: SelectorImpl> Component<Impl> {
|
impl<Impl: SelectorImpl> Component<Impl> {
|
||||||
/// Returns true if this is a combinator.
|
/// Returns true if this is a combinator.
|
||||||
|
#[inline]
|
||||||
pub fn is_combinator(&self) -> bool {
|
pub fn is_combinator(&self) -> bool {
|
||||||
matches!(*self, Component::Combinator(_))
|
matches!(*self, Component::Combinator(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if this is a :host() selector.
|
||||||
|
#[inline]
|
||||||
|
pub fn is_host(&self) -> bool {
|
||||||
|
matches!(*self, Component::Host(..))
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the value as a combinator if applicable, None otherwise.
|
/// Returns the value as a combinator if applicable, None otherwise.
|
||||||
pub fn as_combinator(&self) -> Option<Combinator> {
|
pub fn as_combinator(&self) -> Option<Combinator> {
|
||||||
match *self {
|
match *self {
|
||||||
|
|
|
@ -54,6 +54,8 @@ pub enum ContextualParseError<'a> {
|
||||||
InvalidMediaRule(&'a str, ParseError<'a>),
|
InvalidMediaRule(&'a str, ParseError<'a>),
|
||||||
/// A value was not recognized.
|
/// A value was not recognized.
|
||||||
UnsupportedValue(&'a str, ParseError<'a>),
|
UnsupportedValue(&'a str, ParseError<'a>),
|
||||||
|
/// A never-matching `:host` selector was found.
|
||||||
|
NeverMatchingHostSelector(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> fmt::Display for ContextualParseError<'a> {
|
impl<'a> fmt::Display for ContextualParseError<'a> {
|
||||||
|
@ -210,6 +212,9 @@ impl<'a> fmt::Display for ContextualParseError<'a> {
|
||||||
parse_error_to_str(err, f)
|
parse_error_to_str(err, f)
|
||||||
},
|
},
|
||||||
ContextualParseError::UnsupportedValue(_value, ref err) => parse_error_to_str(err, f),
|
ContextualParseError::UnsupportedValue(_value, ref err) => parse_error_to_str(err, f),
|
||||||
|
ContextualParseError::NeverMatchingHostSelector(ref selector) => {
|
||||||
|
write!(f, ":host selector is not featureless: {}", selector)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ pub struct TopLevelRuleParser<'a> {
|
||||||
/// This won't contain any namespaces, and only nested parsers created with
|
/// This won't contain any namespaces, and only nested parsers created with
|
||||||
/// `ParserContext::new_with_rule_type` will.
|
/// `ParserContext::new_with_rule_type` will.
|
||||||
pub context: ParserContext<'a>,
|
pub context: ParserContext<'a>,
|
||||||
/// The current stajkj/te of the parser.
|
/// The current state of the parser.
|
||||||
pub state: State,
|
pub state: State,
|
||||||
/// Whether we have tried to parse was invalid due to being in the wrong
|
/// Whether we have tried to parse was invalid due to being in the wrong
|
||||||
/// place (e.g. an @import rule was found while in the `Body` state). Reset
|
/// place (e.g. an @import rule was found while in the `Body` state). Reset
|
||||||
|
@ -587,6 +587,38 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
fn check_for_useless_selector(
|
||||||
|
input: &mut Parser,
|
||||||
|
context: &ParserContext,
|
||||||
|
selectors: &SelectorList<SelectorImpl>,
|
||||||
|
) {
|
||||||
|
use cssparser::ToCss;
|
||||||
|
|
||||||
|
'selector_loop: for selector in selectors.0.iter() {
|
||||||
|
let mut current = selector.iter();
|
||||||
|
loop {
|
||||||
|
let mut found_host = false;
|
||||||
|
let mut found_non_host = false;
|
||||||
|
for component in &mut current {
|
||||||
|
if component.is_host() {
|
||||||
|
found_host = true;
|
||||||
|
} else {
|
||||||
|
found_non_host = true;
|
||||||
|
}
|
||||||
|
if found_host && found_non_host {
|
||||||
|
let location = input.current_source_location();
|
||||||
|
context.log_css_error(location, ContextualParseError::NeverMatchingHostSelector(selector.to_css_string()));
|
||||||
|
continue 'selector_loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if current.next_sequence().is_none() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, 'b, 'i> QualifiedRuleParser<'i> for NestedRuleParser<'a, 'b> {
|
impl<'a, 'b, 'i> QualifiedRuleParser<'i> for NestedRuleParser<'a, 'b> {
|
||||||
type Prelude = SelectorList<SelectorImpl>;
|
type Prelude = SelectorList<SelectorImpl>;
|
||||||
type QualifiedRule = CssRule;
|
type QualifiedRule = CssRule;
|
||||||
|
@ -601,7 +633,11 @@ impl<'a, 'b, 'i> QualifiedRuleParser<'i> for NestedRuleParser<'a, 'b> {
|
||||||
namespaces: self.namespaces,
|
namespaces: self.namespaces,
|
||||||
url_data: Some(self.context.url_data),
|
url_data: Some(self.context.url_data),
|
||||||
};
|
};
|
||||||
SelectorList::parse(&selector_parser, input)
|
let selectors = SelectorList::parse(&selector_parser, input)?;
|
||||||
|
if self.context.error_reporting_enabled() {
|
||||||
|
check_for_useless_selector(input, &self.context, &selectors);
|
||||||
|
}
|
||||||
|
Ok(selectors)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_block<'t>(
|
fn parse_block<'t>(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue