mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 02:38:25 +00:00
Move Truthiness
into ruff_python_ast
(#4071)
This commit is contained in:
parent
407af6e0ae
commit
df77595426
5 changed files with 113 additions and 132 deletions
|
@ -3,6 +3,7 @@ use std::path::Path;
|
|||
|
||||
use itertools::Itertools;
|
||||
use log::error;
|
||||
use num_traits::Zero;
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
@ -50,6 +51,13 @@ pub fn unparse_constant(constant: &Constant, stylist: &Stylist) -> String {
|
|||
generator.generate()
|
||||
}
|
||||
|
||||
fn is_iterable_initializer<F>(id: &str, is_builtin: F) -> bool
|
||||
where
|
||||
F: Fn(&str) -> bool,
|
||||
{
|
||||
matches!(id, "list" | "tuple" | "set" | "dict" | "frozenset") && is_builtin(id)
|
||||
}
|
||||
|
||||
/// Return `true` if the `Expr` contains an expression that appears to include a
|
||||
/// side-effect (like a function call).
|
||||
///
|
||||
|
@ -68,10 +76,7 @@ where
|
|||
{
|
||||
if args.is_empty() && keywords.is_empty() {
|
||||
if let ExprKind::Name { id, .. } = &func.node {
|
||||
if !matches!(id.as_str(), "set" | "list" | "tuple" | "dict" | "frozenset") {
|
||||
return true;
|
||||
}
|
||||
if !is_builtin(id) {
|
||||
if !is_iterable_initializer(id.as_str(), |id| is_builtin(id)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -1422,6 +1427,98 @@ pub fn locate_cmpops(contents: &str) -> Vec<LocatedCmpop> {
|
|||
ops
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, is_macro::Is)]
|
||||
pub enum Truthiness {
|
||||
// An expression evaluates to `False`.
|
||||
Falsey,
|
||||
// An expression evaluates to `True`.
|
||||
Truthy,
|
||||
// An expression evaluates to an unknown value (e.g., a variable `x` of unknown type).
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl From<Option<bool>> for Truthiness {
|
||||
fn from(value: Option<bool>) -> Self {
|
||||
match value {
|
||||
Some(true) => Truthiness::Truthy,
|
||||
Some(false) => Truthiness::Falsey,
|
||||
None => Truthiness::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Truthiness> for Option<bool> {
|
||||
fn from(truthiness: Truthiness) -> Self {
|
||||
match truthiness {
|
||||
Truthiness::Truthy => Some(true),
|
||||
Truthiness::Falsey => Some(false),
|
||||
Truthiness::Unknown => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Truthiness {
|
||||
pub fn from_expr<F>(expr: &Expr, is_builtin: F) -> Self
|
||||
where
|
||||
F: Fn(&str) -> bool,
|
||||
{
|
||||
match &expr.node {
|
||||
ExprKind::Constant { value, .. } => match value {
|
||||
Constant::Bool(value) => Some(*value),
|
||||
Constant::None => Some(false),
|
||||
Constant::Str(string) => Some(!string.is_empty()),
|
||||
Constant::Bytes(bytes) => Some(!bytes.is_empty()),
|
||||
Constant::Int(int) => Some(!int.is_zero()),
|
||||
Constant::Float(float) => Some(*float != 0.0),
|
||||
Constant::Complex { real, imag } => Some(*real != 0.0 || *imag != 0.0),
|
||||
Constant::Ellipsis => Some(true),
|
||||
Constant::Tuple(elts) => Some(!elts.is_empty()),
|
||||
},
|
||||
ExprKind::JoinedStr { values, .. } => {
|
||||
if values.is_empty() {
|
||||
Some(false)
|
||||
} else if values.iter().any(|value| {
|
||||
let ExprKind::Constant { value: Constant::Str(string), .. } = &value.node else {
|
||||
return false;
|
||||
};
|
||||
!string.is_empty()
|
||||
}) {
|
||||
Some(true)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
ExprKind::List { elts, .. }
|
||||
| ExprKind::Set { elts, .. }
|
||||
| ExprKind::Tuple { elts, .. } => Some(!elts.is_empty()),
|
||||
ExprKind::Dict { keys, .. } => Some(!keys.is_empty()),
|
||||
ExprKind::Call {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
} => {
|
||||
if let ExprKind::Name { id, .. } = &func.node {
|
||||
if is_iterable_initializer(id.as_str(), |id| is_builtin(id)) {
|
||||
if args.is_empty() && keywords.is_empty() {
|
||||
Some(false)
|
||||
} else if args.len() == 1 && keywords.is_empty() {
|
||||
Self::from_expr(&args[0], is_builtin).into()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::borrow::Cow;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue