mirror of
https://github.com/astral-sh/ruff.git
synced 2025-07-07 21:25:08 +00:00
[flake8-bugbear
] Exempt NewType
calls where the original type is immutable (B008
) (#15765)
## Summary Resolves #12717. This change incorporates the logic added in #15588. ## Test Plan `cargo nextest run` and `cargo insta test`. --------- Co-authored-by: Dhruv Manilawala <dhruvmanila@gmail.com>
This commit is contained in:
parent
6090408f65
commit
4bec8ba731
5 changed files with 88 additions and 55 deletions
|
@ -2,7 +2,9 @@
|
|||
|
||||
use ruff_python_ast::helpers::{any_over_expr, is_const_false, map_subscript};
|
||||
use ruff_python_ast::name::QualifiedName;
|
||||
use ruff_python_ast::{self as ast, Expr, Int, Operator, ParameterWithDefault, Parameters, Stmt};
|
||||
use ruff_python_ast::{
|
||||
self as ast, Expr, ExprCall, Int, Operator, ParameterWithDefault, Parameters, Stmt, StmtAssign,
|
||||
};
|
||||
use ruff_python_stdlib::typing::{
|
||||
as_pep_585_generic, has_pep_585_generic, is_immutable_generic_type,
|
||||
is_immutable_non_generic_type, is_immutable_return_type, is_literal_member,
|
||||
|
@ -301,6 +303,56 @@ pub fn is_immutable_func(
|
|||
})
|
||||
}
|
||||
|
||||
/// Return `true` if `name` is bound to the `typing.NewType` call where the original type is
|
||||
/// immutable.
|
||||
///
|
||||
/// For example:
|
||||
/// ```python
|
||||
/// from typing import NewType
|
||||
///
|
||||
/// UserId = NewType("UserId", int)
|
||||
/// ```
|
||||
///
|
||||
/// Here, `name` would be `UserId`.
|
||||
pub fn is_immutable_newtype_call(
|
||||
name: &ast::ExprName,
|
||||
semantic: &SemanticModel,
|
||||
extend_immutable_calls: &[QualifiedName],
|
||||
) -> bool {
|
||||
let Some(binding) = semantic.only_binding(name).map(|id| semantic.binding(id)) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
if !binding.kind.is_assignment() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let Some(Stmt::Assign(StmtAssign { value, .. })) = binding.statement(semantic) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let Expr::Call(ExprCall {
|
||||
func, arguments, ..
|
||||
}) = value.as_ref()
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
|
||||
if !semantic.match_typing_expr(func, "NewType") {
|
||||
return false;
|
||||
}
|
||||
|
||||
if arguments.len() != 2 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let Some(original_type) = arguments.find_argument_value("tp", 1) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
is_immutable_annotation(original_type, semantic, extend_immutable_calls)
|
||||
}
|
||||
|
||||
/// Return `true` if `func` is a function that returns a mutable value.
|
||||
pub fn is_mutable_func(func: &Expr, semantic: &SemanticModel) -> bool {
|
||||
semantic
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue