mirror of https://github.com/astral-sh/ruff
Minor stylistic improvements for functions detecting PEP-604 unions (#14633)
This commit is contained in:
parent
8a860b89b4
commit
4fb1416bf4
|
|
@ -119,22 +119,32 @@ pub(crate) fn redundant_none_literal<'a>(checker: &mut Checker, literal_expr: &'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If possible, return a [`Fix`] for a violation of this rule.
|
||||||
|
///
|
||||||
|
/// Avoid producing code that would raise an exception when
|
||||||
|
/// `Literal[None] | None` would be fixed to `None | None`.
|
||||||
|
/// Instead, do not provide a fix. We don't need to worry about unions
|
||||||
|
/// that use [`typing.Union`], as `Union[None, None]` is valid Python.
|
||||||
|
/// See <https://github.com/astral-sh/ruff/issues/14567>.
|
||||||
|
///
|
||||||
|
/// [`typing.Union`]: https://docs.python.org/3/library/typing.html#typing.Union
|
||||||
fn create_fix_edit(semantic: &SemanticModel, literal_expr: &Expr) -> Option<Edit> {
|
fn create_fix_edit(semantic: &SemanticModel, literal_expr: &Expr) -> Option<Edit> {
|
||||||
let mut enclosing_union = None;
|
let enclosing_pep604_union = semantic
|
||||||
for expr in semantic.current_expressions().skip(1).take_while(|expr| {
|
.current_expressions()
|
||||||
matches!(
|
.skip(1)
|
||||||
expr,
|
.take_while(|expr| {
|
||||||
Expr::BinOp(ExprBinOp {
|
matches!(
|
||||||
op: Operator::BitOr,
|
expr,
|
||||||
..
|
Expr::BinOp(ExprBinOp {
|
||||||
})
|
op: Operator::BitOr,
|
||||||
)
|
..
|
||||||
}) {
|
})
|
||||||
enclosing_union = Some(expr);
|
)
|
||||||
}
|
})
|
||||||
|
.last();
|
||||||
|
|
||||||
let mut is_fixable = true;
|
let mut is_fixable = true;
|
||||||
if let Some(enclosing_union) = enclosing_union {
|
if let Some(enclosing_pep604_union) = enclosing_pep604_union {
|
||||||
traverse_union(
|
traverse_union(
|
||||||
&mut |expr, _| {
|
&mut |expr, _| {
|
||||||
if matches!(expr, Expr::NoneLiteral(_)) {
|
if matches!(expr, Expr::NoneLiteral(_)) {
|
||||||
|
|
@ -151,14 +161,9 @@ fn create_fix_edit(semantic: &SemanticModel, literal_expr: &Expr) -> Option<Edit
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
semantic,
|
semantic,
|
||||||
enclosing_union,
|
enclosing_pep604_union,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avoid producing code that would raise an exception when
|
|
||||||
// `Literal[None] | None` would be fixed to `None | None`.
|
|
||||||
// Instead do not provide a fix. No action needed for `typing.Union`,
|
|
||||||
// as `Union[None, None]` is valid Python.
|
|
||||||
// See https://github.com/astral-sh/ruff/issues/14567.
|
|
||||||
is_fixable.then(|| Edit::range_replacement("None".to_string(), literal_expr.range()))
|
is_fixable.then(|| Edit::range_replacement("None".to_string(), literal_expr.range()))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ pub(crate) fn never_union(checker: &mut Checker, expr: &Expr) {
|
||||||
// Instead do not provide a fix. No action needed for `typing.Union`,
|
// Instead do not provide a fix. No action needed for `typing.Union`,
|
||||||
// as `Union[None, None]` is valid Python.
|
// as `Union[None, None]` is valid Python.
|
||||||
// See https://github.com/astral-sh/ruff/issues/14567.
|
// See https://github.com/astral-sh/ruff/issues/14567.
|
||||||
if !in_union_with_bare_none(checker.semantic()) {
|
if !is_pep604_union_with_bare_none(checker.semantic()) {
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
checker.locator().slice(right.as_ref()).to_string(),
|
checker.locator().slice(right.as_ref()).to_string(),
|
||||||
expr.range(),
|
expr.range(),
|
||||||
|
|
@ -107,7 +107,7 @@ pub(crate) fn never_union(checker: &mut Checker, expr: &Expr) {
|
||||||
},
|
},
|
||||||
right.range(),
|
right.range(),
|
||||||
);
|
);
|
||||||
if !in_union_with_bare_none(checker.semantic()) {
|
if !is_pep604_union_with_bare_none(checker.semantic()) {
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
checker.locator().slice(left.as_ref()).to_string(),
|
checker.locator().slice(left.as_ref()).to_string(),
|
||||||
expr.range(),
|
expr.range(),
|
||||||
|
|
@ -219,31 +219,43 @@ impl std::fmt::Display for NeverLike {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn in_union_with_bare_none(semantic: &SemanticModel) -> bool {
|
/// Return `true` if this union is a [PEP 604 union] that contains `None`,
|
||||||
let mut enclosing_union = None;
|
/// e.g. `int | Never | None`.
|
||||||
let mut expression_ancestors = semantic.current_expressions().skip(1);
|
///
|
||||||
let mut parent_expr = expression_ancestors.next();
|
/// Autofixing these unions can be dangerous,
|
||||||
while let Some(Expr::BinOp(ExprBinOp {
|
/// as `None | None` results in a runtime exception in Python.
|
||||||
op: Operator::BitOr,
|
///
|
||||||
..
|
/// [PEP 604 union]: https://docs.python.org/3/library/stdtypes.html#types-union
|
||||||
})) = parent_expr
|
fn is_pep604_union_with_bare_none(semantic: &SemanticModel) -> bool {
|
||||||
{
|
let enclosing_pep604_union = semantic
|
||||||
enclosing_union = parent_expr;
|
.current_expressions()
|
||||||
parent_expr = expression_ancestors.next();
|
.skip(1)
|
||||||
}
|
.take_while(|expr| {
|
||||||
|
matches!(
|
||||||
|
expr,
|
||||||
|
Expr::BinOp(ExprBinOp {
|
||||||
|
op: Operator::BitOr,
|
||||||
|
..
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.last();
|
||||||
|
|
||||||
let mut is_union_with_bare_none = false;
|
let Some(enclosing_pep604_union) = enclosing_pep604_union else {
|
||||||
if let Some(enclosing_union) = enclosing_union {
|
return false;
|
||||||
traverse_union(
|
};
|
||||||
&mut |expr, _| {
|
|
||||||
if matches!(expr, Expr::NoneLiteral(_)) {
|
|
||||||
is_union_with_bare_none = true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
semantic,
|
|
||||||
enclosing_union,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
is_union_with_bare_none
|
let mut union_contains_bare_none = false;
|
||||||
|
|
||||||
|
traverse_union(
|
||||||
|
&mut |expr, _| {
|
||||||
|
if matches!(expr, Expr::NoneLiteral(_)) {
|
||||||
|
union_contains_bare_none = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
semantic,
|
||||||
|
enclosing_pep604_union,
|
||||||
|
);
|
||||||
|
|
||||||
|
union_contains_bare_none
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue