mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +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]
|
||||
pub(crate) fn is_featureless_host_selector(&mut self) -> bool {
|
||||
self.selector_length() > 0 &&
|
||||
self.all(|component| matches!(*component, Component::Host(..))) &&
|
||||
self.all(|component| component.is_host()) &&
|
||||
self.next_sequence().is_none()
|
||||
}
|
||||
|
||||
|
@ -1123,10 +1123,17 @@ pub enum Component<Impl: SelectorImpl> {
|
|||
|
||||
impl<Impl: SelectorImpl> Component<Impl> {
|
||||
/// Returns true if this is a combinator.
|
||||
#[inline]
|
||||
pub fn is_combinator(&self) -> bool {
|
||||
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.
|
||||
pub fn as_combinator(&self) -> Option<Combinator> {
|
||||
match *self {
|
||||
|
|
|
@ -54,6 +54,8 @@ pub enum ContextualParseError<'a> {
|
|||
InvalidMediaRule(&'a str, ParseError<'a>),
|
||||
/// A value was not recognized.
|
||||
UnsupportedValue(&'a str, ParseError<'a>),
|
||||
/// A never-matching `:host` selector was found.
|
||||
NeverMatchingHostSelector(String),
|
||||
}
|
||||
|
||||
impl<'a> fmt::Display for ContextualParseError<'a> {
|
||||
|
@ -210,6 +212,9 @@ impl<'a> fmt::Display for ContextualParseError<'a> {
|
|||
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
|
||||
/// `ParserContext::new_with_rule_type` will.
|
||||
pub context: ParserContext<'a>,
|
||||
/// The current stajkj/te of the parser.
|
||||
/// The current state of the parser.
|
||||
pub state: State,
|
||||
/// 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
|
||||
|
@ -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> {
|
||||
type Prelude = SelectorList<SelectorImpl>;
|
||||
type QualifiedRule = CssRule;
|
||||
|
@ -601,7 +633,11 @@ impl<'a, 'b, 'i> QualifiedRuleParser<'i> for NestedRuleParser<'a, 'b> {
|
|||
namespaces: self.namespaces,
|
||||
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>(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue