mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 22:01:47 +00:00
104 lines
3.2 KiB
Rust
104 lines
3.2 KiB
Rust
use rustpython_ast::{Arguments, Constant, Expr, ExprKind};
|
|
|
|
use crate::ast::helpers::compose_call_path;
|
|
use crate::ast::types::Range;
|
|
use crate::ast::visitor;
|
|
use crate::ast::visitor::Visitor;
|
|
use crate::check_ast::Checker;
|
|
use crate::checks::{Check, CheckKind};
|
|
use crate::flake8_bugbear::plugins::mutable_argument_default::is_mutable_func;
|
|
|
|
// TODO(charlie): Verify imports for each of the imported members.
|
|
const IMMUTABLE_FUNCS: [&str; 11] = [
|
|
"tuple",
|
|
"frozenset",
|
|
"operator.attrgetter",
|
|
"operator.itemgetter",
|
|
"operator.methodcaller",
|
|
"attrgetter",
|
|
"itemgetter",
|
|
"methodcaller",
|
|
"types.MappingProxyType",
|
|
"MappingProxyType",
|
|
"re.compile",
|
|
];
|
|
|
|
fn is_immutable_func(expr: &Expr, extend_immutable_calls: &[String]) -> bool {
|
|
compose_call_path(expr).map_or_else(
|
|
|| false,
|
|
|func| IMMUTABLE_FUNCS.contains(&func.as_str()) || extend_immutable_calls.contains(&func),
|
|
)
|
|
}
|
|
|
|
struct ArgumentDefaultVisitor<'a> {
|
|
checks: Vec<(CheckKind, Range)>,
|
|
extend_immutable_calls: &'a [String],
|
|
}
|
|
|
|
impl<'a, 'b> Visitor<'b> for ArgumentDefaultVisitor<'b>
|
|
where
|
|
'b: 'a,
|
|
{
|
|
fn visit_expr(&mut self, expr: &'b Expr) {
|
|
match &expr.node {
|
|
ExprKind::Call { func, args, .. } => {
|
|
if !is_mutable_func(func)
|
|
&& !is_immutable_func(func, &self.extend_immutable_calls)
|
|
&& !is_nan_or_infinity(func, args)
|
|
{
|
|
self.checks.push((
|
|
CheckKind::FunctionCallArgumentDefault,
|
|
Range::from_located(expr),
|
|
))
|
|
}
|
|
visitor::walk_expr(self, expr)
|
|
}
|
|
ExprKind::Lambda { .. } => {}
|
|
_ => visitor::walk_expr(self, expr),
|
|
}
|
|
}
|
|
}
|
|
|
|
fn is_nan_or_infinity(expr: &Expr, args: &[Expr]) -> bool {
|
|
if let ExprKind::Name { id, .. } = &expr.node {
|
|
if id == "float" {
|
|
if let Some(arg) = args.first() {
|
|
if let ExprKind::Constant {
|
|
value: Constant::Str(value),
|
|
..
|
|
} = &arg.node
|
|
{
|
|
let lowercased = value.to_lowercase();
|
|
return lowercased == "nan"
|
|
|| lowercased == "+nan"
|
|
|| lowercased == "-nan"
|
|
|| lowercased == "inf"
|
|
|| lowercased == "+inf"
|
|
|| lowercased == "-inf"
|
|
|| lowercased == "infinity"
|
|
|| lowercased == "+infinity"
|
|
|| lowercased == "-infinity";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
false
|
|
}
|
|
|
|
/// B008
|
|
pub fn function_call_argument_default(checker: &mut Checker, arguments: &Arguments) {
|
|
let mut visitor = ArgumentDefaultVisitor {
|
|
checks: vec![],
|
|
extend_immutable_calls: &checker.settings.flake8_bugbear.extend_immutable_calls,
|
|
};
|
|
for expr in arguments
|
|
.defaults
|
|
.iter()
|
|
.chain(arguments.kw_defaults.iter())
|
|
{
|
|
visitor.visit_expr(expr);
|
|
}
|
|
for (check, range) in visitor.checks {
|
|
checker.add_check(Check::new(check, range));
|
|
}
|
|
}
|