mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 10:48:32 +00:00
[refurb
] Also report non-name expressions (FURB169
) (#15905)
## Summary Follow-up to #15779. Prior to this change, non-name expressions are not reported at all: ```python type(a.b) is type(None) # no error ``` This change enhances the rule so that such cases are also reported in preview. Additionally: * The fix will now be marked as unsafe if there are any comments within its range. * Error messages are slightly modified. ## Test Plan `cargo nextest run` and `cargo insta test`. --------- Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
parent
700e969c56
commit
5852217198
7 changed files with 497 additions and 147 deletions
|
@ -26,6 +26,23 @@ type(None) != type(foo)
|
|||
|
||||
type(None) != type(None)
|
||||
|
||||
type(a.b) is type(None)
|
||||
|
||||
type(
|
||||
a(
|
||||
# Comment
|
||||
)
|
||||
) != type(None)
|
||||
|
||||
type(
|
||||
a := 1
|
||||
) == type(None)
|
||||
|
||||
type(
|
||||
a for a in range(0)
|
||||
) is not type(None)
|
||||
|
||||
|
||||
# Ok.
|
||||
|
||||
foo is None
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
use ruff_diagnostics::{Applicability, Edit, Fix};
|
||||
use ruff_python_ast::name::Name;
|
||||
use ruff_python_ast::{self as ast, Expr};
|
||||
use ruff_python_codegen::Generator;
|
||||
use ruff_python_semantic::{BindingId, ResolvedReference, SemanticModel};
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::settings::types::PythonVersion;
|
||||
|
||||
/// Format a code snippet to call `name.method()`.
|
||||
|
@ -39,31 +41,45 @@ pub(super) fn generate_method_call(name: Name, method: &str, generator: Generato
|
|||
generator.stmt(&stmt.into())
|
||||
}
|
||||
|
||||
/// Format a code snippet comparing `name` to `None` (e.g., `name is None`).
|
||||
pub(super) fn generate_none_identity_comparison(
|
||||
name: Name,
|
||||
/// Returns a fix that replace `range` with
|
||||
/// a generated `a is None`/`a is not None` check.
|
||||
pub(super) fn replace_with_identity_check(
|
||||
left: &Expr,
|
||||
range: TextRange,
|
||||
negate: bool,
|
||||
generator: Generator,
|
||||
) -> String {
|
||||
// Construct `name`.
|
||||
let var = ast::ExprName {
|
||||
id: name,
|
||||
ctx: ast::ExprContext::Load,
|
||||
range: TextRange::default(),
|
||||
};
|
||||
// Construct `name is None` or `name is not None`.
|
||||
checker: &Checker,
|
||||
) -> Fix {
|
||||
let (semantic, generator) = (checker.semantic(), checker.generator());
|
||||
|
||||
let op = if negate {
|
||||
ast::CmpOp::IsNot
|
||||
} else {
|
||||
ast::CmpOp::Is
|
||||
};
|
||||
let compare = ast::ExprCompare {
|
||||
left: Box::new(var.into()),
|
||||
ops: Box::from([op]),
|
||||
comparators: Box::from([ast::Expr::NoneLiteral(ast::ExprNoneLiteral::default())]),
|
||||
|
||||
let new_expr = Expr::Compare(ast::ExprCompare {
|
||||
left: left.clone().into(),
|
||||
ops: [op].into(),
|
||||
comparators: [ast::ExprNoneLiteral::default().into()].into(),
|
||||
range: TextRange::default(),
|
||||
});
|
||||
|
||||
let new_content = generator.expr(&new_expr);
|
||||
let new_content = if semantic.current_expression_parent().is_some() {
|
||||
format!("({new_content})")
|
||||
} else {
|
||||
new_content
|
||||
};
|
||||
generator.expr(&compare.into())
|
||||
|
||||
let applicability = if checker.comment_ranges().intersects(range) {
|
||||
Applicability::Unsafe
|
||||
} else {
|
||||
Applicability::Safe
|
||||
};
|
||||
|
||||
let edit = Edit::range_replacement(new_content, range);
|
||||
|
||||
Fix::applicable_edit(edit, applicability)
|
||||
}
|
||||
|
||||
// Helpers for read-whole-file and write-whole-file
|
||||
|
|
|
@ -11,7 +11,7 @@ mod tests {
|
|||
use test_case::test_case;
|
||||
|
||||
use crate::registry::Rule;
|
||||
use crate::settings::types::PythonVersion;
|
||||
use crate::settings::types::{PreviewMode, PythonVersion};
|
||||
use crate::test::test_path;
|
||||
use crate::{assert_messages, settings};
|
||||
|
||||
|
@ -60,6 +60,24 @@ mod tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test_case(Rule::TypeNoneComparison, Path::new("FURB169.py"))]
|
||||
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!(
|
||||
"preview__{}_{}",
|
||||
rule_code.noqa_code(),
|
||||
path.to_string_lossy()
|
||||
);
|
||||
let diagnostics = test_path(
|
||||
Path::new("refurb").join(path).as_path(),
|
||||
&settings::LinterSettings {
|
||||
preview: PreviewMode::Enabled,
|
||||
..settings::LinterSettings::for_rule(rule_code)
|
||||
},
|
||||
)?;
|
||||
assert_messages!(snapshot, diagnostics);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_whole_file_python_39() -> Result<()> {
|
||||
let diagnostics = test_path(
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
use ruff_diagnostics::{Applicability, Diagnostic, Edit, Fix, FixAvailability, Violation};
|
||||
use ruff_python_ast::{self as ast, CmpOp, Expr, Operator};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, FixAvailability, Violation};
|
||||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||
use ruff_python_ast::{self as ast, Expr, Operator};
|
||||
use ruff_python_semantic::SemanticModel;
|
||||
use ruff_text_size::TextRange;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::rules::refurb::helpers::replace_with_identity_check;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for uses of `isinstance` that check if an object is of type `None`.
|
||||
|
@ -69,7 +68,7 @@ pub(crate) fn isinstance_type_none(checker: &mut Checker, call: &ast::ExprCall)
|
|||
return;
|
||||
}
|
||||
|
||||
let fix = replace_with_identity_check(expr, call.range, checker);
|
||||
let fix = replace_with_identity_check(expr, call.range, false, checker);
|
||||
let diagnostic = Diagnostic::new(IsinstanceTypeNone, call.range);
|
||||
|
||||
checker.diagnostics.push(diagnostic.with_fix(fix));
|
||||
|
@ -138,31 +137,3 @@ fn is_none(expr: &Expr, semantic: &SemanticModel) -> bool {
|
|||
}
|
||||
inner(expr, false, semantic)
|
||||
}
|
||||
|
||||
fn replace_with_identity_check(expr: &Expr, range: TextRange, checker: &Checker) -> Fix {
|
||||
let (semantic, generator) = (checker.semantic(), checker.generator());
|
||||
|
||||
let new_expr = Expr::Compare(ast::ExprCompare {
|
||||
left: expr.clone().into(),
|
||||
ops: [CmpOp::Is].into(),
|
||||
comparators: [ast::ExprNoneLiteral::default().into()].into(),
|
||||
range: TextRange::default(),
|
||||
});
|
||||
|
||||
let new_content = generator.expr(&new_expr);
|
||||
let new_content = if semantic.current_expression_parent().is_some() {
|
||||
format!("({new_content})")
|
||||
} else {
|
||||
new_content
|
||||
};
|
||||
|
||||
let applicability = if checker.comment_ranges().intersects(range) {
|
||||
Applicability::Unsafe
|
||||
} else {
|
||||
Applicability::Safe
|
||||
};
|
||||
|
||||
let edit = Edit::range_replacement(new_content, range);
|
||||
|
||||
Fix::applicable_edit(edit, applicability)
|
||||
}
|
||||
|
|
|
@ -1,22 +1,21 @@
|
|||
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
||||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic};
|
||||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||
use ruff_python_ast::name::Name;
|
||||
use ruff_python_ast::{self as ast, CmpOp, Expr};
|
||||
use ruff_python_semantic::SemanticModel;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::fix::edits::pad;
|
||||
use crate::rules::refurb::helpers::generate_none_identity_comparison;
|
||||
use crate::rules::refurb::helpers::replace_with_identity_check;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for uses of `type` that compare the type of an object to the type of
|
||||
/// `None`.
|
||||
/// Checks for uses of `type` that compare the type of an object to the type of `None`.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// There is only ever one instance of `None`, so it is more efficient and
|
||||
/// readable to use the `is` operator to check if an object is `None`.
|
||||
///
|
||||
/// Only name expressions (e.g., `type(foo) == type(None)`) are reported.
|
||||
/// In [preview], the rule will also report other kinds of expressions.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// type(obj) is type(None)
|
||||
|
@ -27,34 +26,32 @@ use crate::rules::refurb::helpers::generate_none_identity_comparison;
|
|||
/// obj is None
|
||||
/// ```
|
||||
///
|
||||
/// ## Fix safety
|
||||
/// If the fix might remove comments, it will be marked as unsafe.
|
||||
///
|
||||
/// ## References
|
||||
/// - [Python documentation: `isinstance`](https://docs.python.org/3/library/functions.html#isinstance)
|
||||
/// - [Python documentation: `None`](https://docs.python.org/3/library/constants.html#None)
|
||||
/// - [Python documentation: `type`](https://docs.python.org/3/library/functions.html#type)
|
||||
/// - [Python documentation: Identity comparisons](https://docs.python.org/3/reference/expressions.html#is-not)
|
||||
///
|
||||
/// [preview]: https://docs.astral.sh/ruff/preview/
|
||||
#[derive(ViolationMetadata)]
|
||||
pub(crate) struct TypeNoneComparison {
|
||||
object: Name,
|
||||
comparison: Comparison,
|
||||
replacement: IdentityCheck,
|
||||
}
|
||||
|
||||
impl Violation for TypeNoneComparison {
|
||||
const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes;
|
||||
|
||||
impl AlwaysFixableViolation for TypeNoneComparison {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let TypeNoneComparison { object, .. } = self;
|
||||
format!("Compare the identities of `{object}` and `None` instead of their respective types")
|
||||
format!(
|
||||
"When checking against `None`, use `{}` instead of comparison with `type(None)`",
|
||||
self.replacement.op()
|
||||
)
|
||||
}
|
||||
|
||||
fn fix_title(&self) -> Option<String> {
|
||||
let TypeNoneComparison { object, comparison } = self;
|
||||
match comparison {
|
||||
Comparison::Is | Comparison::Eq => Some(format!("Replace with `{object} is None`")),
|
||||
Comparison::IsNot | Comparison::NotEq => {
|
||||
Some(format!("Replace with `{object} is not None`"))
|
||||
}
|
||||
}
|
||||
fn fix_title(&self) -> String {
|
||||
format!("Replace with `{} None`", self.replacement.op())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,16 +61,12 @@ pub(crate) fn type_none_comparison(checker: &mut Checker, compare: &ast::ExprCom
|
|||
return;
|
||||
};
|
||||
|
||||
// Ensure that the comparison is an identity or equality test.
|
||||
let comparison = match op {
|
||||
CmpOp::Is => Comparison::Is,
|
||||
CmpOp::IsNot => Comparison::IsNot,
|
||||
CmpOp::Eq => Comparison::Eq,
|
||||
CmpOp::NotEq => Comparison::NotEq,
|
||||
let replacement = match op {
|
||||
CmpOp::Is | CmpOp::Eq => IdentityCheck::Is,
|
||||
CmpOp::IsNot | CmpOp::NotEq => IdentityCheck::IsNot,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
// Get the objects whose types are being compared.
|
||||
let Some(left_arg) = type_call_arg(&compare.left, checker.semantic()) else {
|
||||
return;
|
||||
};
|
||||
|
@ -81,48 +74,24 @@ pub(crate) fn type_none_comparison(checker: &mut Checker, compare: &ast::ExprCom
|
|||
return;
|
||||
};
|
||||
|
||||
// If one of the objects is `None`, get the other object; else, return.
|
||||
let other_arg = match (
|
||||
left_arg.is_none_literal_expr(),
|
||||
right_arg.is_none_literal_expr(),
|
||||
) {
|
||||
(true, false) => right_arg,
|
||||
(false, true) => left_arg,
|
||||
// If both are `None`, just pick one.
|
||||
(true, true) => left_arg,
|
||||
let other_arg = match (left_arg, right_arg) {
|
||||
(Expr::NoneLiteral(_), _) => right_arg,
|
||||
(_, Expr::NoneLiteral(_)) => left_arg,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
// Get the name of the other object (or `None` if both were `None`).
|
||||
let other_arg_name = match other_arg {
|
||||
Expr::Name(ast::ExprName { id, .. }) => id.clone(),
|
||||
Expr::NoneLiteral { .. } => Name::new_static("None"),
|
||||
_ => return,
|
||||
};
|
||||
if checker.settings.preview.is_disabled()
|
||||
&& !matches!(other_arg, Expr::Name(_) | Expr::NoneLiteral(_))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
TypeNoneComparison {
|
||||
object: other_arg_name.clone(),
|
||||
comparison,
|
||||
},
|
||||
compare.range(),
|
||||
);
|
||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||
pad(
|
||||
match comparison {
|
||||
Comparison::Is | Comparison::Eq => {
|
||||
generate_none_identity_comparison(other_arg_name, false, checker.generator())
|
||||
}
|
||||
Comparison::IsNot | Comparison::NotEq => {
|
||||
generate_none_identity_comparison(other_arg_name, true, checker.generator())
|
||||
}
|
||||
},
|
||||
compare.range(),
|
||||
checker.locator(),
|
||||
),
|
||||
compare.range(),
|
||||
)));
|
||||
checker.diagnostics.push(diagnostic);
|
||||
let diagnostic = Diagnostic::new(TypeNoneComparison { replacement }, compare.range);
|
||||
|
||||
let negate = replacement == IdentityCheck::IsNot;
|
||||
let fix = replace_with_identity_check(other_arg, compare.range, negate, checker);
|
||||
|
||||
checker.diagnostics.push(diagnostic.with_fix(fix));
|
||||
}
|
||||
|
||||
/// Returns the object passed to the function, if the expression is a call to
|
||||
|
@ -143,9 +112,16 @@ fn type_call_arg<'a>(expr: &'a Expr, semantic: &'a SemanticModel) -> Option<&'a
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum Comparison {
|
||||
enum IdentityCheck {
|
||||
Is,
|
||||
IsNot,
|
||||
Eq,
|
||||
NotEq,
|
||||
}
|
||||
|
||||
impl IdentityCheck {
|
||||
fn op(self) -> CmpOp {
|
||||
match self {
|
||||
Self::Is => CmpOp::Is,
|
||||
Self::IsNot => CmpOp::IsNot,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/refurb/mod.rs
|
||||
---
|
||||
FURB169.py:5:1: FURB169 [*] Compare the identities of `foo` and `None` instead of their respective types
|
||||
FURB169.py:5:1: FURB169 [*] When checking against `None`, use `is` instead of comparison with `type(None)`
|
||||
|
|
||||
3 | # Error.
|
||||
4 |
|
||||
|
@ -10,7 +10,7 @@ FURB169.py:5:1: FURB169 [*] Compare the identities of `foo` and `None` instead o
|
|||
6 |
|
||||
7 | type(None) is type(foo)
|
||||
|
|
||||
= help: Replace with `foo is None`
|
||||
= help: Replace with `is None`
|
||||
|
||||
ℹ Safe fix
|
||||
2 2 |
|
||||
|
@ -22,7 +22,7 @@ FURB169.py:5:1: FURB169 [*] Compare the identities of `foo` and `None` instead o
|
|||
7 7 | type(None) is type(foo)
|
||||
8 8 |
|
||||
|
||||
FURB169.py:7:1: FURB169 [*] Compare the identities of `foo` and `None` instead of their respective types
|
||||
FURB169.py:7:1: FURB169 [*] When checking against `None`, use `is` instead of comparison with `type(None)`
|
||||
|
|
||||
5 | type(foo) is type(None)
|
||||
6 |
|
||||
|
@ -31,7 +31,7 @@ FURB169.py:7:1: FURB169 [*] Compare the identities of `foo` and `None` instead o
|
|||
8 |
|
||||
9 | type(None) is type(None)
|
||||
|
|
||||
= help: Replace with `foo is None`
|
||||
= help: Replace with `is None`
|
||||
|
||||
ℹ Safe fix
|
||||
4 4 |
|
||||
|
@ -43,7 +43,7 @@ FURB169.py:7:1: FURB169 [*] Compare the identities of `foo` and `None` instead o
|
|||
9 9 | type(None) is type(None)
|
||||
10 10 |
|
||||
|
||||
FURB169.py:9:1: FURB169 [*] Compare the identities of `None` and `None` instead of their respective types
|
||||
FURB169.py:9:1: FURB169 [*] When checking against `None`, use `is` instead of comparison with `type(None)`
|
||||
|
|
||||
7 | type(None) is type(foo)
|
||||
8 |
|
||||
|
@ -52,7 +52,7 @@ FURB169.py:9:1: FURB169 [*] Compare the identities of `None` and `None` instead
|
|||
10 |
|
||||
11 | type(foo) is not type(None)
|
||||
|
|
||||
= help: Replace with `None is None`
|
||||
= help: Replace with `is None`
|
||||
|
||||
ℹ Safe fix
|
||||
6 6 |
|
||||
|
@ -64,7 +64,7 @@ FURB169.py:9:1: FURB169 [*] Compare the identities of `None` and `None` instead
|
|||
11 11 | type(foo) is not type(None)
|
||||
12 12 |
|
||||
|
||||
FURB169.py:11:1: FURB169 [*] Compare the identities of `foo` and `None` instead of their respective types
|
||||
FURB169.py:11:1: FURB169 [*] When checking against `None`, use `is not` instead of comparison with `type(None)`
|
||||
|
|
||||
9 | type(None) is type(None)
|
||||
10 |
|
||||
|
@ -73,7 +73,7 @@ FURB169.py:11:1: FURB169 [*] Compare the identities of `foo` and `None` instead
|
|||
12 |
|
||||
13 | type(None) is not type(foo)
|
||||
|
|
||||
= help: Replace with `foo is not None`
|
||||
= help: Replace with `is not None`
|
||||
|
||||
ℹ Safe fix
|
||||
8 8 |
|
||||
|
@ -85,7 +85,7 @@ FURB169.py:11:1: FURB169 [*] Compare the identities of `foo` and `None` instead
|
|||
13 13 | type(None) is not type(foo)
|
||||
14 14 |
|
||||
|
||||
FURB169.py:13:1: FURB169 [*] Compare the identities of `foo` and `None` instead of their respective types
|
||||
FURB169.py:13:1: FURB169 [*] When checking against `None`, use `is not` instead of comparison with `type(None)`
|
||||
|
|
||||
11 | type(foo) is not type(None)
|
||||
12 |
|
||||
|
@ -94,7 +94,7 @@ FURB169.py:13:1: FURB169 [*] Compare the identities of `foo` and `None` instead
|
|||
14 |
|
||||
15 | type(None) is not type(None)
|
||||
|
|
||||
= help: Replace with `foo is not None`
|
||||
= help: Replace with `is not None`
|
||||
|
||||
ℹ Safe fix
|
||||
10 10 |
|
||||
|
@ -106,7 +106,7 @@ FURB169.py:13:1: FURB169 [*] Compare the identities of `foo` and `None` instead
|
|||
15 15 | type(None) is not type(None)
|
||||
16 16 |
|
||||
|
||||
FURB169.py:15:1: FURB169 [*] Compare the identities of `None` and `None` instead of their respective types
|
||||
FURB169.py:15:1: FURB169 [*] When checking against `None`, use `is not` instead of comparison with `type(None)`
|
||||
|
|
||||
13 | type(None) is not type(foo)
|
||||
14 |
|
||||
|
@ -115,7 +115,7 @@ FURB169.py:15:1: FURB169 [*] Compare the identities of `None` and `None` instead
|
|||
16 |
|
||||
17 | type(foo) == type(None)
|
||||
|
|
||||
= help: Replace with `None is not None`
|
||||
= help: Replace with `is not None`
|
||||
|
||||
ℹ Safe fix
|
||||
12 12 |
|
||||
|
@ -127,7 +127,7 @@ FURB169.py:15:1: FURB169 [*] Compare the identities of `None` and `None` instead
|
|||
17 17 | type(foo) == type(None)
|
||||
18 18 |
|
||||
|
||||
FURB169.py:17:1: FURB169 [*] Compare the identities of `foo` and `None` instead of their respective types
|
||||
FURB169.py:17:1: FURB169 [*] When checking against `None`, use `is` instead of comparison with `type(None)`
|
||||
|
|
||||
15 | type(None) is not type(None)
|
||||
16 |
|
||||
|
@ -136,7 +136,7 @@ FURB169.py:17:1: FURB169 [*] Compare the identities of `foo` and `None` instead
|
|||
18 |
|
||||
19 | type(None) == type(foo)
|
||||
|
|
||||
= help: Replace with `foo is None`
|
||||
= help: Replace with `is None`
|
||||
|
||||
ℹ Safe fix
|
||||
14 14 |
|
||||
|
@ -148,7 +148,7 @@ FURB169.py:17:1: FURB169 [*] Compare the identities of `foo` and `None` instead
|
|||
19 19 | type(None) == type(foo)
|
||||
20 20 |
|
||||
|
||||
FURB169.py:19:1: FURB169 [*] Compare the identities of `foo` and `None` instead of their respective types
|
||||
FURB169.py:19:1: FURB169 [*] When checking against `None`, use `is` instead of comparison with `type(None)`
|
||||
|
|
||||
17 | type(foo) == type(None)
|
||||
18 |
|
||||
|
@ -157,7 +157,7 @@ FURB169.py:19:1: FURB169 [*] Compare the identities of `foo` and `None` instead
|
|||
20 |
|
||||
21 | type(None) == type(None)
|
||||
|
|
||||
= help: Replace with `foo is None`
|
||||
= help: Replace with `is None`
|
||||
|
||||
ℹ Safe fix
|
||||
16 16 |
|
||||
|
@ -169,7 +169,7 @@ FURB169.py:19:1: FURB169 [*] Compare the identities of `foo` and `None` instead
|
|||
21 21 | type(None) == type(None)
|
||||
22 22 |
|
||||
|
||||
FURB169.py:21:1: FURB169 [*] Compare the identities of `None` and `None` instead of their respective types
|
||||
FURB169.py:21:1: FURB169 [*] When checking against `None`, use `is` instead of comparison with `type(None)`
|
||||
|
|
||||
19 | type(None) == type(foo)
|
||||
20 |
|
||||
|
@ -178,7 +178,7 @@ FURB169.py:21:1: FURB169 [*] Compare the identities of `None` and `None` instead
|
|||
22 |
|
||||
23 | type(foo) != type(None)
|
||||
|
|
||||
= help: Replace with `None is None`
|
||||
= help: Replace with `is None`
|
||||
|
||||
ℹ Safe fix
|
||||
18 18 |
|
||||
|
@ -190,7 +190,7 @@ FURB169.py:21:1: FURB169 [*] Compare the identities of `None` and `None` instead
|
|||
23 23 | type(foo) != type(None)
|
||||
24 24 |
|
||||
|
||||
FURB169.py:23:1: FURB169 [*] Compare the identities of `foo` and `None` instead of their respective types
|
||||
FURB169.py:23:1: FURB169 [*] When checking against `None`, use `is not` instead of comparison with `type(None)`
|
||||
|
|
||||
21 | type(None) == type(None)
|
||||
22 |
|
||||
|
@ -199,7 +199,7 @@ FURB169.py:23:1: FURB169 [*] Compare the identities of `foo` and `None` instead
|
|||
24 |
|
||||
25 | type(None) != type(foo)
|
||||
|
|
||||
= help: Replace with `foo is not None`
|
||||
= help: Replace with `is not None`
|
||||
|
||||
ℹ Safe fix
|
||||
20 20 |
|
||||
|
@ -211,7 +211,7 @@ FURB169.py:23:1: FURB169 [*] Compare the identities of `foo` and `None` instead
|
|||
25 25 | type(None) != type(foo)
|
||||
26 26 |
|
||||
|
||||
FURB169.py:25:1: FURB169 [*] Compare the identities of `foo` and `None` instead of their respective types
|
||||
FURB169.py:25:1: FURB169 [*] When checking against `None`, use `is not` instead of comparison with `type(None)`
|
||||
|
|
||||
23 | type(foo) != type(None)
|
||||
24 |
|
||||
|
@ -220,7 +220,7 @@ FURB169.py:25:1: FURB169 [*] Compare the identities of `foo` and `None` instead
|
|||
26 |
|
||||
27 | type(None) != type(None)
|
||||
|
|
||||
= help: Replace with `foo is not None`
|
||||
= help: Replace with `is not None`
|
||||
|
||||
ℹ Safe fix
|
||||
22 22 |
|
||||
|
@ -232,16 +232,16 @@ FURB169.py:25:1: FURB169 [*] Compare the identities of `foo` and `None` instead
|
|||
27 27 | type(None) != type(None)
|
||||
28 28 |
|
||||
|
||||
FURB169.py:27:1: FURB169 [*] Compare the identities of `None` and `None` instead of their respective types
|
||||
FURB169.py:27:1: FURB169 [*] When checking against `None`, use `is not` instead of comparison with `type(None)`
|
||||
|
|
||||
25 | type(None) != type(foo)
|
||||
26 |
|
||||
27 | type(None) != type(None)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ FURB169
|
||||
28 |
|
||||
29 | # Ok.
|
||||
29 | type(a.b) is type(None)
|
||||
|
|
||||
= help: Replace with `None is not None`
|
||||
= help: Replace with `is not None`
|
||||
|
||||
ℹ Safe fix
|
||||
24 24 |
|
||||
|
@ -250,5 +250,5 @@ FURB169.py:27:1: FURB169 [*] Compare the identities of `None` and `None` instead
|
|||
27 |-type(None) != type(None)
|
||||
27 |+None is not None
|
||||
28 28 |
|
||||
29 29 | # Ok.
|
||||
29 29 | type(a.b) is type(None)
|
||||
30 30 |
|
||||
|
|
|
@ -0,0 +1,352 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/refurb/mod.rs
|
||||
---
|
||||
FURB169.py:5:1: FURB169 [*] When checking against `None`, use `is` instead of comparison with `type(None)`
|
||||
|
|
||||
3 | # Error.
|
||||
4 |
|
||||
5 | type(foo) is type(None)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ FURB169
|
||||
6 |
|
||||
7 | type(None) is type(foo)
|
||||
|
|
||||
= help: Replace with `is None`
|
||||
|
||||
ℹ Safe fix
|
||||
2 2 |
|
||||
3 3 | # Error.
|
||||
4 4 |
|
||||
5 |-type(foo) is type(None)
|
||||
5 |+foo is None
|
||||
6 6 |
|
||||
7 7 | type(None) is type(foo)
|
||||
8 8 |
|
||||
|
||||
FURB169.py:7:1: FURB169 [*] When checking against `None`, use `is` instead of comparison with `type(None)`
|
||||
|
|
||||
5 | type(foo) is type(None)
|
||||
6 |
|
||||
7 | type(None) is type(foo)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ FURB169
|
||||
8 |
|
||||
9 | type(None) is type(None)
|
||||
|
|
||||
= help: Replace with `is None`
|
||||
|
||||
ℹ Safe fix
|
||||
4 4 |
|
||||
5 5 | type(foo) is type(None)
|
||||
6 6 |
|
||||
7 |-type(None) is type(foo)
|
||||
7 |+foo is None
|
||||
8 8 |
|
||||
9 9 | type(None) is type(None)
|
||||
10 10 |
|
||||
|
||||
FURB169.py:9:1: FURB169 [*] When checking against `None`, use `is` instead of comparison with `type(None)`
|
||||
|
|
||||
7 | type(None) is type(foo)
|
||||
8 |
|
||||
9 | type(None) is type(None)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ FURB169
|
||||
10 |
|
||||
11 | type(foo) is not type(None)
|
||||
|
|
||||
= help: Replace with `is None`
|
||||
|
||||
ℹ Safe fix
|
||||
6 6 |
|
||||
7 7 | type(None) is type(foo)
|
||||
8 8 |
|
||||
9 |-type(None) is type(None)
|
||||
9 |+None is None
|
||||
10 10 |
|
||||
11 11 | type(foo) is not type(None)
|
||||
12 12 |
|
||||
|
||||
FURB169.py:11:1: FURB169 [*] When checking against `None`, use `is not` instead of comparison with `type(None)`
|
||||
|
|
||||
9 | type(None) is type(None)
|
||||
10 |
|
||||
11 | type(foo) is not type(None)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB169
|
||||
12 |
|
||||
13 | type(None) is not type(foo)
|
||||
|
|
||||
= help: Replace with `is not None`
|
||||
|
||||
ℹ Safe fix
|
||||
8 8 |
|
||||
9 9 | type(None) is type(None)
|
||||
10 10 |
|
||||
11 |-type(foo) is not type(None)
|
||||
11 |+foo is not None
|
||||
12 12 |
|
||||
13 13 | type(None) is not type(foo)
|
||||
14 14 |
|
||||
|
||||
FURB169.py:13:1: FURB169 [*] When checking against `None`, use `is not` instead of comparison with `type(None)`
|
||||
|
|
||||
11 | type(foo) is not type(None)
|
||||
12 |
|
||||
13 | type(None) is not type(foo)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB169
|
||||
14 |
|
||||
15 | type(None) is not type(None)
|
||||
|
|
||||
= help: Replace with `is not None`
|
||||
|
||||
ℹ Safe fix
|
||||
10 10 |
|
||||
11 11 | type(foo) is not type(None)
|
||||
12 12 |
|
||||
13 |-type(None) is not type(foo)
|
||||
13 |+foo is not None
|
||||
14 14 |
|
||||
15 15 | type(None) is not type(None)
|
||||
16 16 |
|
||||
|
||||
FURB169.py:15:1: FURB169 [*] When checking against `None`, use `is not` instead of comparison with `type(None)`
|
||||
|
|
||||
13 | type(None) is not type(foo)
|
||||
14 |
|
||||
15 | type(None) is not type(None)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB169
|
||||
16 |
|
||||
17 | type(foo) == type(None)
|
||||
|
|
||||
= help: Replace with `is not None`
|
||||
|
||||
ℹ Safe fix
|
||||
12 12 |
|
||||
13 13 | type(None) is not type(foo)
|
||||
14 14 |
|
||||
15 |-type(None) is not type(None)
|
||||
15 |+None is not None
|
||||
16 16 |
|
||||
17 17 | type(foo) == type(None)
|
||||
18 18 |
|
||||
|
||||
FURB169.py:17:1: FURB169 [*] When checking against `None`, use `is` instead of comparison with `type(None)`
|
||||
|
|
||||
15 | type(None) is not type(None)
|
||||
16 |
|
||||
17 | type(foo) == type(None)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ FURB169
|
||||
18 |
|
||||
19 | type(None) == type(foo)
|
||||
|
|
||||
= help: Replace with `is None`
|
||||
|
||||
ℹ Safe fix
|
||||
14 14 |
|
||||
15 15 | type(None) is not type(None)
|
||||
16 16 |
|
||||
17 |-type(foo) == type(None)
|
||||
17 |+foo is None
|
||||
18 18 |
|
||||
19 19 | type(None) == type(foo)
|
||||
20 20 |
|
||||
|
||||
FURB169.py:19:1: FURB169 [*] When checking against `None`, use `is` instead of comparison with `type(None)`
|
||||
|
|
||||
17 | type(foo) == type(None)
|
||||
18 |
|
||||
19 | type(None) == type(foo)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ FURB169
|
||||
20 |
|
||||
21 | type(None) == type(None)
|
||||
|
|
||||
= help: Replace with `is None`
|
||||
|
||||
ℹ Safe fix
|
||||
16 16 |
|
||||
17 17 | type(foo) == type(None)
|
||||
18 18 |
|
||||
19 |-type(None) == type(foo)
|
||||
19 |+foo is None
|
||||
20 20 |
|
||||
21 21 | type(None) == type(None)
|
||||
22 22 |
|
||||
|
||||
FURB169.py:21:1: FURB169 [*] When checking against `None`, use `is` instead of comparison with `type(None)`
|
||||
|
|
||||
19 | type(None) == type(foo)
|
||||
20 |
|
||||
21 | type(None) == type(None)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ FURB169
|
||||
22 |
|
||||
23 | type(foo) != type(None)
|
||||
|
|
||||
= help: Replace with `is None`
|
||||
|
||||
ℹ Safe fix
|
||||
18 18 |
|
||||
19 19 | type(None) == type(foo)
|
||||
20 20 |
|
||||
21 |-type(None) == type(None)
|
||||
21 |+None is None
|
||||
22 22 |
|
||||
23 23 | type(foo) != type(None)
|
||||
24 24 |
|
||||
|
||||
FURB169.py:23:1: FURB169 [*] When checking against `None`, use `is not` instead of comparison with `type(None)`
|
||||
|
|
||||
21 | type(None) == type(None)
|
||||
22 |
|
||||
23 | type(foo) != type(None)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ FURB169
|
||||
24 |
|
||||
25 | type(None) != type(foo)
|
||||
|
|
||||
= help: Replace with `is not None`
|
||||
|
||||
ℹ Safe fix
|
||||
20 20 |
|
||||
21 21 | type(None) == type(None)
|
||||
22 22 |
|
||||
23 |-type(foo) != type(None)
|
||||
23 |+foo is not None
|
||||
24 24 |
|
||||
25 25 | type(None) != type(foo)
|
||||
26 26 |
|
||||
|
||||
FURB169.py:25:1: FURB169 [*] When checking against `None`, use `is not` instead of comparison with `type(None)`
|
||||
|
|
||||
23 | type(foo) != type(None)
|
||||
24 |
|
||||
25 | type(None) != type(foo)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ FURB169
|
||||
26 |
|
||||
27 | type(None) != type(None)
|
||||
|
|
||||
= help: Replace with `is not None`
|
||||
|
||||
ℹ Safe fix
|
||||
22 22 |
|
||||
23 23 | type(foo) != type(None)
|
||||
24 24 |
|
||||
25 |-type(None) != type(foo)
|
||||
25 |+foo is not None
|
||||
26 26 |
|
||||
27 27 | type(None) != type(None)
|
||||
28 28 |
|
||||
|
||||
FURB169.py:27:1: FURB169 [*] When checking against `None`, use `is not` instead of comparison with `type(None)`
|
||||
|
|
||||
25 | type(None) != type(foo)
|
||||
26 |
|
||||
27 | type(None) != type(None)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ FURB169
|
||||
28 |
|
||||
29 | type(a.b) is type(None)
|
||||
|
|
||||
= help: Replace with `is not None`
|
||||
|
||||
ℹ Safe fix
|
||||
24 24 |
|
||||
25 25 | type(None) != type(foo)
|
||||
26 26 |
|
||||
27 |-type(None) != type(None)
|
||||
27 |+None is not None
|
||||
28 28 |
|
||||
29 29 | type(a.b) is type(None)
|
||||
30 30 |
|
||||
|
||||
FURB169.py:29:1: FURB169 [*] When checking against `None`, use `is` instead of comparison with `type(None)`
|
||||
|
|
||||
27 | type(None) != type(None)
|
||||
28 |
|
||||
29 | type(a.b) is type(None)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ FURB169
|
||||
30 |
|
||||
31 | type(
|
||||
|
|
||||
= help: Replace with `is None`
|
||||
|
||||
ℹ Safe fix
|
||||
26 26 |
|
||||
27 27 | type(None) != type(None)
|
||||
28 28 |
|
||||
29 |-type(a.b) is type(None)
|
||||
29 |+a.b is None
|
||||
30 30 |
|
||||
31 31 | type(
|
||||
32 32 | a(
|
||||
|
||||
FURB169.py:31:1: FURB169 [*] When checking against `None`, use `is not` instead of comparison with `type(None)`
|
||||
|
|
||||
29 | type(a.b) is type(None)
|
||||
30 |
|
||||
31 | / type(
|
||||
32 | | a(
|
||||
33 | | # Comment
|
||||
34 | | )
|
||||
35 | | ) != type(None)
|
||||
| |_______________^ FURB169
|
||||
36 |
|
||||
37 | type(
|
||||
|
|
||||
= help: Replace with `is not None`
|
||||
|
||||
ℹ Unsafe fix
|
||||
28 28 |
|
||||
29 29 | type(a.b) is type(None)
|
||||
30 30 |
|
||||
31 |-type(
|
||||
32 |- a(
|
||||
33 |- # Comment
|
||||
34 |- )
|
||||
35 |-) != type(None)
|
||||
31 |+a() is not None
|
||||
36 32 |
|
||||
37 33 | type(
|
||||
38 34 | a := 1
|
||||
|
||||
FURB169.py:37:1: FURB169 [*] When checking against `None`, use `is` instead of comparison with `type(None)`
|
||||
|
|
||||
35 | ) != type(None)
|
||||
36 |
|
||||
37 | / type(
|
||||
38 | | a := 1
|
||||
39 | | ) == type(None)
|
||||
| |_______________^ FURB169
|
||||
40 |
|
||||
41 | type(
|
||||
|
|
||||
= help: Replace with `is None`
|
||||
|
||||
ℹ Safe fix
|
||||
34 34 | )
|
||||
35 35 | ) != type(None)
|
||||
36 36 |
|
||||
37 |-type(
|
||||
38 |- a := 1
|
||||
39 |-) == type(None)
|
||||
37 |+(a := 1) is None
|
||||
40 38 |
|
||||
41 39 | type(
|
||||
42 40 | a for a in range(0)
|
||||
|
||||
FURB169.py:41:1: FURB169 [*] When checking against `None`, use `is not` instead of comparison with `type(None)`
|
||||
|
|
||||
39 | ) == type(None)
|
||||
40 |
|
||||
41 | / type(
|
||||
42 | | a for a in range(0)
|
||||
43 | | ) is not type(None)
|
||||
| |___________________^ FURB169
|
||||
|
|
||||
= help: Replace with `is not None`
|
||||
|
||||
ℹ Safe fix
|
||||
38 38 | a := 1
|
||||
39 39 | ) == type(None)
|
||||
40 40 |
|
||||
41 |-type(
|
||||
42 |- a for a in range(0)
|
||||
43 |-) is not type(None)
|
||||
41 |+(a for a in range(0)) is not None
|
||||
44 42 |
|
||||
45 43 |
|
||||
46 44 | # Ok.
|
Loading…
Add table
Add a link
Reference in a new issue